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