1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * USB Serial Console driver 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (C) 2001 - 2002 Greg Kroah-Hartman (greg@kroah.com) 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 7*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License version 8*1da177e4SLinus Torvalds * 2 as published by the Free Software Foundation. 9*1da177e4SLinus Torvalds * 10*1da177e4SLinus Torvalds * Thanks to Randy Dunlap for the original version of this code. 11*1da177e4SLinus Torvalds * 12*1da177e4SLinus Torvalds */ 13*1da177e4SLinus Torvalds 14*1da177e4SLinus Torvalds #include <linux/config.h> 15*1da177e4SLinus Torvalds #include <linux/kernel.h> 16*1da177e4SLinus Torvalds #include <linux/init.h> 17*1da177e4SLinus Torvalds #include <linux/slab.h> 18*1da177e4SLinus Torvalds #include <linux/tty.h> 19*1da177e4SLinus Torvalds #include <linux/console.h> 20*1da177e4SLinus Torvalds #include <linux/usb.h> 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds static int debug; 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds #include "usb-serial.h" 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds struct usbcons_info { 27*1da177e4SLinus Torvalds int magic; 28*1da177e4SLinus Torvalds int break_flag; 29*1da177e4SLinus Torvalds struct usb_serial_port *port; 30*1da177e4SLinus Torvalds }; 31*1da177e4SLinus Torvalds 32*1da177e4SLinus Torvalds static struct usbcons_info usbcons_info; 33*1da177e4SLinus Torvalds static struct console usbcons; 34*1da177e4SLinus Torvalds 35*1da177e4SLinus Torvalds /* 36*1da177e4SLinus Torvalds * ------------------------------------------------------------ 37*1da177e4SLinus Torvalds * USB Serial console driver 38*1da177e4SLinus Torvalds * 39*1da177e4SLinus Torvalds * Much of the code here is copied from drivers/char/serial.c 40*1da177e4SLinus Torvalds * and implements a phony serial console in the same way that 41*1da177e4SLinus Torvalds * serial.c does so that in case some software queries it, 42*1da177e4SLinus Torvalds * it will get the same results. 43*1da177e4SLinus Torvalds * 44*1da177e4SLinus Torvalds * Things that are different from the way the serial port code 45*1da177e4SLinus Torvalds * does things, is that we call the lower level usb-serial 46*1da177e4SLinus Torvalds * driver code to initialize the device, and we set the initial 47*1da177e4SLinus Torvalds * console speeds based on the command line arguments. 48*1da177e4SLinus Torvalds * ------------------------------------------------------------ 49*1da177e4SLinus Torvalds */ 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds /* 53*1da177e4SLinus Torvalds * The parsing of the command line works exactly like the 54*1da177e4SLinus Torvalds * serial.c code, except that the specifier is "ttyUSB" instead 55*1da177e4SLinus Torvalds * of "ttyS". 56*1da177e4SLinus Torvalds */ 57*1da177e4SLinus Torvalds static int __init usb_console_setup(struct console *co, char *options) 58*1da177e4SLinus Torvalds { 59*1da177e4SLinus Torvalds struct usbcons_info *info = &usbcons_info; 60*1da177e4SLinus Torvalds int baud = 9600; 61*1da177e4SLinus Torvalds int bits = 8; 62*1da177e4SLinus Torvalds int parity = 'n'; 63*1da177e4SLinus Torvalds int doflow = 0; 64*1da177e4SLinus Torvalds int cflag = CREAD | HUPCL | CLOCAL; 65*1da177e4SLinus Torvalds char *s; 66*1da177e4SLinus Torvalds struct usb_serial *serial; 67*1da177e4SLinus Torvalds struct usb_serial_port *port; 68*1da177e4SLinus Torvalds int retval = 0; 69*1da177e4SLinus Torvalds struct tty_struct *tty; 70*1da177e4SLinus Torvalds struct termios *termios; 71*1da177e4SLinus Torvalds 72*1da177e4SLinus Torvalds dbg ("%s", __FUNCTION__); 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds if (options) { 75*1da177e4SLinus Torvalds baud = simple_strtoul(options, NULL, 10); 76*1da177e4SLinus Torvalds s = options; 77*1da177e4SLinus Torvalds while (*s >= '0' && *s <= '9') 78*1da177e4SLinus Torvalds s++; 79*1da177e4SLinus Torvalds if (*s) 80*1da177e4SLinus Torvalds parity = *s++; 81*1da177e4SLinus Torvalds if (*s) 82*1da177e4SLinus Torvalds bits = *s++ - '0'; 83*1da177e4SLinus Torvalds if (*s) 84*1da177e4SLinus Torvalds doflow = (*s++ == 'r'); 85*1da177e4SLinus Torvalds } 86*1da177e4SLinus Torvalds 87*1da177e4SLinus Torvalds /* build a cflag setting */ 88*1da177e4SLinus Torvalds switch (baud) { 89*1da177e4SLinus Torvalds case 1200: 90*1da177e4SLinus Torvalds cflag |= B1200; 91*1da177e4SLinus Torvalds break; 92*1da177e4SLinus Torvalds case 2400: 93*1da177e4SLinus Torvalds cflag |= B2400; 94*1da177e4SLinus Torvalds break; 95*1da177e4SLinus Torvalds case 4800: 96*1da177e4SLinus Torvalds cflag |= B4800; 97*1da177e4SLinus Torvalds break; 98*1da177e4SLinus Torvalds case 19200: 99*1da177e4SLinus Torvalds cflag |= B19200; 100*1da177e4SLinus Torvalds break; 101*1da177e4SLinus Torvalds case 38400: 102*1da177e4SLinus Torvalds cflag |= B38400; 103*1da177e4SLinus Torvalds break; 104*1da177e4SLinus Torvalds case 57600: 105*1da177e4SLinus Torvalds cflag |= B57600; 106*1da177e4SLinus Torvalds break; 107*1da177e4SLinus Torvalds case 115200: 108*1da177e4SLinus Torvalds cflag |= B115200; 109*1da177e4SLinus Torvalds break; 110*1da177e4SLinus Torvalds case 9600: 111*1da177e4SLinus Torvalds default: 112*1da177e4SLinus Torvalds cflag |= B9600; 113*1da177e4SLinus Torvalds /* 114*1da177e4SLinus Torvalds * Set this to a sane value to prevent a divide error 115*1da177e4SLinus Torvalds */ 116*1da177e4SLinus Torvalds baud = 9600; 117*1da177e4SLinus Torvalds break; 118*1da177e4SLinus Torvalds } 119*1da177e4SLinus Torvalds switch (bits) { 120*1da177e4SLinus Torvalds case 7: 121*1da177e4SLinus Torvalds cflag |= CS7; 122*1da177e4SLinus Torvalds break; 123*1da177e4SLinus Torvalds default: 124*1da177e4SLinus Torvalds case 8: 125*1da177e4SLinus Torvalds cflag |= CS8; 126*1da177e4SLinus Torvalds break; 127*1da177e4SLinus Torvalds } 128*1da177e4SLinus Torvalds switch (parity) { 129*1da177e4SLinus Torvalds case 'o': case 'O': 130*1da177e4SLinus Torvalds cflag |= PARODD; 131*1da177e4SLinus Torvalds break; 132*1da177e4SLinus Torvalds case 'e': case 'E': 133*1da177e4SLinus Torvalds cflag |= PARENB; 134*1da177e4SLinus Torvalds break; 135*1da177e4SLinus Torvalds } 136*1da177e4SLinus Torvalds co->cflag = cflag; 137*1da177e4SLinus Torvalds 138*1da177e4SLinus Torvalds /* grab the first serial port that happens to be connected */ 139*1da177e4SLinus Torvalds serial = usb_serial_get_by_index(0); 140*1da177e4SLinus Torvalds if (serial == NULL) { 141*1da177e4SLinus Torvalds /* no device is connected yet, sorry :( */ 142*1da177e4SLinus Torvalds err ("No USB device connected to ttyUSB0"); 143*1da177e4SLinus Torvalds return -ENODEV; 144*1da177e4SLinus Torvalds } 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds port = serial->port[0]; 147*1da177e4SLinus Torvalds port->tty = NULL; 148*1da177e4SLinus Torvalds 149*1da177e4SLinus Torvalds info->port = port; 150*1da177e4SLinus Torvalds 151*1da177e4SLinus Torvalds ++port->open_count; 152*1da177e4SLinus Torvalds if (port->open_count == 1) { 153*1da177e4SLinus Torvalds /* only call the device specific open if this 154*1da177e4SLinus Torvalds * is the first time the port is opened */ 155*1da177e4SLinus Torvalds if (serial->type->open) 156*1da177e4SLinus Torvalds retval = serial->type->open(port, NULL); 157*1da177e4SLinus Torvalds else 158*1da177e4SLinus Torvalds retval = usb_serial_generic_open(port, NULL); 159*1da177e4SLinus Torvalds if (retval) 160*1da177e4SLinus Torvalds port->open_count = 0; 161*1da177e4SLinus Torvalds } 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds if (retval) { 164*1da177e4SLinus Torvalds err ("could not open USB console port"); 165*1da177e4SLinus Torvalds return retval; 166*1da177e4SLinus Torvalds } 167*1da177e4SLinus Torvalds 168*1da177e4SLinus Torvalds if (serial->type->set_termios) { 169*1da177e4SLinus Torvalds /* build up a fake tty structure so that the open call has something 170*1da177e4SLinus Torvalds * to look at to get the cflag value */ 171*1da177e4SLinus Torvalds tty = kmalloc (sizeof (*tty), GFP_KERNEL); 172*1da177e4SLinus Torvalds if (!tty) { 173*1da177e4SLinus Torvalds err ("no more memory"); 174*1da177e4SLinus Torvalds return -ENOMEM; 175*1da177e4SLinus Torvalds } 176*1da177e4SLinus Torvalds termios = kmalloc (sizeof (*termios), GFP_KERNEL); 177*1da177e4SLinus Torvalds if (!termios) { 178*1da177e4SLinus Torvalds err ("no more memory"); 179*1da177e4SLinus Torvalds kfree (tty); 180*1da177e4SLinus Torvalds return -ENOMEM; 181*1da177e4SLinus Torvalds } 182*1da177e4SLinus Torvalds memset (tty, 0x00, sizeof(*tty)); 183*1da177e4SLinus Torvalds memset (termios, 0x00, sizeof(*termios)); 184*1da177e4SLinus Torvalds termios->c_cflag = cflag; 185*1da177e4SLinus Torvalds tty->termios = termios; 186*1da177e4SLinus Torvalds port->tty = tty; 187*1da177e4SLinus Torvalds 188*1da177e4SLinus Torvalds /* set up the initial termios settings */ 189*1da177e4SLinus Torvalds serial->type->set_termios(port, NULL); 190*1da177e4SLinus Torvalds port->tty = NULL; 191*1da177e4SLinus Torvalds kfree (termios); 192*1da177e4SLinus Torvalds kfree (tty); 193*1da177e4SLinus Torvalds } 194*1da177e4SLinus Torvalds 195*1da177e4SLinus Torvalds return retval; 196*1da177e4SLinus Torvalds } 197*1da177e4SLinus Torvalds 198*1da177e4SLinus Torvalds static void usb_console_write(struct console *co, const char *buf, unsigned count) 199*1da177e4SLinus Torvalds { 200*1da177e4SLinus Torvalds static struct usbcons_info *info = &usbcons_info; 201*1da177e4SLinus Torvalds struct usb_serial_port *port = info->port; 202*1da177e4SLinus Torvalds struct usb_serial *serial; 203*1da177e4SLinus Torvalds int retval = -ENODEV; 204*1da177e4SLinus Torvalds 205*1da177e4SLinus Torvalds if (!port) 206*1da177e4SLinus Torvalds return; 207*1da177e4SLinus Torvalds serial = port->serial; 208*1da177e4SLinus Torvalds 209*1da177e4SLinus Torvalds if (count == 0) 210*1da177e4SLinus Torvalds return; 211*1da177e4SLinus Torvalds 212*1da177e4SLinus Torvalds dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); 213*1da177e4SLinus Torvalds 214*1da177e4SLinus Torvalds if (!port->open_count) { 215*1da177e4SLinus Torvalds dbg ("%s - port not opened", __FUNCTION__); 216*1da177e4SLinus Torvalds goto exit; 217*1da177e4SLinus Torvalds } 218*1da177e4SLinus Torvalds 219*1da177e4SLinus Torvalds /* pass on to the driver specific version of this function if it is available */ 220*1da177e4SLinus Torvalds if (serial->type->write) 221*1da177e4SLinus Torvalds retval = serial->type->write(port, buf, count); 222*1da177e4SLinus Torvalds else 223*1da177e4SLinus Torvalds retval = usb_serial_generic_write(port, buf, count); 224*1da177e4SLinus Torvalds 225*1da177e4SLinus Torvalds exit: 226*1da177e4SLinus Torvalds dbg("%s - return value (if we had one): %d", __FUNCTION__, retval); 227*1da177e4SLinus Torvalds } 228*1da177e4SLinus Torvalds 229*1da177e4SLinus Torvalds static struct console usbcons = { 230*1da177e4SLinus Torvalds .name = "ttyUSB", 231*1da177e4SLinus Torvalds .write = usb_console_write, 232*1da177e4SLinus Torvalds .setup = usb_console_setup, 233*1da177e4SLinus Torvalds .flags = CON_PRINTBUFFER, 234*1da177e4SLinus Torvalds .index = -1, 235*1da177e4SLinus Torvalds }; 236*1da177e4SLinus Torvalds 237*1da177e4SLinus Torvalds void usb_serial_console_init (int serial_debug, int minor) 238*1da177e4SLinus Torvalds { 239*1da177e4SLinus Torvalds debug = serial_debug; 240*1da177e4SLinus Torvalds 241*1da177e4SLinus Torvalds if (minor == 0) { 242*1da177e4SLinus Torvalds /* 243*1da177e4SLinus Torvalds * Call register_console() if this is the first device plugged 244*1da177e4SLinus Torvalds * in. If we call it earlier, then the callback to 245*1da177e4SLinus Torvalds * console_setup() will fail, as there is not a device seen by 246*1da177e4SLinus Torvalds * the USB subsystem yet. 247*1da177e4SLinus Torvalds */ 248*1da177e4SLinus Torvalds /* 249*1da177e4SLinus Torvalds * Register console. 250*1da177e4SLinus Torvalds * NOTES: 251*1da177e4SLinus Torvalds * console_setup() is called (back) immediately (from register_console). 252*1da177e4SLinus Torvalds * console_write() is called immediately from register_console iff 253*1da177e4SLinus Torvalds * CON_PRINTBUFFER is set in flags. 254*1da177e4SLinus Torvalds */ 255*1da177e4SLinus Torvalds dbg ("registering the USB serial console."); 256*1da177e4SLinus Torvalds register_console(&usbcons); 257*1da177e4SLinus Torvalds } 258*1da177e4SLinus Torvalds } 259*1da177e4SLinus Torvalds 260*1da177e4SLinus Torvalds void usb_serial_console_exit (void) 261*1da177e4SLinus Torvalds { 262*1da177e4SLinus Torvalds unregister_console(&usbcons); 263*1da177e4SLinus Torvalds } 264*1da177e4SLinus Torvalds 265