0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0012
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/slab.h>
0016 #include <linux/tty.h>
0017 #include <linux/console.h>
0018 #include <linux/serial.h>
0019 #include <linux/usb.h>
0020 #include <linux/usb/serial.h>
0021
0022 struct usbcons_info {
0023 int magic;
0024 int break_flag;
0025 struct usb_serial_port *port;
0026 };
0027
0028 static struct usbcons_info usbcons_info;
0029 static struct console usbcons;
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 static const struct tty_operations usb_console_fake_tty_ops = {
0048 };
0049
0050
0051
0052
0053
0054
0055 static int usb_console_setup(struct console *co, char *options)
0056 {
0057 struct usbcons_info *info = &usbcons_info;
0058 int baud = 9600;
0059 int bits = 8;
0060 int parity = 'n';
0061 int doflow = 0;
0062 int cflag = CREAD | HUPCL | CLOCAL;
0063 char *s;
0064 struct usb_serial *serial;
0065 struct usb_serial_port *port;
0066 int retval;
0067 struct tty_struct *tty = NULL;
0068 struct ktermios dummy;
0069
0070 if (options) {
0071 baud = simple_strtoul(options, NULL, 10);
0072 s = options;
0073 while (*s >= '0' && *s <= '9')
0074 s++;
0075 if (*s)
0076 parity = *s++;
0077 if (*s)
0078 bits = *s++ - '0';
0079 if (*s)
0080 doflow = (*s++ == 'r');
0081 }
0082
0083
0084 if (baud == 0)
0085 baud = 9600;
0086
0087 switch (bits) {
0088 case 7:
0089 cflag |= CS7;
0090 break;
0091 default:
0092 case 8:
0093 cflag |= CS8;
0094 break;
0095 }
0096 switch (parity) {
0097 case 'o': case 'O':
0098 cflag |= PARODD;
0099 break;
0100 case 'e': case 'E':
0101 cflag |= PARENB;
0102 break;
0103 }
0104
0105 if (doflow)
0106 cflag |= CRTSCTS;
0107
0108
0109
0110
0111
0112 port = usb_serial_port_get_by_minor(co->index);
0113 if (port == NULL) {
0114
0115 pr_err("No USB device connected to ttyUSB%i\n", co->index);
0116 return -ENODEV;
0117 }
0118 serial = port->serial;
0119
0120 retval = usb_autopm_get_interface(serial->interface);
0121 if (retval)
0122 goto error_get_interface;
0123
0124 tty_port_tty_set(&port->port, NULL);
0125
0126 info->port = port;
0127
0128 ++port->port.count;
0129 if (!tty_port_initialized(&port->port)) {
0130 if (serial->type->set_termios) {
0131
0132
0133
0134
0135
0136 tty = kzalloc(sizeof(*tty), GFP_KERNEL);
0137 if (!tty) {
0138 retval = -ENOMEM;
0139 goto reset_open_count;
0140 }
0141 kref_init(&tty->kref);
0142 tty->driver = usb_serial_tty_driver;
0143 tty->index = co->index;
0144 init_ldsem(&tty->ldisc_sem);
0145 spin_lock_init(&tty->files_lock);
0146 INIT_LIST_HEAD(&tty->tty_files);
0147 kref_get(&tty->driver->kref);
0148 __module_get(tty->driver->owner);
0149 tty->ops = &usb_console_fake_tty_ops;
0150 tty_init_termios(tty);
0151 tty_port_tty_set(&port->port, tty);
0152 }
0153
0154
0155
0156 retval = serial->type->open(NULL, port);
0157 if (retval) {
0158 dev_err(&port->dev, "could not open USB console port\n");
0159 goto fail;
0160 }
0161
0162 if (serial->type->set_termios) {
0163 tty->termios.c_cflag = cflag;
0164 tty_termios_encode_baud_rate(&tty->termios, baud, baud);
0165 memset(&dummy, 0, sizeof(struct ktermios));
0166 serial->type->set_termios(tty, port, &dummy);
0167
0168 tty_port_tty_set(&port->port, NULL);
0169 tty_save_termios(tty);
0170 tty_kref_put(tty);
0171 }
0172 tty_port_set_initialized(&port->port, 1);
0173 }
0174
0175
0176 --port->port.count;
0177
0178
0179 port->port.console = 1;
0180
0181 mutex_unlock(&serial->disc_mutex);
0182 return retval;
0183
0184 fail:
0185 tty_port_tty_set(&port->port, NULL);
0186 tty_kref_put(tty);
0187 reset_open_count:
0188 port->port.count = 0;
0189 info->port = NULL;
0190 usb_autopm_put_interface(serial->interface);
0191 error_get_interface:
0192 usb_serial_put(serial);
0193 mutex_unlock(&serial->disc_mutex);
0194 return retval;
0195 }
0196
0197 static void usb_console_write(struct console *co,
0198 const char *buf, unsigned count)
0199 {
0200 static struct usbcons_info *info = &usbcons_info;
0201 struct usb_serial_port *port = info->port;
0202 struct usb_serial *serial;
0203 int retval = -ENODEV;
0204
0205 if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
0206 return;
0207 serial = port->serial;
0208
0209 if (count == 0)
0210 return;
0211
0212 dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count);
0213
0214 if (!port->port.console) {
0215 dev_dbg(&port->dev, "%s - port not opened\n", __func__);
0216 return;
0217 }
0218
0219 while (count) {
0220 unsigned int i;
0221 unsigned int lf;
0222
0223 for (i = 0, lf = 0 ; i < count ; i++) {
0224 if (*(buf + i) == 10) {
0225 lf = 1;
0226 i++;
0227 break;
0228 }
0229 }
0230
0231
0232 retval = serial->type->write(NULL, port, buf, i);
0233 dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval);
0234 if (lf) {
0235
0236 unsigned char cr = 13;
0237 retval = serial->type->write(NULL, port, &cr, 1);
0238 dev_dbg(&port->dev, "%s - write cr: %d\n",
0239 __func__, retval);
0240 }
0241 buf += i;
0242 count -= i;
0243 }
0244 }
0245
0246 static struct tty_driver *usb_console_device(struct console *co, int *index)
0247 {
0248 struct tty_driver **p = (struct tty_driver **)co->data;
0249
0250 if (!*p)
0251 return NULL;
0252
0253 *index = co->index;
0254 return *p;
0255 }
0256
0257 static struct console usbcons = {
0258 .name = "ttyUSB",
0259 .write = usb_console_write,
0260 .device = usb_console_device,
0261 .setup = usb_console_setup,
0262 .flags = CON_PRINTBUFFER,
0263 .index = -1,
0264 .data = &usb_serial_tty_driver,
0265 };
0266
0267 void usb_serial_console_disconnect(struct usb_serial *serial)
0268 {
0269 if (serial->port[0] && serial->port[0] == usbcons_info.port) {
0270 usb_serial_console_exit();
0271 usb_serial_put(serial);
0272 }
0273 }
0274
0275 void usb_serial_console_init(int minor)
0276 {
0277 if (minor == 0) {
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 pr_debug("registering the USB serial console.\n");
0292 register_console(&usbcons);
0293 }
0294 }
0295
0296 void usb_serial_console_exit(void)
0297 {
0298 if (usbcons_info.port) {
0299 unregister_console(&usbcons);
0300 usbcons_info.port->port.console = 0;
0301 usbcons_info.port = NULL;
0302 }
0303 }
0304