root/drivers/usb/serial/console.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usb_console_setup
  2. usb_console_write
  3. usb_console_device
  4. usb_serial_console_disconnect
  5. usb_serial_console_init
  6. usb_serial_console_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * USB Serial Console driver
   4  *
   5  * Copyright (C) 2001 - 2002 Greg Kroah-Hartman (greg@kroah.com)
   6  *
   7  * Thanks to Randy Dunlap for the original version of this code.
   8  *
   9  */
  10 
  11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12 
  13 #include <linux/kernel.h>
  14 #include <linux/module.h>
  15 #include <linux/slab.h>
  16 #include <linux/tty.h>
  17 #include <linux/console.h>
  18 #include <linux/serial.h>
  19 #include <linux/usb.h>
  20 #include <linux/usb/serial.h>
  21 
  22 struct usbcons_info {
  23         int                     magic;
  24         int                     break_flag;
  25         struct usb_serial_port  *port;
  26 };
  27 
  28 static struct usbcons_info usbcons_info;
  29 static struct console usbcons;
  30 
  31 /*
  32  * ------------------------------------------------------------
  33  * USB Serial console driver
  34  *
  35  * Much of the code here is copied from drivers/char/serial.c
  36  * and implements a phony serial console in the same way that
  37  * serial.c does so that in case some software queries it,
  38  * it will get the same results.
  39  *
  40  * Things that are different from the way the serial port code
  41  * does things, is that we call the lower level usb-serial
  42  * driver code to initialize the device, and we set the initial
  43  * console speeds based on the command line arguments.
  44  * ------------------------------------------------------------
  45  */
  46 
  47 static const struct tty_operations usb_console_fake_tty_ops = {
  48 };
  49 
  50 /*
  51  * The parsing of the command line works exactly like the
  52  * serial.c code, except that the specifier is "ttyUSB" instead
  53  * of "ttyS".
  54  */
  55 static int usb_console_setup(struct console *co, char *options)
  56 {
  57         struct usbcons_info *info = &usbcons_info;
  58         int baud = 9600;
  59         int bits = 8;
  60         int parity = 'n';
  61         int doflow = 0;
  62         int cflag = CREAD | HUPCL | CLOCAL;
  63         char *s;
  64         struct usb_serial *serial;
  65         struct usb_serial_port *port;
  66         int retval;
  67         struct tty_struct *tty = NULL;
  68         struct ktermios dummy;
  69 
  70         if (options) {
  71                 baud = simple_strtoul(options, NULL, 10);
  72                 s = options;
  73                 while (*s >= '0' && *s <= '9')
  74                         s++;
  75                 if (*s)
  76                         parity = *s++;
  77                 if (*s)
  78                         bits   = *s++ - '0';
  79                 if (*s)
  80                         doflow = (*s++ == 'r');
  81         }
  82         
  83         /* Sane default */
  84         if (baud == 0)
  85                 baud = 9600;
  86 
  87         switch (bits) {
  88         case 7:
  89                 cflag |= CS7;
  90                 break;
  91         default:
  92         case 8:
  93                 cflag |= CS8;
  94                 break;
  95         }
  96         switch (parity) {
  97         case 'o': case 'O':
  98                 cflag |= PARODD;
  99                 break;
 100         case 'e': case 'E':
 101                 cflag |= PARENB;
 102                 break;
 103         }
 104 
 105         /*
 106          * no need to check the index here: if the index is wrong, console
 107          * code won't call us
 108          */
 109         port = usb_serial_port_get_by_minor(co->index);
 110         if (port == NULL) {
 111                 /* no device is connected yet, sorry :( */
 112                 pr_err("No USB device connected to ttyUSB%i\n", co->index);
 113                 return -ENODEV;
 114         }
 115         serial = port->serial;
 116 
 117         retval = usb_autopm_get_interface(serial->interface);
 118         if (retval)
 119                 goto error_get_interface;
 120 
 121         tty_port_tty_set(&port->port, NULL);
 122 
 123         info->port = port;
 124 
 125         ++port->port.count;
 126         if (!tty_port_initialized(&port->port)) {
 127                 if (serial->type->set_termios) {
 128                         /*
 129                          * allocate a fake tty so the driver can initialize
 130                          * the termios structure, then later call set_termios to
 131                          * configure according to command line arguments
 132                          */
 133                         tty = kzalloc(sizeof(*tty), GFP_KERNEL);
 134                         if (!tty) {
 135                                 retval = -ENOMEM;
 136                                 goto reset_open_count;
 137                         }
 138                         kref_init(&tty->kref);
 139                         tty->driver = usb_serial_tty_driver;
 140                         tty->index = co->index;
 141                         init_ldsem(&tty->ldisc_sem);
 142                         spin_lock_init(&tty->files_lock);
 143                         INIT_LIST_HEAD(&tty->tty_files);
 144                         kref_get(&tty->driver->kref);
 145                         __module_get(tty->driver->owner);
 146                         tty->ops = &usb_console_fake_tty_ops;
 147                         tty_init_termios(tty);
 148                         tty_port_tty_set(&port->port, tty);
 149                 }
 150 
 151                 /* only call the device specific open if this
 152                  * is the first time the port is opened */
 153                 retval = serial->type->open(NULL, port);
 154                 if (retval) {
 155                         dev_err(&port->dev, "could not open USB console port\n");
 156                         goto fail;
 157                 }
 158 
 159                 if (serial->type->set_termios) {
 160                         tty->termios.c_cflag = cflag;
 161                         tty_termios_encode_baud_rate(&tty->termios, baud, baud);
 162                         memset(&dummy, 0, sizeof(struct ktermios));
 163                         serial->type->set_termios(tty, port, &dummy);
 164 
 165                         tty_port_tty_set(&port->port, NULL);
 166                         tty_save_termios(tty);
 167                         tty_kref_put(tty);
 168                 }
 169                 tty_port_set_initialized(&port->port, 1);
 170         }
 171         /* Now that any required fake tty operations are completed restore
 172          * the tty port count */
 173         --port->port.count;
 174         /* The console is special in terms of closing the device so
 175          * indicate this port is now acting as a system console. */
 176         port->port.console = 1;
 177 
 178         mutex_unlock(&serial->disc_mutex);
 179         return retval;
 180 
 181  fail:
 182         tty_port_tty_set(&port->port, NULL);
 183         tty_kref_put(tty);
 184  reset_open_count:
 185         port->port.count = 0;
 186         info->port = NULL;
 187         usb_autopm_put_interface(serial->interface);
 188  error_get_interface:
 189         usb_serial_put(serial);
 190         mutex_unlock(&serial->disc_mutex);
 191         return retval;
 192 }
 193 
 194 static void usb_console_write(struct console *co,
 195                                         const char *buf, unsigned count)
 196 {
 197         static struct usbcons_info *info = &usbcons_info;
 198         struct usb_serial_port *port = info->port;
 199         struct usb_serial *serial;
 200         int retval = -ENODEV;
 201 
 202         if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
 203                 return;
 204         serial = port->serial;
 205 
 206         if (count == 0)
 207                 return;
 208 
 209         dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count);
 210 
 211         if (!port->port.console) {
 212                 dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 213                 return;
 214         }
 215 
 216         while (count) {
 217                 unsigned int i;
 218                 unsigned int lf;
 219                 /* search for LF so we can insert CR if necessary */
 220                 for (i = 0, lf = 0 ; i < count ; i++) {
 221                         if (*(buf + i) == 10) {
 222                                 lf = 1;
 223                                 i++;
 224                                 break;
 225                         }
 226                 }
 227                 /* pass on to the driver specific version of this function if
 228                    it is available */
 229                 retval = serial->type->write(NULL, port, buf, i);
 230                 dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval);
 231                 if (lf) {
 232                         /* append CR after LF */
 233                         unsigned char cr = 13;
 234                         retval = serial->type->write(NULL, port, &cr, 1);
 235                         dev_dbg(&port->dev, "%s - write cr: %d\n",
 236                                                         __func__, retval);
 237                 }
 238                 buf += i;
 239                 count -= i;
 240         }
 241 }
 242 
 243 static struct tty_driver *usb_console_device(struct console *co, int *index)
 244 {
 245         struct tty_driver **p = (struct tty_driver **)co->data;
 246 
 247         if (!*p)
 248                 return NULL;
 249 
 250         *index = co->index;
 251         return *p;
 252 }
 253 
 254 static struct console usbcons = {
 255         .name =         "ttyUSB",
 256         .write =        usb_console_write,
 257         .device =       usb_console_device,
 258         .setup =        usb_console_setup,
 259         .flags =        CON_PRINTBUFFER,
 260         .index =        -1,
 261         .data =         &usb_serial_tty_driver,
 262 };
 263 
 264 void usb_serial_console_disconnect(struct usb_serial *serial)
 265 {
 266         if (serial->port[0] && serial->port[0] == usbcons_info.port) {
 267                 usb_serial_console_exit();
 268                 usb_serial_put(serial);
 269         }
 270 }
 271 
 272 void usb_serial_console_init(int minor)
 273 {
 274         if (minor == 0) {
 275                 /*
 276                  * Call register_console() if this is the first device plugged
 277                  * in.  If we call it earlier, then the callback to
 278                  * console_setup() will fail, as there is not a device seen by
 279                  * the USB subsystem yet.
 280                  */
 281                 /*
 282                  * Register console.
 283                  * NOTES:
 284                  * console_setup() is called (back) immediately (from
 285                  * register_console). console_write() is called immediately
 286                  * from register_console iff CON_PRINTBUFFER is set in flags.
 287                  */
 288                 pr_debug("registering the USB serial console.\n");
 289                 register_console(&usbcons);
 290         }
 291 }
 292 
 293 void usb_serial_console_exit(void)
 294 {
 295         if (usbcons_info.port) {
 296                 unregister_console(&usbcons);
 297                 usbcons_info.port->port.console = 0;
 298                 usbcons_info.port = NULL;
 299         }
 300 }
 301 

/* [<][>][^][v][top][bottom][index][help] */