155bd2133SJag Raman /* vcc.c: sun4v virtual channel concentrator 255bd2133SJag Raman * 355bd2133SJag Raman * Copyright (C) 2017 Oracle. All rights reserved. 455bd2133SJag Raman */ 555bd2133SJag Raman 655bd2133SJag Raman #include <linux/module.h> 7*ce808b74SJag Raman #include <linux/tty.h> 855bd2133SJag Raman 9f283ebd5SJag Raman #define DRV_MODULE_NAME "vcc" 10f283ebd5SJag Raman #define DRV_MODULE_VERSION "1.1" 11f283ebd5SJag Raman #define DRV_MODULE_RELDATE "July 1, 2017" 12f283ebd5SJag Raman 13*ce808b74SJag Raman static char version[] = 14*ce808b74SJag Raman DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")"; 15*ce808b74SJag Raman 16f283ebd5SJag Raman MODULE_DESCRIPTION("Sun LDOM virtual console concentrator driver"); 17f283ebd5SJag Raman MODULE_LICENSE("GPL"); 18f283ebd5SJag Raman MODULE_VERSION(DRV_MODULE_VERSION); 19f283ebd5SJag Raman 20*ce808b74SJag Raman #define VCC_MAX_PORTS 1024 21*ce808b74SJag Raman #define VCC_MINOR_START 0 /* must be zero */ 22*ce808b74SJag Raman 23*ce808b74SJag Raman static const char vcc_driver_name[] = "vcc"; 24*ce808b74SJag Raman static const char vcc_device_node[] = "vcc"; 25*ce808b74SJag Raman static struct tty_driver *vcc_tty_driver; 26*ce808b74SJag Raman 27f283ebd5SJag Raman int vcc_dbg; 28f283ebd5SJag Raman int vcc_dbg_ldc; 29f283ebd5SJag Raman int vcc_dbg_vio; 30f283ebd5SJag Raman 31f283ebd5SJag Raman module_param(vcc_dbg, uint, 0664); 32f283ebd5SJag Raman module_param(vcc_dbg_ldc, uint, 0664); 33f283ebd5SJag Raman module_param(vcc_dbg_vio, uint, 0664); 34f283ebd5SJag Raman 35f283ebd5SJag Raman #define VCC_DBG_DRV 0x1 36f283ebd5SJag Raman #define VCC_DBG_LDC 0x2 37f283ebd5SJag Raman #define VCC_DBG_PKT 0x4 38f283ebd5SJag Raman 39f283ebd5SJag Raman #define vccdbg(f, a...) \ 40f283ebd5SJag Raman do { \ 41f283ebd5SJag Raman if (vcc_dbg & VCC_DBG_DRV) \ 42f283ebd5SJag Raman pr_info(f, ## a); \ 43f283ebd5SJag Raman } while (0) \ 44f283ebd5SJag Raman 45f283ebd5SJag Raman #define vccdbgl(l) \ 46f283ebd5SJag Raman do { \ 47f283ebd5SJag Raman if (vcc_dbg & VCC_DBG_LDC) \ 48f283ebd5SJag Raman ldc_print(l); \ 49f283ebd5SJag Raman } while (0) \ 50f283ebd5SJag Raman 51f283ebd5SJag Raman #define vccdbgp(pkt) \ 52f283ebd5SJag Raman do { \ 53f283ebd5SJag Raman if (vcc_dbg & VCC_DBG_PKT) { \ 54f283ebd5SJag Raman int i; \ 55f283ebd5SJag Raman for (i = 0; i < pkt.tag.stype; i++) \ 56f283ebd5SJag Raman pr_info("[%c]", pkt.data[i]); \ 57f283ebd5SJag Raman } \ 58f283ebd5SJag Raman } while (0) \ 59f283ebd5SJag Raman 60*ce808b74SJag Raman /* Note: Be careful when adding flags to this line discipline. Don't 61*ce808b74SJag Raman * add anything that will cause echoing or we'll go into recursive 62*ce808b74SJag Raman * loop echoing chars back and forth with the console drivers. 63*ce808b74SJag Raman */ 64*ce808b74SJag Raman static struct ktermios vcc_tty_termios = { 65*ce808b74SJag Raman .c_iflag = IGNBRK | IGNPAR, 66*ce808b74SJag Raman .c_oflag = OPOST, 67*ce808b74SJag Raman .c_cflag = B38400 | CS8 | CREAD | HUPCL, 68*ce808b74SJag Raman .c_cc = INIT_C_CC, 69*ce808b74SJag Raman .c_ispeed = 38400, 70*ce808b74SJag Raman .c_ospeed = 38400 71*ce808b74SJag Raman }; 72*ce808b74SJag Raman 73*ce808b74SJag Raman static const struct tty_operations vcc_ops; 74*ce808b74SJag Raman 75*ce808b74SJag Raman #define VCC_TTY_FLAGS (TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_REAL_RAW) 76*ce808b74SJag Raman 77*ce808b74SJag Raman static int vcc_tty_init(void) 78*ce808b74SJag Raman { 79*ce808b74SJag Raman int rv; 80*ce808b74SJag Raman 81*ce808b74SJag Raman pr_info("VCC: %s\n", version); 82*ce808b74SJag Raman 83*ce808b74SJag Raman vcc_tty_driver = tty_alloc_driver(VCC_MAX_PORTS, VCC_TTY_FLAGS); 84*ce808b74SJag Raman if (!vcc_tty_driver) { 85*ce808b74SJag Raman pr_err("VCC: TTY driver alloc failed\n"); 86*ce808b74SJag Raman return -ENOMEM; 87*ce808b74SJag Raman } 88*ce808b74SJag Raman 89*ce808b74SJag Raman vcc_tty_driver->driver_name = vcc_driver_name; 90*ce808b74SJag Raman vcc_tty_driver->name = vcc_device_node; 91*ce808b74SJag Raman 92*ce808b74SJag Raman vcc_tty_driver->minor_start = VCC_MINOR_START; 93*ce808b74SJag Raman vcc_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; 94*ce808b74SJag Raman vcc_tty_driver->init_termios = vcc_tty_termios; 95*ce808b74SJag Raman 96*ce808b74SJag Raman tty_set_operations(vcc_tty_driver, &vcc_ops); 97*ce808b74SJag Raman 98*ce808b74SJag Raman rv = tty_register_driver(vcc_tty_driver); 99*ce808b74SJag Raman if (rv) { 100*ce808b74SJag Raman pr_err("VCC: TTY driver registration failed\n"); 101*ce808b74SJag Raman put_tty_driver(vcc_tty_driver); 102*ce808b74SJag Raman vcc_tty_driver = NULL; 103*ce808b74SJag Raman return rv; 104*ce808b74SJag Raman } 105*ce808b74SJag Raman 106*ce808b74SJag Raman vccdbg("VCC: TTY driver registered\n"); 107*ce808b74SJag Raman 108*ce808b74SJag Raman return 0; 109*ce808b74SJag Raman } 110*ce808b74SJag Raman 111*ce808b74SJag Raman static void vcc_tty_exit(void) 112*ce808b74SJag Raman { 113*ce808b74SJag Raman tty_unregister_driver(vcc_tty_driver); 114*ce808b74SJag Raman put_tty_driver(vcc_tty_driver); 115*ce808b74SJag Raman vccdbg("VCC: TTY driver unregistered\n"); 116*ce808b74SJag Raman 117*ce808b74SJag Raman vcc_tty_driver = NULL; 118*ce808b74SJag Raman } 119*ce808b74SJag Raman 12055bd2133SJag Raman static int __init vcc_init(void) 12155bd2133SJag Raman { 122*ce808b74SJag Raman int rv; 123*ce808b74SJag Raman 124*ce808b74SJag Raman rv = vcc_tty_init(); 125*ce808b74SJag Raman if (rv) { 126*ce808b74SJag Raman pr_err("VCC: TTY init failed\n"); 127*ce808b74SJag Raman return rv; 128*ce808b74SJag Raman } 129*ce808b74SJag Raman 130*ce808b74SJag Raman return rv; 13155bd2133SJag Raman } 13255bd2133SJag Raman 13355bd2133SJag Raman static void __exit vcc_exit(void) 13455bd2133SJag Raman { 135*ce808b74SJag Raman vcc_tty_exit(); 136*ce808b74SJag Raman vccdbg("VCC: TTY driver unregistered\n"); 13755bd2133SJag Raman } 13855bd2133SJag Raman 13955bd2133SJag Raman module_init(vcc_init); 14055bd2133SJag Raman module_exit(vcc_exit); 141