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

symbolserial.c (4702B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Symbol USB barcode to serial driver
      4 *
      5 * Copyright (C) 2013 Johan Hovold <jhovold@gmail.com>
      6 * Copyright (C) 2009 Greg Kroah-Hartman <gregkh@suse.de>
      7 * Copyright (C) 2009 Novell Inc.
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/tty.h>
     12#include <linux/slab.h>
     13#include <linux/tty_driver.h>
     14#include <linux/tty_flip.h>
     15#include <linux/module.h>
     16#include <linux/usb.h>
     17#include <linux/usb/serial.h>
     18#include <linux/uaccess.h>
     19
     20static const struct usb_device_id id_table[] = {
     21	{ USB_DEVICE(0x05e0, 0x0600) },
     22	{ },
     23};
     24MODULE_DEVICE_TABLE(usb, id_table);
     25
     26struct symbol_private {
     27	spinlock_t lock;	/* protects the following flags */
     28	bool throttled;
     29	bool actually_throttled;
     30};
     31
     32static void symbol_int_callback(struct urb *urb)
     33{
     34	struct usb_serial_port *port = urb->context;
     35	struct symbol_private *priv = usb_get_serial_port_data(port);
     36	unsigned char *data = urb->transfer_buffer;
     37	int status = urb->status;
     38	unsigned long flags;
     39	int result;
     40	int data_length;
     41
     42	switch (status) {
     43	case 0:
     44		/* success */
     45		break;
     46	case -ECONNRESET:
     47	case -ENOENT:
     48	case -ESHUTDOWN:
     49		/* this urb is terminated, clean up */
     50		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
     51			__func__, status);
     52		return;
     53	default:
     54		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
     55			__func__, status);
     56		goto exit;
     57	}
     58
     59	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
     60
     61	/*
     62	 * Data from the device comes with a 1 byte header:
     63	 *
     64	 * <size of data> <data>...
     65	 */
     66	if (urb->actual_length > 1) {
     67		data_length = data[0];
     68		if (data_length > (urb->actual_length - 1))
     69			data_length = urb->actual_length - 1;
     70		tty_insert_flip_string(&port->port, &data[1], data_length);
     71		tty_flip_buffer_push(&port->port);
     72	} else {
     73		dev_dbg(&port->dev, "%s - short packet\n", __func__);
     74	}
     75
     76exit:
     77	spin_lock_irqsave(&priv->lock, flags);
     78
     79	/* Continue trying to always read if we should */
     80	if (!priv->throttled) {
     81		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
     82		if (result)
     83			dev_err(&port->dev,
     84			    "%s - failed resubmitting read urb, error %d\n",
     85							__func__, result);
     86	} else
     87		priv->actually_throttled = true;
     88	spin_unlock_irqrestore(&priv->lock, flags);
     89}
     90
     91static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
     92{
     93	struct symbol_private *priv = usb_get_serial_port_data(port);
     94	unsigned long flags;
     95	int result = 0;
     96
     97	spin_lock_irqsave(&priv->lock, flags);
     98	priv->throttled = false;
     99	priv->actually_throttled = false;
    100	spin_unlock_irqrestore(&priv->lock, flags);
    101
    102	/* Start reading from the device */
    103	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
    104	if (result)
    105		dev_err(&port->dev,
    106			"%s - failed resubmitting read urb, error %d\n",
    107			__func__, result);
    108	return result;
    109}
    110
    111static void symbol_close(struct usb_serial_port *port)
    112{
    113	usb_kill_urb(port->interrupt_in_urb);
    114}
    115
    116static void symbol_throttle(struct tty_struct *tty)
    117{
    118	struct usb_serial_port *port = tty->driver_data;
    119	struct symbol_private *priv = usb_get_serial_port_data(port);
    120
    121	spin_lock_irq(&priv->lock);
    122	priv->throttled = true;
    123	spin_unlock_irq(&priv->lock);
    124}
    125
    126static void symbol_unthrottle(struct tty_struct *tty)
    127{
    128	struct usb_serial_port *port = tty->driver_data;
    129	struct symbol_private *priv = usb_get_serial_port_data(port);
    130	int result;
    131	bool was_throttled;
    132
    133	spin_lock_irq(&priv->lock);
    134	priv->throttled = false;
    135	was_throttled = priv->actually_throttled;
    136	priv->actually_throttled = false;
    137	spin_unlock_irq(&priv->lock);
    138
    139	if (was_throttled) {
    140		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
    141		if (result)
    142			dev_err(&port->dev,
    143				"%s - failed submitting read urb, error %d\n",
    144							__func__, result);
    145	}
    146}
    147
    148static int symbol_port_probe(struct usb_serial_port *port)
    149{
    150	struct symbol_private *priv;
    151
    152	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    153	if (!priv)
    154		return -ENOMEM;
    155
    156	spin_lock_init(&priv->lock);
    157
    158	usb_set_serial_port_data(port, priv);
    159
    160	return 0;
    161}
    162
    163static void symbol_port_remove(struct usb_serial_port *port)
    164{
    165	struct symbol_private *priv = usb_get_serial_port_data(port);
    166
    167	kfree(priv);
    168}
    169
    170static struct usb_serial_driver symbol_device = {
    171	.driver = {
    172		.owner =	THIS_MODULE,
    173		.name =		"symbol",
    174	},
    175	.id_table =		id_table,
    176	.num_ports =		1,
    177	.num_interrupt_in =	1,
    178	.port_probe =		symbol_port_probe,
    179	.port_remove =		symbol_port_remove,
    180	.open =			symbol_open,
    181	.close =		symbol_close,
    182	.throttle = 		symbol_throttle,
    183	.unthrottle =		symbol_unthrottle,
    184	.read_int_callback =	symbol_int_callback,
    185};
    186
    187static struct usb_serial_driver * const serial_drivers[] = {
    188	&symbol_device, NULL
    189};
    190
    191module_usb_serial_driver(serial_drivers, id_table);
    192
    193MODULE_LICENSE("GPL v2");