ChangeSet 1.1005.1.8, 2003/06/27 12:02:02-07:00, abbotti@mev.co.uk [PATCH] USB: several ftdi_sio driver patches I have attached several patches for the ftdi_sio (USB serial device) driver that I have been accumulating over the last month or so as the official maintainer (Bill Ryder) has been rather quiet of late. He hasn't responded to any patches or other messages on ftdi-usb-sio-devel since the end of March. The last patch Bill sent to linux-usb-devel was for ftdi_sio version 1.3.3, which is the latest available for download from the sourceforge project page. Greg had some criticisms about whitespace, braces, etc. which was not replied to by Bill. In this sequence of patches, I have tidied some things up, accepted patches and vid/pids for extra device support and fixed a spinlock bug. The patches apply cleanly in the sequence presented here. I have split the patches by function, but have attempted to preserve the chronology where possible - there is a certain amount of time-warping going on as can be seen from the file header comments changed by the patches! The patches are as follows: 2.4.21-ftdi_sio-p01-xonxoff.patch - John Wilkins Xon/Xoff patch (included in ftdi_sio-1.3.3) 2.4.21-ftdi_sio-p02-homechoice.patch - John Wilkins vid/pid for Homechoice (included in ftdi_sio-1.3.3) 2.4.21-ftdi_sio-p03-readspeed.patch - Richard Shooter's read speed-up code (included in ftdi_sio-1.3.3), but I've tidied up the source and moved some stuff around. I've bumped the version to 1.3.3a to distinguish it from the 1.3.3 that Bill previously sent. 2.4.21-ftdi_sio-p04-spinlockbug.patch - my patch to avoid copying user data with a spinlock held (and interrupts disabled). 2.4.21-ftdi_sio-p05-sealink.patch - Adds Sealevel vid/pids - based on a patch by Tuan Hoang but with less bloat. 2.4.21-ftdi_sio-p06-usbuirt.patch - David Norwood's patch for USB-UIRT device using a preset custom divisor. 2.4.21-ftdi_sio-p07-writepooltidy.patch - my patch to take account of write urb pool table entries that failed allocation, and to free the write urb and transfer buffer allocated by the usbserial driver. 2.4.21-ftdi_sio-p08-relais.patch - support for USB Relais pid, backported from 2.5.x. 2.4.21-ftdi_sio-p09-tira1.patch - half of Erik Nygren's patch to support Home Electronics' Tira-1 IR tranceiver using a preset custom divisor. 2.4.21-ftdi_sio-p10-forcebaud.patch - the other half of Erik Nygren's patch forces the baud rate setting to B38400 for USB-UIRT and Tira-1 devices and also forces RTS/CTS on for Tira-1. 2.4.21-ftdi_sio-p11-paranoid.patch - my patch to make sure pointers that fail paranoid checks are not dereferenced. 2.4.21-ftdi_sio-p12-versionbump.patch - my patch to bump the version. This is stepping on Bill's toes a little, but I think whatever ends up in the 2.4.22 kernel should be labelled version 1.3.4. I have a 2.5.x driver version as a work in progress containing most of the above changes. I just need to finish it off a little and maybe replace the write urb pool stuff with something resembling the changes in the Visor driver. drivers/usb/serial/ftdi_sio.c | 604 ++++++++++++++++++++++++++++++++++-------- drivers/usb/serial/ftdi_sio.h | 69 ++++ 2 files changed, 568 insertions(+), 105 deletions(-) diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Fri Jun 27 16:27:10 2003 +++ b/drivers/usb/serial/ftdi_sio.c Fri Jun 27 16:27:10 2003 @@ -17,6 +17,48 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (23/Jun/2003) Ian Abbott + * Reduced flip buffer pushes and corrected a data length test in + * ftdi_read_bulk_callback. + * Defererence pointers after any paranoid checks, not before. + * + * (21/Jun/2003) Erik Nygren + * Added support for Home Electronics Tira-1 IR tranceiver using FT232BM chip. + * See . Only operates properly + * at 100000 and RTS-CTS, so set custom divisor mode on startup. + * Also force the Tira-1 and USB-UIRT to only use their custom baud rates. + * + * (18/Jun/2003) Ian Abbott + * Added Device ID of the USB relais from Rudolf Gugler (backported from + * Philipp Gühring's patch for 2.5.x kernel). + * Moved read transfer buffer reallocation into startup function. + * Free existing write urb and transfer buffer in startup function. + * Only use urbs in write urb pool that were successfully allocated. + * Moved some constant macros out of functions. + * Minor whitespace and comment changes. + * + * (12/Jun/2003) David Norwood + * Added support for USB-UIRT IR tranceiver using 8U232AM chip. + * See . Only + * operates properly at 312500, so set custom divisor mode on startup. + * + * (12/Jun/2003) Ian Abbott + * Added Sealevel SeaLINK+ 210x, 220x, 240x, 280x vid/pids from Tuan Hoang + * - I've eliminated some that don't seem to exist! + * Added Home Electronics Tira-1 IR transceiver pid from Chris Horn + * Some whitespace/coding-style cleanups + * + * (11/Jun/2003) Ian Abbott + * Fixed unsafe spinlock usage in ftdi_write + * + * (24/Feb/2003) Richard Shooter + * Increase read buffer size to improve read speeds at higher baud rates + * (specifically tested with up to 1Mb/sec at 1.5M baud) + * + * (23/Feb/2003) John Wilkins + * Added Xon/xoff flow control (activating support in the ftdi device) + * Added vid/pid for Videonetworks/Homechoice (UK ISP) + * * (23/Feb/2003) Bill Ryder * Added matrix orb device vid/pids from Wayne Wylupski * @@ -175,7 +217,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.3.2" +#define DRIVER_VERSION "v1.3.4" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" @@ -203,9 +245,11 @@ static struct usb_device_id id_table_8U232AM [] = { { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0, 0x3ff) }, @@ -213,15 +257,63 @@ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) }, { } /* Terminating entry */ }; static struct usb_device_id id_table_FT232BM [] = { { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) }, @@ -229,7 +321,64 @@ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) }, + { } /* Terminating entry */ +}; + +static struct usb_device_id id_table_USB_UIRT [] = { + { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, + { } /* Terminating entry */ +}; + + +static struct usb_device_id id_table_HE_TIRA1 [] = { + { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -237,16 +386,67 @@ static __devinitdata struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID) }, { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID) }, { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID) }, { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID) }, { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID) }, { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID) }, - { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID) }, { } /* Terminating entry */ + { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, id_table_combined); @@ -257,6 +457,9 @@ /* Don't be tempted to increase this buffer to > 64 ! I tried it and it doesn't work */ #define URB_TRANSFER_BUFFER_SIZE 64 /* the device's max packet size */ +/* Constants for read urb */ +#define BUFSZ 512 +#define PKTSZ 64 struct ftdi_private { ftdi_chip_type_t chip_type; @@ -276,6 +479,8 @@ struct urb *write_urb_pool[NUM_URBS]; spinlock_t write_urb_pool_lock; + int force_baud; /* if non-zero, force the baud rate to this value */ + int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ }; /* Used for TIOCMIWAIT */ @@ -290,6 +495,8 @@ static int ftdi_SIO_startup (struct usb_serial *serial); static int ftdi_8U232AM_startup (struct usb_serial *serial); static int ftdi_FT232BM_startup (struct usb_serial *serial); +static int ftdi_USB_UIRT_startup (struct usb_serial *serial); +static int ftdi_HE_TIRA1_startup (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial); static int ftdi_open (struct usb_serial_port *port, struct file *filp); static void ftdi_close (struct usb_serial_port *port, struct file *filp); @@ -381,6 +588,56 @@ .shutdown = ftdi_shutdown, }; +static struct usb_serial_device_type ftdi_USB_UIRT_device = { + .owner = THIS_MODULE, + .name = "USB-UIRT Infrared Receiver/Transmitter", + .id_table = id_table_USB_UIRT, + .num_interrupt_in = 0, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ftdi_open, + .close = ftdi_close, + .throttle = ftdi_throttle, + .unthrottle = ftdi_unthrottle, + .write = ftdi_write, + .write_room = ftdi_write_room, + .chars_in_buffer = ftdi_chars_in_buffer, + .read_bulk_callback = ftdi_read_bulk_callback, + .write_bulk_callback = ftdi_write_bulk_callback, + .ioctl = ftdi_ioctl, + .set_termios = ftdi_set_termios, + .break_ctl = ftdi_break_ctl, + .startup = ftdi_USB_UIRT_startup, + .shutdown = ftdi_shutdown, +}; + +/* The TIRA1 is based on a FT232BM which requires a fixed baud rate of 100000 + * and which requires RTS-CTS to be enabled. */ +static struct usb_serial_device_type ftdi_HE_TIRA1_device = { + .owner = THIS_MODULE, + .name = "Home-Electronics TIRA-1 IR Transceiver", + .id_table = id_table_HE_TIRA1, + .num_interrupt_in = 0, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ftdi_open, + .close = ftdi_close, + .throttle = ftdi_throttle, + .unthrottle = ftdi_unthrottle, + .write = ftdi_write, + .write_room = ftdi_write_room, + .chars_in_buffer = ftdi_chars_in_buffer, + .read_bulk_callback = ftdi_read_bulk_callback, + .write_bulk_callback = ftdi_write_bulk_callback, + .ioctl = ftdi_ioctl, + .set_termios = ftdi_set_termios, + .break_ctl = ftdi_break_ctl, + .startup = ftdi_HE_TIRA1_startup, + .shutdown = ftdi_shutdown, +}; + #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */ @@ -684,13 +941,14 @@ /* Called from ftdi_SIO_startup, etc. */ static int ftdi_common_startup (struct usb_serial *serial) { + struct usb_serial_port *port = &serial->port[0]; struct ftdi_private *priv; int i ; struct urb *urb; dbg("%s",__FUNCTION__); - priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); + priv = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private)); return -ENOMEM; @@ -702,17 +960,40 @@ than queue a task to deliver them */ priv->flags = ASYNC_LOW_LATENCY; - /* create our write urb pool and transfer buffers - shared across all ftdi devices */ + /* Increase the size of read buffers */ + if (port->bulk_in_buffer) { + kfree (port->bulk_in_buffer); + } + port->bulk_in_buffer = kmalloc (BUFSZ, GFP_KERNEL); + if (!port->bulk_in_buffer) { + kfree (priv); + return -ENOMEM; + } + if (port->read_urb) { + port->read_urb->transfer_buffer = port->bulk_in_buffer; + port->read_urb->transfer_buffer_length = BUFSZ; + } + + /* Free port's existing write urb and transfer buffer. */ + if (port->write_urb) { + usb_free_urb (port->write_urb); + port->write_urb = NULL; + } + if (port->bulk_out_buffer) { + kfree (port->bulk_out_buffer); + port->bulk_out_buffer = NULL; + } + + /* create our write urb pool and transfer buffers */ spin_lock_init (&priv->write_urb_pool_lock); for (i = 0; i < NUM_URBS; ++i) { urb = usb_alloc_urb(0); priv->write_urb_pool[i] = urb; if (urb == NULL) { err("Unable to create new urb in urb pool"); - continue; + break; } - urb->transfer_buffer = NULL; urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (!urb->transfer_buffer) { err("%s - out of memory for urb buffers.", @@ -721,6 +1002,13 @@ } } + /* Need at least one write urb in the pool */ + if (i == 0) { + kfree (priv); + return -ENOMEM; + } + + port->private = priv; return (0); } @@ -788,6 +1076,50 @@ return (0); } /* ftdi_FT232BM_startup */ +/* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */ +/* Called from usbserial:serial_probe */ +static int ftdi_USB_UIRT_startup (struct usb_serial *serial) +{ /* ftdi_USB_UIRT_startup */ + struct ftdi_private *priv; + int err; + + dbg("%s",__FUNCTION__); + err = ftdi_8U232AM_startup(serial); + if (err){ + return (err); + } + + priv = serial->port->private; + priv->flags |= ASYNC_SPD_CUST; + priv->custom_divisor = 77; + priv->force_baud = B38400; + + return (0); +} /* ftdi_USB_UIRT_startup */ + +/* Startup for the HE-TIRA1 device, which requires hardwired + * baudrate (38400 gets mapped to 100000) */ +static int ftdi_HE_TIRA1_startup (struct usb_serial *serial) +{ /* ftdi_HE_TIRA1_startup */ + struct ftdi_private *priv; + int err; + + dbg("%s",__FUNCTION__); + err = ftdi_FT232BM_startup(serial); + if (err){ + return (err); + } + + priv = serial->port->private; + priv->flags |= ASYNC_SPD_CUST; + priv->custom_divisor = 240; + priv->force_baud = B38400; + priv->force_rtscts = 1; + + return (0); +} /* ftdi_HE_TIRA1_startup */ + + /* ftdi_shutdown is called from usbserial:usb_serial_disconnect * it is called when the usb device is disconnected * @@ -816,19 +1148,17 @@ if (port->open_count == 0){ spin_lock_irqsave (&priv->write_urb_pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) { - if (priv->write_urb_pool[i]) { - /* FIXME - uncomment the following usb_unlink_urb call when - * the host controllers get fixed to set urb->dev = NULL after - * the urb is finished. Otherwise this call oopses. */ - /* usb_unlink_urb(priv->write_urb_pool[i]); */ - if (priv->write_urb_pool[i]->transfer_buffer) { - kfree(priv->write_urb_pool[i]->transfer_buffer); - priv->write_urb_pool[i]->transfer_buffer = NULL; - } - usb_free_urb (priv->write_urb_pool[i]); - priv->write_urb_pool[i] = NULL; + for (i = 0; i < NUM_URBS && priv->write_urb_pool[i]; ++i) { + /* FIXME - uncomment the following usb_unlink_urb call when + * the host controllers get fixed to set urb->dev = NULL after + * the urb is finished. Otherwise this call oopses. */ + /* usb_unlink_urb(priv->write_urb_pool[i]); */ + if (priv->write_urb_pool[i]->transfer_buffer) { + kfree(priv->write_urb_pool[i]->transfer_buffer); + priv->write_urb_pool[i]->transfer_buffer = NULL; } + usb_free_urb (priv->write_urb_pool[i]); + priv->write_urb_pool[i] = NULL; } spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); @@ -880,10 +1210,6 @@ err("%s Error from RTS HIGH urb", __FUNCTION__); } - /* Make sure write_urb is initialised since a write_pool is used now */ - port->write_urb = NULL; /* prevents usbserial.c from trying something silly */ - - /* Start reading from the device */ FILL_BULK_URB(port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), @@ -998,20 +1324,18 @@ spin_lock_irqsave (&(priv->write_urb_pool_lock), flags) ; - for (i = 0 ; i < NUM_URBS; i++) { + for (i = 0 ; i < NUM_URBS && priv->write_urb_pool[i]; i++) { if (priv->write_urb_pool[i] -> status != -EINPROGRESS) { - urb = priv->write_urb_pool[i]; - /* Must make sure another device doesn't grab this */ - /* BUT unfortunately the uhci stack errors if it sees this */ - /* so have to increase the size of the spin_lock */ - /* urb->status = -EINPROGRESS; */ + urb = priv->write_urb_pool[i]; + /* Must make sure another write doesn't grab this */ + urb->status = -EINPROGRESS; break; } } + spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); if (urb == NULL) { - spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); dbg("%s - no more free urbs", __FUNCTION__); goto exit; } @@ -1020,7 +1344,6 @@ if (urb->transfer_buffer == NULL) { urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (urb->transfer_buffer == NULL) { - spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); err("%s ran out of kernel memory for urb ...", __FUNCTION__); goto exit; } @@ -1036,7 +1359,6 @@ if (from_user) { if (copy_from_user(urb->transfer_buffer + data_offset, current_position, user_byte_count )){ - spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); return -EFAULT; } } else { @@ -1060,6 +1382,11 @@ ftdi_write_bulk_callback, port); urb->transfer_flags |= USB_QUEUE_BULK; + /* uhci stack errors if it status set to -EINPROGRESS on */ + /* urb submission, so clear status before submission. */ + spin_lock_irqsave (&(priv->write_urb_pool_lock), flags) ; + urb->status = 0; + result = usb_submit_urb(urb); if (result) { spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); @@ -1089,7 +1416,7 @@ static void ftdi_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + struct usb_serial *serial; dbg("%s", __FUNCTION__); @@ -1101,6 +1428,7 @@ return; } + serial = get_usb_serial (port, __FUNCTION__); if (!serial) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; @@ -1128,7 +1456,7 @@ spin_lock_irqsave (&priv->write_urb_pool_lock, flags); - for (i = 0; i < NUM_URBS; i++) { + for (i = 0; i < NUM_URBS && priv->write_urb_pool[i]; i++) { if (priv->write_urb_pool[i]->status != -EINPROGRESS) { room += URB_TRANSFER_BUFFER_SIZE - priv->write_offset; } @@ -1154,7 +1482,7 @@ spin_lock_irqsave (&priv->write_urb_pool_lock, flags); /* tally up the number of bytes waiting */ - for (i = 0; i < NUM_URBS; ++i) { + for (i = 0; i < NUM_URBS && priv->write_urb_pool[i]; i++) { if (priv->write_urb_pool[i]->status == -EINPROGRESS) { chars += URB_TRANSFER_BUFFER_SIZE - data_offset; } @@ -1173,15 +1501,22 @@ static void ftdi_read_bulk_callback (struct urb *urb) { /* ftdi_read_bulk_callback */ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = get_usb_serial(port,__FUNCTION__); - struct tty_struct *tty = port->tty ; - struct ftdi_private *priv = (struct ftdi_private *) port->private; + struct usb_serial *serial; + struct tty_struct *tty; + struct ftdi_private *priv; char error_flag; unsigned char *data = urb->transfer_buffer; - const int data_offset = 2; int i; int result; + int need_flip; + int packet_offset; + + if (urb->number_of_packets > 0) { + err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, + urb->transfer_buffer_length, urb->actual_length, urb->number_of_packets ); + err("%s transfer_flags %x USB_QUEUE_BULK %x ", __FUNCTION__,urb->transfer_flags, USB_QUEUE_BULK ); + } dbg("%s", __FUNCTION__); @@ -1191,16 +1526,19 @@ if (port->open_count <= 0) return; + serial = get_usb_serial(port,__FUNCTION__); if (!serial){ dbg("%s - bad serial pointer - exiting",__FUNCTION__); return; } + tty = port->tty; if (!tty) { dbg("%s - bad tty pointer - exiting",__FUNCTION__); return; } + priv = (struct ftdi_private *) port->private; if (urb->status) { /* This will happen at close every time so it is a dbg not an err */ @@ -1221,75 +1559,82 @@ /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */ /* if CD is dropped and the line is not CLOCAL then we should hangup */ - /* Compare new line status to the old one, signal if different */ - if (priv != NULL) { - char new_status = data[0] & FTDI_STATUS_B0_MASK; - if (new_status != priv->prev_status) { - priv->diff_status |= new_status ^ priv->prev_status; - wake_up_interruptible(&priv->delta_msr_wait); - priv->prev_status = new_status; + need_flip = 0; + for (packet_offset=0; packet_offset < urb->actual_length; packet_offset += PKTSZ) { + /* Compare new line status to the old one, signal if different */ + if (priv != NULL) { + char new_status = data[packet_offset+0] & FTDI_STATUS_B0_MASK; + if (new_status != priv->prev_status) { + priv->diff_status |= new_status ^ priv->prev_status; + wake_up_interruptible(&priv->delta_msr_wait); + priv->prev_status = new_status; + } } - } - /* Handle errors and break */ - error_flag = TTY_NORMAL; - /* Although the device uses a bitmask and hence can have multiple */ - /* errors on a packet - the order here sets the priority the */ - /* error is returned to the tty layer */ - - if ( data[1] & FTDI_RS_OE ) { - error_flag = TTY_OVERRUN; - dbg("OVERRRUN error"); - } - if ( data[1] & FTDI_RS_BI ) { - error_flag = TTY_BREAK; - dbg("BREAK received"); - } - if ( data[1] & FTDI_RS_PE ) { - error_flag = TTY_PARITY; - dbg("PARITY error"); - } - if ( data[1] & FTDI_RS_FE ) { - error_flag = TTY_FRAME; - dbg("FRAMING error"); - } - if (urb->actual_length > data_offset) { - - for (i = data_offset ; i < urb->actual_length ; ++i) { - /* have to make sure we don't overflow the buffer - with tty_insert_flip_char's */ - if(tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty_flip_buffer_push(tty); + /* Handle errors and break */ + error_flag = TTY_NORMAL; + /* Although the device uses a bitmask and hence can have multiple */ + /* errors on a packet - the order here sets the priority the */ + /* error is returned to the tty layer */ + + if ( data[packet_offset+1] & FTDI_RS_OE ) { + error_flag = TTY_OVERRUN; + dbg("OVERRRUN error"); + } + if ( data[packet_offset+1] & FTDI_RS_BI ) { + error_flag = TTY_BREAK; + dbg("BREAK received"); + } + if ( data[packet_offset+1] & FTDI_RS_PE ) { + error_flag = TTY_PARITY; + dbg("PARITY error"); + } + if ( data[packet_offset+1] & FTDI_RS_FE ) { + error_flag = TTY_FRAME; + dbg("FRAMING error"); + } + if (urb->actual_length > packet_offset + 2) { + for (i = 2; (i < PKTSZ) && ((i+packet_offset) < urb->actual_length); ++i) { + /* have to make sure we don't overflow the buffer + with tty_insert_flip_char's */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* Note that the error flag is duplicated for + every character received since we don't know + which character it applied to */ + tty_insert_flip_char(tty, data[packet_offset+i], error_flag); } - /* Note that the error flag is duplicated for - every character received since we don't know - which character it applied to */ - tty_insert_flip_char(tty, data[i], error_flag); + need_flip = 1; } - tty_flip_buffer_push(tty); - } #ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW - /* if a parity error is detected you get status packets forever - until a character is sent without a parity error. - This doesn't work well since the application receives a never - ending stream of bad data - even though new data hasn't been sent. - Therefore I (bill) have taken this out. - However - this might make sense for framing errors and so on - so I am leaving the code in for now. - */ - else { - if (error_flag != TTY_NORMAL){ - dbg("error_flag is not normal"); + /* if a parity error is detected you get status packets forever + until a character is sent without a parity error. + This doesn't work well since the application receives a never + ending stream of bad data - even though new data hasn't been sent. + Therefore I (bill) have taken this out. + However - this might make sense for framing errors and so on + so I am leaving the code in for now. + */ + else { + if (error_flag != TTY_NORMAL){ + dbg("error_flag is not normal"); /* In this case it is just status - if that is an error send a bad character */ if(tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } tty_insert_flip_char(tty, 0xff, error_flag); - tty_flip_buffer_push(tty); + need_flip = 1; + } } - } #endif + } /* "for(packet_offset=0..." */ + + /* Low latency */ + if (need_flip) { + tty_flip_buffer_push(tty); + } /* if the port is closed stop trying to read */ if (port->open_count > 0){ @@ -1347,14 +1692,32 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios) { /* ftdi_termios */ struct usb_serial *serial = port->serial; - unsigned int cflag = port->tty->termios->c_cflag; + unsigned int cflag; struct ftdi_private *priv = (struct ftdi_private *)port->private; __u16 urb_value; /* will hold the new flags */ char buf[1]; /* Perhaps I should dynamically alloc this? */ + // Added for xon/xoff support + unsigned int iflag = port->tty->termios->c_iflag; + unsigned char vstop; + unsigned char vstart; dbg("%s", __FUNCTION__); + /* Force baud rate if this device requires it, unless it is set to B0. */ + if (priv->force_baud && ((port->tty->termios->c_cflag & CBAUD) != B0)) { + dbg("%s: forcing baud rate for this device", __FUNCTION__); + port->tty->termios->c_cflag &= ~CBAUD; + port->tty->termios->c_cflag |= priv->force_baud; + } + + /* Force RTS-CTS if this device requires it. */ + if (priv->force_rtscts) { + dbg("%s: forcing rtscts for this device", __FUNCTION__); + port->tty->termios->c_cflag |= CRTSCTS; + } + + cflag = port->tty->termios->c_cflag; /* FIXME -For this cut I don't care if the line is really changing or not - so just do the change regardless - should be able to @@ -1434,16 +1797,43 @@ } } else { - /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ - dbg("%s Turning off hardware flow control", __FUNCTION__); - if (usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("urb failed to clear flow control"); - } + /* + * Xon/Xoff code + * + * Check the IXOFF status in the iflag component of the termios structure + * if IXOFF is not set, the pre-xon/xoff code is executed. + */ + if (iflag & IXOFF) { + dbg("%s request to enable xonxoff iflag=%04x",__FUNCTION__,iflag); + // Try to enable the XON/XOFF on the ftdi_sio + // Set the vstart and vstop -- could have been done up above where + // a lot of other dereferencing is done but that would be very + // inefficient as vstart and vstop are not always needed + vstart=port->tty->termios->c_cc[VSTART]; + vstop=port->tty->termios->c_cc[VSTOP]; + urb_value=(vstop << 8) | (vstart); + + if (usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + urb_value , FTDI_SIO_XON_XOFF_HS, + buf, 0, WDR_TIMEOUT) < 0) { + err("urb failed to set to xon/xoff flow control"); + } + } else { + /* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */ + /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ + dbg("%s Turning off hardware flow control", __FUNCTION__); + if (usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, 0, + buf, 0, WDR_TIMEOUT) < 0) { + err("urb failed to clear flow control"); + } + } } return; @@ -1665,6 +2055,8 @@ usb_serial_register (&ftdi_SIO_device); usb_serial_register (&ftdi_8U232AM_device); usb_serial_register (&ftdi_FT232BM_device); + usb_serial_register (&ftdi_USB_UIRT_device); + usb_serial_register (&ftdi_HE_TIRA1_device); info(DRIVER_VERSION ":" DRIVER_DESC); @@ -1677,6 +2069,8 @@ dbg("%s", __FUNCTION__); + usb_serial_deregister (&ftdi_HE_TIRA1_device); + usb_serial_deregister (&ftdi_USB_UIRT_device); usb_serial_deregister (&ftdi_FT232BM_device); usb_serial_deregister (&ftdi_8U232AM_device); usb_serial_deregister (&ftdi_SIO_device); diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h Fri Jun 27 16:27:10 2003 +++ b/drivers/usb/serial/ftdi_sio.h Fri Jun 27 16:27:10 2003 @@ -17,11 +17,15 @@ * Bill Ryder - bryder@sgi.com formerly of Silicon Graphics, Inc.- wrote the * FTDI_SIO implementation. * + * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais + * from Rudolf Gugler + * */ #define FTDI_VID 0x0403 /* Vendor Id */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ +#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ @@ -31,6 +35,10 @@ #define FTDI_XF_634_PID 0xFC09 /* Four line device */ #define FTDI_XF_632_PID 0xFC08 /* Two line device */ +/* Video Networks Limited / Homechoice in the UK use an ftdi-based device for their 1Mb */ +/* broadband internet service. The following PID is exhibited by the usb device supplied */ +/* (the VID is the standard ftdi vid (FTDI_VID) */ +#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */ /* * The following are the values for the Matrix Orbital LCD displays, @@ -45,6 +53,67 @@ #define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ #define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ +/* + * The following are the values for the Sealevel SeaLINK+ adapters. + * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and + * removed some PIDs that don't seem to match any existing products.) + */ +#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */ +#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */ +#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */ +#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */ +#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */ +#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */ +#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */ +#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */ +#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */ +#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */ +#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */ +#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */ +#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */ +#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */ +#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */ +#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */ +#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */ +#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */ +#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */ +#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */ +#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */ +#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */ +#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */ +#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */ +#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */ +#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */ +#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */ +#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */ +#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */ +#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */ +#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */ +#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */ +#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */ +#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */ +#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */ +#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */ +#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */ +#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */ +#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */ +#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */ +#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */ +#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */ +#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */ +#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */ +#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ +#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ +#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ + +/* + * Home Electronics (www.home-electro.com) USB gadgets + */ +#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR tranceiver */ + +/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */ +/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */ +#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */