safe_serial.c revision 4c4c9432a6c916729c7296c47fe93b053a73e20c
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Safe Encapsulated USB Serial Driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 Lineo 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 Hewlett-Packard 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * By: 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stuart Lynne <sl@lineo.com>, Tom Rushworth <tbr@lineo.com> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The encapsultaion is designed to overcome difficulties with some USB hardware. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * While the USB protocol has a CRC over the data while in transit, i.e. while 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * being carried over the bus, there is no end to end protection. If the hardware 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has any problems getting the data into or out of the USB transmit and receive 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIFO's then data can be lost. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This protocol adds a two byte trailer to each USB packet to specify the number 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of bytes of valid data and a 10 bit CRC that will allow the receiver to verify 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that the entire USB packet was received without error. 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Because in this case the sender and receiver are the class and function drivers 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there is now end to end protection. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is an additional option that can be used to force all transmitted packets 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to be padded to the maximum packet size. This provides a work around for some 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * devices which have problems with small USB packets. 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Assuming a packetsize of N: 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0..N-2 data and optional padding 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * N-2 bits 7-2 - number of bytes of valid data 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bits 1-0 top two bits of 10 bit CRC 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * N-1 bottom 8 bits of 10 bit CRC 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | Data Length | 10 bit CRC | 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * + 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 | 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 + 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The 10 bit CRC is computed across the sent data, followed by the trailer with 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the length set and the CRC set to zero. The CRC is then OR'd into the trailer. 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When received a 10 bit CRC is computed over the entire frame including the trailer 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and should be equal to zero. 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Two module parameters are used to control the encapsulation, if both are 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * turned of the module works as a simple serial device with NO 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * encapsulation. 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See linux/drivers/usbd/serial_fd for a device function driver 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * implementation of this. 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h> 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "usb-serial.h" 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_USB_SAFE_PADDED 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG_USB_SAFE_PADDED 0 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int safe = 1; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int padded = CONFIG_USB_SAFE_PADDED; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "v0.0b" 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com" 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB Safe Encapsulated Serial" 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR (DRIVER_AUTHOR); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) 95521daed8db4443a1574a98fc3abae8e230f09eaaRandy Dunlap#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u16 vendor; // no default 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u16 product; // no default 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(vendor, ushort, 0); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(product, ushort, 0); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(product, "User specified USB idProduct (required)"); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(safe, bool, 0); 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off"); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(padded, bool, 0); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(padded, "Pad to full wMaxPacketSize On/Off"); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CDC_DEVICE_CLASS 0x02 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CDC_INTERFACE_CLASS 0x02 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CDC_INTERFACE_SUBCLASS 0x06 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINEO_INTERFACE_CLASS 0xff 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINEO_INTERFACE_SUBCLASS_SAFENET 0x01 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINEO_SAFENET_CRC 0x01 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINEO_SAFENET_CRC_PADDED 0x02 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINEO_INTERFACE_SUBCLASS_SAFESERIAL 0x02 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINEO_SAFESERIAL_CRC 0x01 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINEO_SAFESERIAL_CRC_PADDED 0x02 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MY_USB_DEVICE(vend,prod,dc,ic,isc) \ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS | \ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS, \ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .idVendor = (vend), \ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .idProduct = (prod),\ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDeviceClass = (dc),\ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bInterfaceClass = (ic), \ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bInterfaceSubClass = (isc), 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table[] = { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE (0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Itsy 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE (0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Calypso 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE (0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Iris 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE (0x4dd, 0x8002, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS, 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // extra null entry for module 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // vendor/produc parameters 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {} // terminating entry 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (usb, id_table); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver safe_driver = { 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "safe_serial", 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = usb_serial_probe, 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = usb_serial_disconnect, 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 167ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman .no_dynamic_id = 1, 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1704c4c9432a6c916729c7296c47fe93b053a73e20cArjan van de Venstatic const __u16 crc10_table[256] = { 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff, 0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x031, 0x202, 0x264, 0x057, 0x2a8, 0x09b, 0x0fd, 0x2ce, 0x330, 0x103, 0x165, 0x356, 0x1a9, 0x39a, 0x3fc, 0x1cf, 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x062, 0x251, 0x237, 0x004, 0x2fb, 0x0c8, 0x0ae, 0x29d, 0x363, 0x150, 0x136, 0x305, 0x1fa, 0x3c9, 0x3af, 0x19c, 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x053, 0x260, 0x206, 0x035, 0x2ca, 0x0f9, 0x09f, 0x2ac, 0x352, 0x161, 0x107, 0x334, 0x1cb, 0x3f8, 0x39e, 0x1ad, 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x0c4, 0x2f7, 0x291, 0x0a2, 0x25d, 0x06e, 0x008, 0x23b, 0x3c5, 0x1f6, 0x190, 0x3a3, 0x15c, 0x36f, 0x309, 0x13a, 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x0f5, 0x2c6, 0x2a0, 0x093, 0x26c, 0x05f, 0x039, 0x20a, 0x3f4, 0x1c7, 0x1a1, 0x392, 0x16d, 0x35e, 0x338, 0x10b, 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x0a6, 0x295, 0x2f3, 0x0c0, 0x23f, 0x00c, 0x06a, 0x259, 0x3a7, 0x194, 0x1f2, 0x3c1, 0x13e, 0x30d, 0x36b, 0x158, 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x097, 0x2a4, 0x2c2, 0x0f1, 0x20e, 0x03d, 0x05b, 0x268, 0x396, 0x1a5, 0x1c3, 0x3f0, 0x10f, 0x33c, 0x35a, 0x169, 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x188, 0x3bb, 0x3dd, 0x1ee, 0x311, 0x122, 0x144, 0x377, 0x289, 0x0ba, 0x0dc, 0x2ef, 0x010, 0x223, 0x245, 0x076, 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x1b9, 0x38a, 0x3ec, 0x1df, 0x320, 0x113, 0x175, 0x346, 0x2b8, 0x08b, 0x0ed, 0x2de, 0x021, 0x212, 0x274, 0x047, 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x1ea, 0x3d9, 0x3bf, 0x18c, 0x373, 0x140, 0x126, 0x315, 0x2eb, 0x0d8, 0x0be, 0x28d, 0x072, 0x241, 0x227, 0x014, 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x1db, 0x3e8, 0x38e, 0x1bd, 0x342, 0x171, 0x117, 0x324, 0x2da, 0x0e9, 0x08f, 0x2bc, 0x043, 0x270, 0x216, 0x025, 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x14c, 0x37f, 0x319, 0x12a, 0x3d5, 0x1e6, 0x180, 0x3b3, 0x24d, 0x07e, 0x018, 0x22b, 0x0d4, 0x2e7, 0x281, 0x0b2, 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x17d, 0x34e, 0x328, 0x11b, 0x3e4, 0x1d7, 0x1b1, 0x382, 0x27c, 0x04f, 0x029, 0x21a, 0x0e5, 0x2d6, 0x2b0, 0x083, 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x12e, 0x31d, 0x37b, 0x148, 0x3b7, 0x184, 0x1e2, 0x3d1, 0x22f, 0x01c, 0x07a, 0x249, 0x0b6, 0x285, 0x2e3, 0x0d0, 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x11f, 0x32c, 0x34a, 0x179, 0x386, 0x1b5, 0x1d3, 0x3e0, 0x21e, 0x02d, 0x04b, 0x278, 0x087, 0x2b4, 0x2d2, 0x0e1, 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CRC10_INITFCS 0x000 // Initial FCS value 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CRC10_GOODFCS 0x000 // Good final FCS value 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CRC10_FCS(fcs, c) ( (((fcs) << 8) & 0x3ff) ^ crc10_table[((fcs) >> 2) & 0xff] ^ (c)) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fcs_compute10 - memcpy and calculate 10 bit CRC across buffer 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @sp: pointer to buffer 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: number of bytes 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fcs: starting FCS 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Perform a memcpy and calculate fcs using ppp 10bit CRC algorithm. Return 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * new 10 bit FCS. 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u16 __inline__ fcs_compute10 (unsigned char *sp, int len, __u16 fcs) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; len-- > 0; fcs = CRC10_FCS (fcs, *sp++)); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return fcs; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void safe_read_bulk_callback (struct urb *urb, struct pt_regs *regs) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *) urb->context; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char length = urb->actual_length; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s", __FUNCTION__); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status) { 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("safe_read_bulk_callback length: %d", port->read_urb->actual_length); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef ECHO_RCV 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *cp = port->read_urb->transfer_buffer; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < port->read_urb->actual_length; i++) { 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((i % 32) == 0) { 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("\nru[%02x] ", i); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%02x ", *cp++); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("\n"); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (safe) { 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u16 fcs; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(fcs = fcs_compute10 (data, length, CRC10_INITFCS))) { 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int actual_length = data[length - 2] >> 2; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (actual_length <= (length - 2)) { 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info ("%s - actual: %d", __FUNCTION__, actual_length); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < actual_length; i++) { 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_insert_flip_char (port->tty, data[i], 0); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flip_buffer_push (port->tty); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err ("%s - inconsistent lengths %d:%d", __FUNCTION__, 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actual_length, length); 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err ("%s - bad CRC %x", __FUNCTION__, fcs); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < length; i++) { 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_insert_flip_char (port->tty, data[i], 0); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flip_buffer_push (port->tty); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Continue trying to always read */ 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb (urb, port->serial->dev, 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvbulkpipe (port->serial->dev, port->bulk_in_endpointAddress), 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->transfer_buffer, urb->transfer_buffer_length, 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds safe_read_bulk_callback, port); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = usb_submit_urb (urb, GFP_ATOMIC))) { 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int safe_write (struct usb_serial_port *port, const unsigned char *buf, int count) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int packet_length; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("safe_write port: %p %d urb: %p count: %d", port, port->number, port->write_urb, 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count); 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->write_urb) { 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s - write urb NULL", __FUNCTION__); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("safe_write write_urb: %d transfer_buffer_length", 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->transfer_buffer_length); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->write_urb->transfer_buffer_length) { 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s - write urb transfer_buffer_length zero", __FUNCTION__); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count == 0) { 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s - write request of 0 bytes", __FUNCTION__); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 302507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman spin_lock(&port->lock); 303507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman if (port->write_urb_busy) { 304507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman spin_unlock(&port->lock); 305507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman dbg("%s - already writing", __FUNCTION__); 306507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman return 0; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 308507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman port->write_urb_busy = 1; 309507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman spin_unlock(&port->lock); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packet_length = port->bulk_out_size; // get max packetsize 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = packet_length - (safe ? 2 : 0); // get bytes to send 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = (count > i) ? i : count; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // get the data into the transfer buffer 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = port->write_urb->transfer_buffer; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (data, '0', packet_length); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (data, buf, count); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (safe) { 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u16 fcs; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // pad if necessary 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!padded) { 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packet_length = count + 2; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // set count 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[packet_length - 2] = count << 2; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[packet_length - 1] = 0; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // compute fcs and insert into trailer 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fcs = fcs_compute10 (data, packet_length, CRC10_INITFCS); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[packet_length - 2] |= fcs >> 8; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[packet_length - 1] |= fcs & 0xff; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // set length to send 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->transfer_buffer_length = packet_length; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->transfer_buffer_length = count; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef ECHO_TX 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *cp = port->write_urb->transfer_buffer; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < port->write_urb->transfer_buffer_length; i++) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((i % 32) == 0) { 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("\nsu[%02x] ", i); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%02x ", *cp++); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("\n"); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->dev = port->serial->dev; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) { 361507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman port->write_urb_busy = 0; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err ("%s - failed submitting write urb, error %d", __FUNCTION__, result); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s urb: %p submitted", __FUNCTION__, port->write_urb); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (count); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int safe_write_room (struct usb_serial_port *port) 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int room = 0; // Default: no room 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s", __FUNCTION__); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 376507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman if (port->write_urb_busy) 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds room = port->bulk_out_size - (safe ? 2 : 0); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (room) { 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("safe_write_room returns %d", room); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (room); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int safe_startup (struct usb_serial *serial) 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) { 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case LINEO_SAFESERIAL_CRC: 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case LINEO_SAFESERIAL_CRC_PADDED: 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds padded = 1; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 400ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver safe_device = { 40118fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 40218fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 403269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "safe_serial", 40418fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_interrupt_in = NUM_DONT_CARE, 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_in = NUM_DONT_CARE, 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_out = NUM_DONT_CARE, 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 1, 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = safe_write, 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = safe_write_room, 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_bulk_callback = safe_read_bulk_callback, 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = safe_startup, 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init safe_init (void) 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, retval; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info (DRIVER_VERSION " " DRIVER_AUTHOR); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info (DRIVER_DESC); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info ("vendor: %x product: %x safe: %d padded: %d\n", vendor, product, safe, padded); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // if we have vendor / product parameters patch them into id list 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vendor || product) { 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info ("vendor: %x product: %x\n", vendor, product); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < (sizeof (id_table) / sizeof (struct usb_device_id)); i++) { 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!id_table[i].idVendor && !id_table[i].idProduct) { 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id_table[i].idVendor = vendor; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id_table[i].idProduct = product; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&safe_device); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_serial_register; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&safe_driver); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_register; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register: 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&safe_device); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register: 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit safe_exit (void) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_deregister (&safe_driver); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister (&safe_device); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (safe_init); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (safe_exit); 459