| 1 | |
| 2 | |
| 3 | * Safe Encapsulated USB Serial Driver
|
| 4 | *
|
| 5 | * Copyright (C) 2010 Johan Hovold <[email protected]>
|
| 6 | * Copyright (C) 2001 Lineo
|
| 7 | * Copyright (C) 2001 Hewlett-Packard
|
| 8 | *
|
| 9 | * By:
|
| 10 | * Stuart Lynne <[email protected]>, Tom Rushworth <[email protected]>
|
| 11 |
|
| 12 |
|
| 13 | |
| 14 | * The encapsultaion is designed to overcome difficulties with some USB
|
| 15 | * hardware.
|
| 16 | *
|
| 17 | * While the USB protocol has a CRC over the data while in transit, i.e. while
|
| 18 | * being carried over the bus, there is no end to end protection. If the
|
| 19 | * hardware has any problems getting the data into or out of the USB transmit
|
| 20 | * and receive FIFO's then data can be lost.
|
| 21 | *
|
| 22 | * This protocol adds a two byte trailer to each USB packet to specify the
|
| 23 | * number of bytes of valid data and a 10 bit CRC that will allow the receiver
|
| 24 | * to verify that the entire USB packet was received without error.
|
| 25 | *
|
| 26 | * Because in this case the sender and receiver are the class and function
|
| 27 | * drivers there is now end to end protection.
|
| 28 | *
|
| 29 | * There is an additional option that can be used to force all transmitted
|
| 30 | * packets to be padded to the maximum packet size. This provides a work
|
| 31 | * around for some devices which have problems with small USB packets.
|
| 32 | *
|
| 33 | * Assuming a packetsize of N:
|
| 34 | *
|
| 35 | * 0..N-2 data and optional padding
|
| 36 | *
|
| 37 | * N-2 bits 7-2 - number of bytes of valid data
|
| 38 | * bits 1-0 top two bits of 10 bit CRC
|
| 39 | * N-1 bottom 8 bits of 10 bit CRC
|
| 40 | *
|
| 41 | *
|
| 42 | * | Data Length | 10 bit CRC |
|
| 43 | * + 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 | 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 +
|
| 44 | *
|
| 45 | * The 10 bit CRC is computed across the sent data, followed by the trailer
|
| 46 | * with the length set and the CRC set to zero. The CRC is then OR'd into
|
| 47 | * the trailer.
|
| 48 | *
|
| 49 | * When received a 10 bit CRC is computed over the entire frame including
|
| 50 | * the trailer and should be equal to zero.
|
| 51 | *
|
| 52 | * Two module parameters are used to control the encapsulation, if both are
|
| 53 | * turned of the module works as a simple serial device with NO
|
| 54 | * encapsulation.
|
| 55 | *
|
| 56 | * See linux/drivers/usbd/serial_fd for a device function driver
|
| 57 | * implementation of this.
|
| 58 | *
|
| 59 |
|
| 60 |
|
| 61 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
| 62 |
|
| 63 | #include <linux/kernel.h>
|
| 64 | #include <linux/errno.h>
|
| 65 | #include <linux/gfp.h>
|
| 66 | #include <linux/tty.h>
|
| 67 | #include <linux/tty_flip.h>
|
| 68 | #include <linux/module.h>
|
| 69 | #include <linux/spinlock.h>
|
| 70 | #include <linux/usb.h>
|
| 71 | #include <linux/usb/serial.h>
|
| 72 |
|
| 73 | static bool safe = true;
|
| 74 | static bool padded = IS_ENABLED(CONFIG_USB_SERIAL_SAFE_PADDED);
|
| 75 |
|
| 76 | #define DRIVER_AUTHOR "[email protected], [email protected], Johan Hovold <[email protected]>"
|
| 77 | #define DRIVER_DESC "USB Safe Encapsulated Serial"
|
| 78 |
|
| 79 | MODULE_AUTHOR(DRIVER_AUTHOR);
|
| 80 | MODULE_DESCRIPTION(DRIVER_DESC);
|
| 81 | MODULE_LICENSE("GPL");
|
| 82 |
|
| 83 | module_param(safe, bool, 0);
|
| 84 | MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off");
|
| 85 |
|
| 86 | module_param(padded, bool, 0);
|
| 87 | MODULE_PARM_DESC(padded, "Pad to full wMaxPacketSize On/Off");
|
| 88 |
|
| 89 | #define CDC_DEVICE_CLASS 0x02
|
| 90 |
|
| 91 | #define CDC_INTERFACE_CLASS 0x02
|
| 92 | #define CDC_INTERFACE_SUBCLASS 0x06
|
| 93 |
|
| 94 | #define LINEO_INTERFACE_CLASS 0xff
|
| 95 |
|
| 96 | #define LINEO_INTERFACE_SUBCLASS_SAFENET 0x01
|
| 97 | #define LINEO_SAFENET_CRC 0x01
|
| 98 | #define LINEO_SAFENET_CRC_PADDED 0x02
|
| 99 |
|
| 100 | #define LINEO_INTERFACE_SUBCLASS_SAFESERIAL 0x02
|
| 101 | #define LINEO_SAFESERIAL_CRC 0x01
|
| 102 | #define LINEO_SAFESERIAL_CRC_PADDED 0x02
|
| 103 |
|
| 104 |
|
| 105 | #define MY_USB_DEVICE(vend, prod, dc, ic, isc) \
|
| 106 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
|
| 107 | USB_DEVICE_ID_MATCH_DEV_CLASS | \
|
| 108 | USB_DEVICE_ID_MATCH_INT_CLASS | \
|
| 109 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, \
|
| 110 | .idVendor = (vend), \
|
| 111 | .idProduct = (prod),\
|
| 112 | .bDeviceClass = (dc),\
|
| 113 | .bInterfaceClass = (ic), \
|
| 114 | .bInterfaceSubClass = (isc),
|
| 115 |
|
| 116 | static const struct usb_device_id id_table[] = {
|
| 117 | {MY_USB_DEVICE(0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
|
| 118 | {MY_USB_DEVICE(0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
|
| 119 | {MY_USB_DEVICE(0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
|
| 120 | {MY_USB_DEVICE(0x4dd, 0x8002, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
|
| 121 | {MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
|
| 122 | {MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
|
| 123 | {MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
|
| 124 | {}
|
| 125 | };
|
| 126 |
|
| 127 | MODULE_DEVICE_TABLE(usb, id_table);
|
| 128 |
|
| 129 | static const __u16 crc10_table[256] = {
|
| 130 | 0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff,
|
| 131 | 0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe,
|
| 132 | 0x031, 0x202, 0x264, 0x057, 0x2a8, 0x09b, 0x0fd, 0x2ce,
|
| 133 | 0x330, 0x103, 0x165, 0x356, 0x1a9, 0x39a, 0x3fc, 0x1cf,
|
| 134 | 0x062, 0x251, 0x237, 0x004, 0x2fb, 0x0c8, 0x0ae, 0x29d,
|
| 135 | 0x363, 0x150, 0x136, 0x305, 0x1fa, 0x3c9, 0x3af, 0x19c,
|
| 136 | 0x053, 0x260, 0x206, 0x035, 0x2ca, 0x0f9, 0x09f, 0x2ac,
|
| 137 | 0x352, 0x161, 0x107, 0x334, 0x1cb, 0x3f8, 0x39e, 0x1ad,
|
| 138 | 0x0c4, 0x2f7, 0x291, 0x0a2, 0x25d, 0x06e, 0x008, 0x23b,
|
| 139 | 0x3c5, 0x1f6, 0x190, 0x3a3, 0x15c, 0x36f, 0x309, 0x13a,
|
| 140 | 0x0f5, 0x2c6, 0x2a0, 0x093, 0x26c, 0x05f, 0x039, 0x20a,
|
| 141 | 0x3f4, 0x1c7, 0x1a1, 0x392, 0x16d, 0x35e, 0x338, 0x10b,
|
| 142 | 0x0a6, 0x295, 0x2f3, 0x0c0, 0x23f, 0x00c, 0x06a, 0x259,
|
| 143 | 0x3a7, 0x194, 0x1f2, 0x3c1, 0x13e, 0x30d, 0x36b, 0x158,
|
| 144 | 0x097, 0x2a4, 0x2c2, 0x0f1, 0x20e, 0x03d, 0x05b, 0x268,
|
| 145 | 0x396, 0x1a5, 0x1c3, 0x3f0, 0x10f, 0x33c, 0x35a, 0x169,
|
| 146 | 0x188, 0x3bb, 0x3dd, 0x1ee, 0x311, 0x122, 0x144, 0x377,
|
| 147 | 0x289, 0x0ba, 0x0dc, 0x2ef, 0x010, 0x223, 0x245, 0x076,
|
| 148 | 0x1b9, 0x38a, 0x3ec, 0x1df, 0x320, 0x113, 0x175, 0x346,
|
| 149 | 0x2b8, 0x08b, 0x0ed, 0x2de, 0x021, 0x212, 0x274, 0x047,
|
| 150 | 0x1ea, 0x3d9, 0x3bf, 0x18c, 0x373, 0x140, 0x126, 0x315,
|
| 151 | 0x2eb, 0x0d8, 0x0be, 0x28d, 0x072, 0x241, 0x227, 0x014,
|
| 152 | 0x1db, 0x3e8, 0x38e, 0x1bd, 0x342, 0x171, 0x117, 0x324,
|
| 153 | 0x2da, 0x0e9, 0x08f, 0x2bc, 0x043, 0x270, 0x216, 0x025,
|
| 154 | 0x14c, 0x37f, 0x319, 0x12a, 0x3d5, 0x1e6, 0x180, 0x3b3,
|
| 155 | 0x24d, 0x07e, 0x018, 0x22b, 0x0d4, 0x2e7, 0x281, 0x0b2,
|
| 156 | 0x17d, 0x34e, 0x328, 0x11b, 0x3e4, 0x1d7, 0x1b1, 0x382,
|
| 157 | 0x27c, 0x04f, 0x029, 0x21a, 0x0e5, 0x2d6, 0x2b0, 0x083,
|
| 158 | 0x12e, 0x31d, 0x37b, 0x148, 0x3b7, 0x184, 0x1e2, 0x3d1,
|
| 159 | 0x22f, 0x01c, 0x07a, 0x249, 0x0b6, 0x285, 0x2e3, 0x0d0,
|
| 160 | 0x11f, 0x32c, 0x34a, 0x179, 0x386, 0x1b5, 0x1d3, 0x3e0,
|
| 161 | 0x21e, 0x02d, 0x04b, 0x278, 0x087, 0x2b4, 0x2d2, 0x0e1,
|
| 162 | };
|
| 163 |
|
| 164 | #define CRC10_INITFCS 0x000
|
| 165 | #define CRC10_GOODFCS 0x000
|
| 166 | #define CRC10_FCS(fcs, c) ((((fcs) << 8) & 0x3ff) ^ crc10_table[((fcs) >> 2) & 0xff] ^ (c))
|
| 167 |
|
| 168 | |
| 169 | * fcs_compute10 - memcpy and calculate 10 bit CRC across buffer
|
| 170 | * @sp: pointer to buffer
|
| 171 | * @len: number of bytes
|
| 172 | * @fcs: starting FCS
|
| 173 | *
|
| 174 | * Perform a memcpy and calculate fcs using ppp 10bit CRC algorithm. Return
|
| 175 | * new 10 bit FCS.
|
| 176 |
|
| 177 | static inline __u16 fcs_compute10(unsigned char *sp, int len, __u16 fcs)
|
| 178 | {
|
| 179 | for (; len-- > 0; fcs = CRC10_FCS(fcs, *sp++));
|
| 180 | return fcs;
|
| 181 | }
|
| 182 |
|
| 183 | static void safe_process_read_urb(struct urb *urb)
|
| 184 | {
|
| 185 | struct usb_serial_port *port = urb->context;
|
| 186 | unsigned char *data = urb->transfer_buffer;
|
| 187 | unsigned char length = urb->actual_length;
|
| 188 | int actual_length;
|
| 189 | __u16 fcs;
|
| 190 |
|
| 191 | if (!length)
|
| 192 | return;
|
| 193 |
|
| 194 | if (!safe)
|
| 195 | goto out;
|
| 196 |
|
| 197 | if (length < 2) {
|
| 198 | dev_err(&port->dev, "malformed packet\n");
|
| 199 | return;
|
| 200 | }
|
| 201 |
|
| 202 | fcs = fcs_compute10(data, length, CRC10_INITFCS);
|
| 203 | if (fcs) {
|
| 204 | dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
|
| 205 | return;
|
| 206 | }
|
| 207 |
|
| 208 | actual_length = data[length - 2] >> 2;
|
| 209 | if (actual_length > (length - 2)) {
|
| 210 | dev_err(&port->dev, "%s - inconsistent lengths %d:%d\n",
|
| 211 | __func__, actual_length, length);
|
| 212 | return;
|
| 213 | }
|
| 214 | dev_info(&urb->dev->dev, "%s - actual: %d\n", __func__, actual_length);
|
| 215 | length = actual_length;
|
| 216 | out:
|
| 217 | tty_insert_flip_string(&port->port, data, length);
|
| 218 | tty_flip_buffer_push(&port->port);
|
| 219 | }
|
| 220 |
|
| 221 | static int safe_prepare_write_buffer(struct usb_serial_port *port,
|
| 222 | void *dest, size_t size)
|
| 223 | {
|
| 224 | unsigned char *buf = dest;
|
| 225 | int count;
|
| 226 | int trailer_len;
|
| 227 | int pkt_len;
|
| 228 | __u16 fcs;
|
| 229 |
|
| 230 | trailer_len = safe ? 2 : 0;
|
| 231 |
|
| 232 | count = kfifo_out_locked(&port->write_fifo, buf, size - trailer_len,
|
| 233 | &port->lock);
|
| 234 | if (!safe)
|
| 235 | return count;
|
| 236 |
|
| 237 |
|
| 238 | if (padded) {
|
| 239 | pkt_len = size;
|
| 240 | memset(buf + count, '0', pkt_len - count - trailer_len);
|
| 241 | } else {
|
| 242 | pkt_len = count + trailer_len;
|
| 243 | }
|
| 244 |
|
| 245 |
|
| 246 | buf[pkt_len - 2] = count << 2;
|
| 247 | buf[pkt_len - 1] = 0;
|
| 248 |
|
| 249 |
|
| 250 | fcs = fcs_compute10(buf, pkt_len, CRC10_INITFCS);
|
| 251 | buf[pkt_len - 2] |= fcs >> 8;
|
| 252 | buf[pkt_len - 1] |= fcs & 0xff;
|
| 253 |
|
| 254 | return pkt_len;
|
| 255 | }
|
| 256 |
|
| 257 | static int safe_startup(struct usb_serial *serial)
|
| 258 | {
|
| 259 | struct usb_interface_descriptor *desc;
|
| 260 | int bulk_out_size;
|
| 261 |
|
| 262 | if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS)
|
| 263 | return -ENODEV;
|
| 264 |
|
| 265 | desc = &serial->interface->cur_altsetting->desc;
|
| 266 |
|
| 267 | if (desc->bInterfaceClass != LINEO_INTERFACE_CLASS)
|
| 268 | return -ENODEV;
|
| 269 | if (desc->bInterfaceSubClass != LINEO_INTERFACE_SUBCLASS_SAFESERIAL)
|
| 270 | return -ENODEV;
|
| 271 |
|
| 272 | switch (desc->bInterfaceProtocol) {
|
| 273 | case LINEO_SAFESERIAL_CRC:
|
| 274 | break;
|
| 275 | case LINEO_SAFESERIAL_CRC_PADDED:
|
| 276 | padded = true;
|
| 277 | break;
|
| 278 | default:
|
| 279 | return -EINVAL;
|
| 280 | }
|
| 281 |
|
| 282 | |
| 283 | * The bulk-out buffer needs to be large enough for the two-byte
|
| 284 | * trailer in safe mode, but assume anything smaller than eight bytes
|
| 285 | * is broken.
|
| 286 |
|
| 287 | bulk_out_size = serial->port[0]->bulk_out_size;
|
| 288 | if (bulk_out_size > 0 && bulk_out_size < 8)
|
| 289 | return -EINVAL;
|
| 290 |
|
| 291 | return 0;
|
| 292 | }
|
| 293 |
|
| 294 | static struct usb_serial_driver safe_device = {
|
| 295 | .driver = {
|
| 296 | .name = "safe_serial",
|
| 297 | },
|
| 298 | .id_table = id_table,
|
| 299 | .num_ports = 1,
|
| 300 | .process_read_urb = safe_process_read_urb,
|
| 301 | .prepare_write_buffer = safe_prepare_write_buffer,
|
| 302 | .attach = safe_startup,
|
| 303 | };
|
| 304 |
|
| 305 | static struct usb_serial_driver * const serial_drivers[] = {
|
| 306 | &safe_device, NULL
|
| 307 | };
|
| 308 |
|
| 309 | module_usb_serial_driver(serial_drivers, id_table);
|