// SPDX-License-Identifier: GPL-2.0+ /* * Safe Encapsulated USB Serial Driver * * Copyright (C) 2010 Johan Hovold <[email protected]> * Copyright (C) 2001 Lineo * Copyright (C) 2001 Hewlett-Packard * * By: * Stuart Lynne <[email protected]>, Tom Rushworth <[email protected]> */ /* * The encapsultaion is designed to overcome difficulties with some USB * hardware. * * While the USB protocol has a CRC over the data while in transit, i.e. while * being carried over the bus, there is no end to end protection. If the * hardware has any problems getting the data into or out of the USB transmit * and receive FIFO's then data can be lost. * * This protocol adds a two byte trailer to each USB packet to specify the * number of bytes of valid data and a 10 bit CRC that will allow the receiver * to verify that the entire USB packet was received without error. * * Because in this case the sender and receiver are the class and function * drivers there is now end to end protection. * * There is an additional option that can be used to force all transmitted * packets to be padded to the maximum packet size. This provides a work * around for some devices which have problems with small USB packets. * * Assuming a packetsize of N: * * 0..N-2 data and optional padding * * N-2 bits 7-2 - number of bytes of valid data * bits 1-0 top two bits of 10 bit CRC * N-1 bottom 8 bits of 10 bit CRC * * * | Data Length | 10 bit CRC | * + 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 | 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 + * * The 10 bit CRC is computed across the sent data, followed by the trailer * with the length set and the CRC set to zero. The CRC is then OR'd into * the trailer. * * When received a 10 bit CRC is computed over the entire frame including * the trailer and should be equal to zero. * * Two module parameters are used to control the encapsulation, if both are * turned of the module works as a simple serial device with NO * encapsulation. * * See linux/drivers/usbd/serial_fd for a device function driver * implementation of this. * */ #define pr_fmt(fmt) … #include <linux/kernel.h> #include <linux/errno.h> #include <linux/gfp.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> static bool safe = …; static bool padded = … IS_ENABLED(…); #define DRIVER_AUTHOR … #define DRIVER_DESC … MODULE_AUTHOR(…); MODULE_DESCRIPTION(…); MODULE_LICENSE(…) …; module_param(safe, bool, 0); MODULE_PARM_DESC(…) …; module_param(padded, bool, 0); MODULE_PARM_DESC(…) …; #define CDC_DEVICE_CLASS … #define CDC_INTERFACE_CLASS … #define CDC_INTERFACE_SUBCLASS … #define LINEO_INTERFACE_CLASS … #define LINEO_INTERFACE_SUBCLASS_SAFENET … #define LINEO_SAFENET_CRC … #define LINEO_SAFENET_CRC_PADDED … #define LINEO_INTERFACE_SUBCLASS_SAFESERIAL … #define LINEO_SAFESERIAL_CRC … #define LINEO_SAFESERIAL_CRC_PADDED … #define MY_USB_DEVICE(vend, prod, dc, ic, isc) … static const struct usb_device_id id_table[] = …; MODULE_DEVICE_TABLE(usb, id_table); static const __u16 crc10_table[256] = …; #define CRC10_INITFCS … #define CRC10_GOODFCS … #define CRC10_FCS(fcs, c) … /** * fcs_compute10 - memcpy and calculate 10 bit CRC across buffer * @sp: pointer to buffer * @len: number of bytes * @fcs: starting FCS * * Perform a memcpy and calculate fcs using ppp 10bit CRC algorithm. Return * new 10 bit FCS. */ static inline __u16 fcs_compute10(unsigned char *sp, int len, __u16 fcs) { … } static void safe_process_read_urb(struct urb *urb) { … } static int safe_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size) { … } static int safe_startup(struct usb_serial *serial) { … } static struct usb_serial_driver safe_device = …; static struct usb_serial_driver * const serial_drivers[] = …; module_usb_serial_driver(…);