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