cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

console.c (7335B)


      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
     22struct usbcons_info {
     23	int			magic;
     24	int			break_flag;
     25	struct usb_serial_port	*port;
     26};
     27
     28static struct usbcons_info usbcons_info;
     29static 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
     47static 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 */
     55static 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	if (doflow)
    106		cflag |= CRTSCTS;
    107
    108	/*
    109	 * no need to check the index here: if the index is wrong, console
    110	 * code won't call us
    111	 */
    112	port = usb_serial_port_get_by_minor(co->index);
    113	if (port == NULL) {
    114		/* no device is connected yet, sorry :( */
    115		pr_err("No USB device connected to ttyUSB%i\n", co->index);
    116		return -ENODEV;
    117	}
    118	serial = port->serial;
    119
    120	retval = usb_autopm_get_interface(serial->interface);
    121	if (retval)
    122		goto error_get_interface;
    123
    124	tty_port_tty_set(&port->port, NULL);
    125
    126	info->port = port;
    127
    128	++port->port.count;
    129	if (!tty_port_initialized(&port->port)) {
    130		if (serial->type->set_termios) {
    131			/*
    132			 * allocate a fake tty so the driver can initialize
    133			 * the termios structure, then later call set_termios to
    134			 * configure according to command line arguments
    135			 */
    136			tty = kzalloc(sizeof(*tty), GFP_KERNEL);
    137			if (!tty) {
    138				retval = -ENOMEM;
    139				goto reset_open_count;
    140			}
    141			kref_init(&tty->kref);
    142			tty->driver = usb_serial_tty_driver;
    143			tty->index = co->index;
    144			init_ldsem(&tty->ldisc_sem);
    145			spin_lock_init(&tty->files_lock);
    146			INIT_LIST_HEAD(&tty->tty_files);
    147			kref_get(&tty->driver->kref);
    148			__module_get(tty->driver->owner);
    149			tty->ops = &usb_console_fake_tty_ops;
    150			tty_init_termios(tty);
    151			tty_port_tty_set(&port->port, tty);
    152		}
    153
    154		/* only call the device specific open if this
    155		 * is the first time the port is opened */
    156		retval = serial->type->open(NULL, port);
    157		if (retval) {
    158			dev_err(&port->dev, "could not open USB console port\n");
    159			goto fail;
    160		}
    161
    162		if (serial->type->set_termios) {
    163			tty->termios.c_cflag = cflag;
    164			tty_termios_encode_baud_rate(&tty->termios, baud, baud);
    165			memset(&dummy, 0, sizeof(struct ktermios));
    166			serial->type->set_termios(tty, port, &dummy);
    167
    168			tty_port_tty_set(&port->port, NULL);
    169			tty_save_termios(tty);
    170			tty_kref_put(tty);
    171		}
    172		tty_port_set_initialized(&port->port, 1);
    173	}
    174	/* Now that any required fake tty operations are completed restore
    175	 * the tty port count */
    176	--port->port.count;
    177	/* The console is special in terms of closing the device so
    178	 * indicate this port is now acting as a system console. */
    179	port->port.console = 1;
    180
    181	mutex_unlock(&serial->disc_mutex);
    182	return retval;
    183
    184 fail:
    185	tty_port_tty_set(&port->port, NULL);
    186	tty_kref_put(tty);
    187 reset_open_count:
    188	port->port.count = 0;
    189	info->port = NULL;
    190	usb_autopm_put_interface(serial->interface);
    191 error_get_interface:
    192	usb_serial_put(serial);
    193	mutex_unlock(&serial->disc_mutex);
    194	return retval;
    195}
    196
    197static void usb_console_write(struct console *co,
    198					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 || port->serial->dev->state == USB_STATE_NOTATTACHED)
    206		return;
    207	serial = port->serial;
    208
    209	if (count == 0)
    210		return;
    211
    212	dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count);
    213
    214	if (!port->port.console) {
    215		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
    216		return;
    217	}
    218
    219	while (count) {
    220		unsigned int i;
    221		unsigned int lf;
    222		/* search for LF so we can insert CR if necessary */
    223		for (i = 0, lf = 0 ; i < count ; i++) {
    224			if (*(buf + i) == 10) {
    225				lf = 1;
    226				i++;
    227				break;
    228			}
    229		}
    230		/* pass on to the driver specific version of this function if
    231		   it is available */
    232		retval = serial->type->write(NULL, port, buf, i);
    233		dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval);
    234		if (lf) {
    235			/* append CR after LF */
    236			unsigned char cr = 13;
    237			retval = serial->type->write(NULL, port, &cr, 1);
    238			dev_dbg(&port->dev, "%s - write cr: %d\n",
    239							__func__, retval);
    240		}
    241		buf += i;
    242		count -= i;
    243	}
    244}
    245
    246static struct tty_driver *usb_console_device(struct console *co, int *index)
    247{
    248	struct tty_driver **p = (struct tty_driver **)co->data;
    249
    250	if (!*p)
    251		return NULL;
    252
    253	*index = co->index;
    254	return *p;
    255}
    256
    257static struct console usbcons = {
    258	.name =		"ttyUSB",
    259	.write =	usb_console_write,
    260	.device =	usb_console_device,
    261	.setup =	usb_console_setup,
    262	.flags =	CON_PRINTBUFFER,
    263	.index =	-1,
    264	.data = 	&usb_serial_tty_driver,
    265};
    266
    267void usb_serial_console_disconnect(struct usb_serial *serial)
    268{
    269	if (serial->port[0] && serial->port[0] == usbcons_info.port) {
    270		usb_serial_console_exit();
    271		usb_serial_put(serial);
    272	}
    273}
    274
    275void usb_serial_console_init(int minor)
    276{
    277	if (minor == 0) {
    278		/*
    279		 * Call register_console() if this is the first device plugged
    280		 * in.  If we call it earlier, then the callback to
    281		 * console_setup() will fail, as there is not a device seen by
    282		 * the USB subsystem yet.
    283		 */
    284		/*
    285		 * Register console.
    286		 * NOTES:
    287		 * console_setup() is called (back) immediately (from
    288		 * register_console). console_write() is called immediately
    289		 * from register_console iff CON_PRINTBUFFER is set in flags.
    290		 */
    291		pr_debug("registering the USB serial console.\n");
    292		register_console(&usbcons);
    293	}
    294}
    295
    296void usb_serial_console_exit(void)
    297{
    298	if (usbcons_info.port) {
    299		unregister_console(&usbcons);
    300		usbcons_info.port->port.console = 0;
    301		usbcons_info.port = NULL;
    302	}
    303}
    304