xref: /openbmc/linux/drivers/usb/serial/console.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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