]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/usb/serial/ftdi_sio.c
USB: replace remaining __FUNCTION__ occurrences
[linux-2.6.git] / drivers / usb / serial / ftdi_sio.c
index a20da8528a5f8b1826134b55be9ffdf00102d1b3..8b531b377dcb54d9e80aa76aecef8e0e93f1749d 100644 (file)
 /*
  * USB FTDI SIO driver
  *
- *     Copyright (C) 1999 - 2001
- *         Greg Kroah-Hartman (greg@kroah.com)
+ *     Copyright (C) 1999 - 2001
+ *         Greg Kroah-Hartman (greg@kroah.com)
  *          Bill Ryder (bryder@sgi.com)
  *     Copyright (C) 2002
  *         Kuba Ober (kuba@mareimbrium.org)
  *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *     and extra documentation
  *
- * (21/Jul/2004) Ian Abbott
- *      Incorporated Steven Turner's code to add support for the FT2232C chip.
- *      The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff.  I have
- *      fixed a couple of things.
- *
- * (27/May/2004) Ian Abbott
- *      Improved throttling code, mostly stolen from the WhiteHEAT driver.
- *
- * (26/Mar/2004) Jan Capek
- *      Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc.
- *
- * (09/Feb/2004) Ian Abbott
- *      Changed full name of USB-UIRT device to avoid "/" character.
- *      Added FTDI's alternate PID (0x6006) for FT232/245 devices.
- *      Added PID for "ELV USB Module UO100" from Stefan Frings.
- * 
- * (21/Oct/2003) Ian Abbott
- *      Renamed some VID/PID macros for Matrix Orbital and Perle Systems
- *      devices.  Removed Matrix Orbital and Perle Systems devices from the
- *      8U232AM device table, but left them in the FT232BM table, as they are
- *      known to use only FT232BM.
- *
- * (17/Oct/2003) Scott Allen
- *      Added vid/pid for Perle Systems UltraPort USB serial converters
- *
- * (21/Sep/2003) Ian Abbott
- *      Added VID/PID for Omnidirectional Control Technology US101 USB to
- *      RS-232 adapter (also rebadged as Dick Smith Electronics XH6381).
- *      VID/PID supplied by Donald Gordon.
- *
- * (19/Aug/2003) Ian Abbott
- *      Freed urb's transfer buffer in write bulk callback.
- *      Omitted some paranoid checks in write bulk callback that don't matter.
- *      Scheduled work in write bulk callback regardless of port's open count.
- *
- * (05/Aug/2003) Ian Abbott
- *      Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter.
- *      VID/PID provided by Steve Briggs.
- *
- * (23/Jul/2003) Ian Abbott
- *      Added PIDs for CrystalFontz 547, 633, 631, 635, 640 and 640 from
- *      Wayne Wylupski.
- *
- * (10/Jul/2003) David Glance
- *      Added PID for DSS-20 SyncStation cradle for Sony-Ericsson P800.
- *
- * (27/Jun/2003) Ian Abbott
- *     Reworked the urb handling logic.  We have no more pool, but dynamically
- *     allocate the urb and the transfer buffer on the fly.  In testing this
- *     does not incure any measurable overhead.  This also relies on the fact
- *     that we have proper reference counting logic for urbs.  I nicked this
- *     from Greg KH's Visor driver.
- *      
- * (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 transceiver using FT232BM chip.
- *      See <http://www.home-electro.com/tira1.htm>.  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 transceiver using 8U232AM chip.
- *      See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>.  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
- *
- * (19/Feb/2003) Ian Abbott
- *      For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has
- *      changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI,
- *      ASYNC_SPD_SHI or ASYNC_SPD_WARP.  Also, unless ASYNC_SPD_CUST is in
- *      force, don't bother changing baud rate when custom_divisor has changed.
- *
- * (18/Feb/2003) Ian Abbott
- *      Fixed TIOCMGET handling to include state of DTR and RTS, the state
- *      of which are now saved by set_dtr() and set_rts().
- *      Fixed improper storage class for buf in set_dtr() and set_rts().
- *      Added FT232BM chip type and support for its extra baud rates (compared
- *      to FT8U232AM).
- *      Took account of special case divisor values for highest baud rates of
- *      FT8U232AM and FT232BM.
- *      For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used,
- *      as previous alt_speed setting is now stale.
- *      Moved startup code common between the startup routines for the
- *      different chip types into a common subroutine.
- *
- * (17/Feb/2003) Bill Ryder
- *      Added write urb buffer pool on a per device basis
- *      Added more checking for open file on callbacks (fixed OOPS)
- *      Added CrystalFontz 632 and 634 PIDs 
- *         (thanx to CrystalFontz for the sample devices - they flushed out
- *           some driver bugs)
- *      Minor debugging message changes
- *      Added throttle, unthrottle and chars_in_buffer functions
- *      Fixed FTDI_SIO (the original device) bug
- *      Fixed some shutdown handling
- *      
- * 
- * 
- * 
- * (07/Jun/2002) Kuba Ober
- *     Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
- *     function. It was getting too complex.
- *     Fix the divisor calculation logic which was setting divisor of 0.125
- *     instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
- *     Also make it bump up the divisor to next integer in case of 7/8 - it's
- *     a better approximation.
- *
- * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
- *      Not tested by me but it doesn't break anything I use.
- * 
- * (04/Jan/2002) Kuba Ober
- *     Implemented 38400 baudrate kludge, where it can be substituted with other
- *       values. That's the only way to set custom baudrates.
- *     Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy.
- *     FIXME: both baudrate things should eventually go to usbserial.c as other
- *       devices may need that functionality too. Actually, it can probably be
- *       merged in serial.c somehow - too many drivers repeat this code over
- *       and over.
- *     Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time.
- *     Divisors for baudrates are calculated by a macro.
- *     Small code cleanups. Ugly whitespace changes for Plato's sake only ;-].
- *
- * (04/Nov/2001) Bill Ryder
- *     Fixed bug in read_bulk_callback where incorrect urb buffer was used.
- *     Cleaned up write offset calculation
- *     Added write_room since default values can be incorrect for sio
- *     Changed write_bulk_callback to use same queue_task as other drivers
- *        (the previous version caused panics)
- *     Removed port iteration code since the device only has one I/O port and it
- *       was wrong anyway.
- * 
- * (31/May/2001) gkh
- *     Switched from using spinlock to a semaphore, which fixes lots of problems.
- *
- * (23/May/2001)   Bill Ryder
- *     Added runtime debug patch (thanx Tyson D Sawyer).
- *     Cleaned up comments for 8U232
- *     Added parity, framing and overrun error handling
- *     Added receive break handling.
- * 
- * (04/08/2001) gb
- *     Identify version on module load.
- *       
- * (18/March/2001) Bill Ryder
- *     (Not released)
- *     Added send break handling. (requires kernel patch too)
- *     Fixed 8U232AM hardware RTS/CTS etc status reporting.
- *     Added flipbuf fix copied from generic device
- * 
- * (12/3/2000) Bill Ryder
- *     Added support for 8U232AM device.
- *     Moved PID and VIDs into header file only.
- *     Turned on low-latency for the tty (device will do high baudrates)
- *     Added shutdown routine to close files when device removed.
- *     More debug and error message cleanups.
- *
- * (11/13/2000) Bill Ryder
- *     Added spinlock protected open code and close code.
- *     Multiple opens work (sort of - see webpage mentioned above).
- *     Cleaned up comments. Removed multiple PID/VID definitions.
- *     Factorised cts/dtr code
- *     Made use of __FUNCTION__ in dbg's
- *      
- * (11/01/2000) Adam J. Richter
- *     usb_device_id table support
- * 
- * (10/05/2000) gkh
- *     Fixed bug with urb->dev not being set properly, now that the usb
- *     core needs it.
- * 
- * (09/11/2000) gkh
- *     Removed DEBUG #ifdefs with call to usb_serial_debug_data
- *
- * (07/19/2000) gkh
- *     Added module_init and module_exit functions to handle the fact that this
- *     driver is a loadable module now.
- *
- * (04/04/2000) Bill Ryder 
- *     Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
- *        handled elsewhere in the tty io driver chain).
- *
- * (03/30/2000) Bill Ryder 
- *     Implemented lots of ioctls
- *     Fixed a race condition in write
- *     Changed some dbg's to errs
- *
- * (03/26/2000) gkh
- *     Split driver up into device specific pieces.
+ * Change entries from 2004 and earlier can be found in versions of this
+ * file in kernel versions prior to the 2.6.24 release.
  *
  */
 
@@ -271,20 +53,63 @@ static int debug;
 static __u16 vendor = FTDI_VID;
 static __u16 product;
 
+struct ftdi_private {
+       ftdi_chip_type_t chip_type;
+                               /* type of the device, either SIO or FT8U232AM */
+       int baud_base;          /* baud base clock for divisor setting */
+       int custom_divisor;     /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
+       __u16 last_set_data_urb_value ;
+                               /* the last data state set - needed for doing a break */
+        int write_offset;       /* This is the offset in the usb data block to write the serial data -
+                                * it is different between devices
+                                */
+       int flags;              /* some ASYNC_xxxx flags are supported */
+       unsigned long last_dtr_rts;     /* saved modem control outputs */
+        wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+       char prev_status, diff_status;        /* Used for TIOCMIWAIT */
+       __u8 rx_flags;          /* receive state flags (throttling) */
+       spinlock_t rx_lock;     /* spinlock for receive state */
+       struct delayed_work rx_work;
+       struct usb_serial_port *port;
+       int rx_processed;
+       unsigned long rx_bytes;
+
+       __u16 interface;        /* FT2232C port interface (0 for FT232/245) */
+
+       speed_t 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 */
+
+       spinlock_t tx_lock;     /* spinlock for transmit state */
+       unsigned long tx_bytes;
+       unsigned long tx_outstanding_bytes;
+       unsigned long tx_outstanding_urbs;
+};
+
 /* struct ftdi_sio_quirk is used by devices requiring special attention. */
 struct ftdi_sio_quirk {
-       void (*setup)(struct usb_serial *); /* Special settings during startup. */
+       int (*probe)(struct usb_serial *);
+       void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */
 };
 
-static void  ftdi_USB_UIRT_setup       (struct usb_serial *serial);
-static void  ftdi_HE_TIRA1_setup       (struct usb_serial *serial);
+static int   ftdi_jtag_probe           (struct usb_serial *serial);
+static int   ftdi_mtxorb_hack_setup    (struct usb_serial *serial);
+static void  ftdi_USB_UIRT_setup       (struct ftdi_private *priv);
+static void  ftdi_HE_TIRA1_setup       (struct ftdi_private *priv);
+
+static struct ftdi_sio_quirk ftdi_jtag_quirk = {
+       .probe  = ftdi_jtag_probe,
+};
+
+static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = {
+       .probe  = ftdi_mtxorb_hack_setup,
+};
 
 static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
-       .setup = ftdi_USB_UIRT_setup,
+       .port_probe = ftdi_USB_UIRT_setup,
 };
 
 static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
-       .setup = ftdi_HE_TIRA1_setup,
+       .port_probe = ftdi_HE_TIRA1_setup,
 };
 
 /*
@@ -306,15 +131,21 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
 
 
 static struct usb_device_id id_table_combined [] = {
+       { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) },
        { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
        { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
        { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
@@ -335,13 +166,17 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
+       { USB_DEVICE(MTXORB_VK_VID, MTXORB_VK_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
        { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_USBX_707_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_2106_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) },
@@ -416,50 +251,58 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
        /*
-        * These will probably use user-space drivers.  Uncomment them if
-        * you need them or use the user-specified vendor/product module
-        * parameters (see ftdi_sio.h for the numbers).  Make a fuss if
-        * you think the driver should recognize any of them by default.
+        * Due to many user requests for multiple ELV devices we enable
+        * them by default.
         */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
-       { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
-       { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
-       { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
-       { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
-       { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
-       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
-       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) },
        { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
        { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
        { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
        { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
        { USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
+       { USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
        { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
-       { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -483,11 +326,14 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) },
        { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
+       { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) },
+       { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
        { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
        { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
        { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
@@ -504,6 +350,22 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
        { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
+       { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
+       { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
+       { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
+       { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -515,7 +377,7 @@ static struct usb_driver ftdi_driver = {
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table_combined,
-       .no_dynamic_id =        1,
+       .no_dynamic_id =        1,
 };
 
 static const char *ftdi_chip_name[] = {
@@ -523,6 +385,7 @@ static const char *ftdi_chip_name[] = {
        [FT8U232AM] = "FT8U232AM",
        [FT232BM] = "FT232BM",
        [FT2232C] = "FT2232C",
+       [FT232RL] = "FT232RL",
 };
 
 
@@ -534,58 +397,28 @@ static const char *ftdi_chip_name[] = {
 #define THROTTLED              0x01
 #define ACTUALLY_THROTTLED     0x02
 
-struct ftdi_private {
-       ftdi_chip_type_t chip_type;
-                               /* type of the device, either SIO or FT8U232AM */
-       int baud_base;          /* baud base clock for divisor setting */
-       int custom_divisor;     /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
-       __u16 last_set_data_urb_value ;
-                               /* the last data state set - needed for doing a break */
-        int write_offset;       /* This is the offset in the usb data block to write the serial data - 
-                                * it is different between devices
-                                */
-       int flags;              /* some ASYNC_xxxx flags are supported */
-       unsigned long last_dtr_rts;     /* saved modem control outputs */
-        wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
-       char prev_status, diff_status;        /* Used for TIOCMIWAIT */
-       __u8 rx_flags;          /* receive state flags (throttling) */
-       spinlock_t rx_lock;     /* spinlock for receive state */
-       struct work_struct rx_work;
-       int rx_processed;
-       unsigned long rx_bytes;
-
-       __u16 interface;        /* FT2232C port interface (0 for FT232/245) */
-
-       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 */
-
-       spinlock_t tx_lock;     /* spinlock for transmit state */
-       unsigned long tx_bytes;
-       unsigned long tx_outstanding_bytes;
-       unsigned long tx_outstanding_urbs;
-};
-
 /* Used for TIOCMIWAIT */
 #define FTDI_STATUS_B0_MASK    (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
 #define FTDI_STATUS_B1_MASK    (FTDI_RS_BI)
 /* End TIOCMIWAIT */
 
-#define FTDI_IMPL_ASYNC_FLAGS = ( ASYNC_SPD_HI | ASYNC_SPD_VHI \
ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP )
+#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \
| ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP)
 
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_probe     (struct usb_serial *serial, const struct usb_device_id *id);
-static int  ftdi_sio_attach            (struct usb_serial *serial);
 static void ftdi_shutdown              (struct usb_serial *serial);
+static int  ftdi_sio_port_probe        (struct usb_serial_port *port);
+static int  ftdi_sio_port_remove       (struct usb_serial_port *port);
 static int  ftdi_open                  (struct usb_serial_port *port, struct file *filp);
 static void ftdi_close                 (struct usb_serial_port *port, struct file *filp);
 static int  ftdi_write                 (struct usb_serial_port *port, const unsigned char *buf, int count);
 static int  ftdi_write_room            (struct usb_serial_port *port);
 static int  ftdi_chars_in_buffer       (struct usb_serial_port *port);
-static void ftdi_write_bulk_callback   (struct urb *urb, struct pt_regs *regs);
-static void ftdi_read_bulk_callback    (struct urb *urb, struct pt_regs *regs);
-static void ftdi_process_read          (void *param);
-static void ftdi_set_termios           (struct usb_serial_port *port, struct termios * old);
+static void ftdi_write_bulk_callback   (struct urb *urb);
+static void ftdi_read_bulk_callback    (struct urb *urb);
+static void ftdi_process_read          (struct work_struct *work);
+static void ftdi_set_termios           (struct usb_serial_port *port, struct ktermios * old);
 static int  ftdi_tiocmget               (struct usb_serial_port *port, struct file *file);
 static int  ftdi_tiocmset              (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear);
 static int  ftdi_ioctl                 (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
@@ -604,12 +437,12 @@ static struct usb_serial_driver ftdi_sio_device = {
                .name =         "ftdi_sio",
        },
        .description =          "FTDI USB Serial Device",
+       .usb_driver =           &ftdi_driver ,
        .id_table =             id_table_combined,
-       .num_interrupt_in =     0,
-       .num_bulk_in =          1,
-       .num_bulk_out =         1,
        .num_ports =            1,
        .probe =                ftdi_sio_probe,
+       .port_probe =           ftdi_sio_port_probe,
+       .port_remove =          ftdi_sio_port_remove,
        .open =                 ftdi_open,
        .close =                ftdi_close,
        .throttle =             ftdi_throttle,
@@ -624,7 +457,6 @@ static struct usb_serial_driver ftdi_sio_device = {
        .ioctl =                ftdi_ioctl,
        .set_termios =          ftdi_set_termios,
        .break_ctl =            ftdi_break_ctl,
-       .attach =               ftdi_sio_attach,
        .shutdown =             ftdi_shutdown,
 };
 
@@ -641,7 +473,7 @@ static struct usb_serial_driver ftdi_sio_device = {
 
 /*
  * ***************************************************************************
- * Utlity functions
+ * Utility functions
  * ***************************************************************************
  */
 
@@ -693,14 +525,13 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
        int rv;
 
        if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
-               dbg("%s - DTR|RTS not being set|cleared", __FUNCTION__);
+               dbg("%s - DTR|RTS not being set|cleared", __func__);
                return 0;       /* no change */
        }
 
        buf = kmalloc(1, GFP_NOIO);
-       if (!buf) {
+       if (!buf)
                return -ENOMEM;
-       }
 
        clear &= ~set;  /* 'set' takes precedence over 'clear' */
        urb_value = 0;
@@ -714,7 +545,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
                urb_value |= FTDI_SIO_SET_RTS_HIGH;
        rv = usb_control_msg(port->serial->dev,
                               usb_sndctrlpipe(port->serial->dev, 0),
-                              FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+                              FTDI_SIO_SET_MODEM_CTRL_REQUEST,
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
                               urb_value, priv->interface,
                               buf, 0, WDR_TIMEOUT);
@@ -722,17 +553,18 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
        kfree(buf);
        if (rv < 0) {
                err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
-                               __FUNCTION__,
+                               __func__,
                                (set & TIOCM_DTR) ? "HIGH" :
                                (clear & TIOCM_DTR) ? "LOW" : "unchanged",
                                (set & TIOCM_RTS) ? "HIGH" :
                                (clear & TIOCM_RTS) ? "LOW" : "unchanged");
        } else {
-               dbg("%s - DTR %s, RTS %s", __FUNCTION__,
+               dbg("%s - DTR %s, RTS %s", __func__,
                                (set & TIOCM_DTR) ? "HIGH" :
                                (clear & TIOCM_DTR) ? "LOW" : "unchanged",
                                (set & TIOCM_RTS) ? "HIGH" :
                                (clear & TIOCM_RTS) ? "LOW" : "unchanged");
+               /* FIXME: locking on last_dtr_rts */
                priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set;
        }
        return rv;
@@ -761,7 +593,7 @@ static int change_speed(struct usb_serial_port *port)
        if (priv->interface) {  /* FT2232C */
                urb_index = (__u16)((urb_index << 8) | priv->interface);
        }
-       
+
        rv = usb_control_msg(port->serial->dev,
                            usb_sndctrlpipe(port->serial->dev, 0),
                            FTDI_SIO_SET_BAUDRATE_REQUEST,
@@ -807,7 +639,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
        /* 1. Get the baud rate from the tty settings, this observes alt_speed hack */
 
        baud = tty_get_baud_rate(port->tty);
-       dbg("%s - tty_get_baud_rate reports speed %d", __FUNCTION__, baud);
+       dbg("%s - tty_get_baud_rate reports speed %d", __func__, baud);
 
        /* 2. Observe async-compatible custom_divisor hack, update baudrate if needed */
 
@@ -815,12 +647,12 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
            ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
             (priv->custom_divisor)) {
                baud = priv->baud_base / priv->custom_divisor;
-               dbg("%s - custom divisor %d sets baud rate to %d", __FUNCTION__, priv->custom_divisor, baud);
+               dbg("%s - custom divisor %d sets baud rate to %d", __func__, priv->custom_divisor, baud);
        }
 
        /* 3. Convert baudrate to device-specific divisor */
 
-       if (!baud) baud = 9600; 
+       if (!baud) baud = 9600;
        switch(priv->chip_type) {
        case SIO: /* SIO chip */
                switch(baud) {
@@ -836,8 +668,9 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
                case 115200: div_value = ftdi_sio_b115200; break;
                } /* baud */
                if (div_value == 0) {
-                       dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__,  baud);
+                       dbg("%s - Baudrate (%d) requested is not supported", __func__,  baud);
                        div_value = ftdi_sio_b9600;
+                       baud = 9600;
                        div_okay = 0;
                }
                break;
@@ -845,29 +678,33 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
                if (baud <= 3000000) {
                        div_value = ftdi_232am_baud_to_divisor(baud);
                } else {
-                       dbg("%s - Baud rate too high!", __FUNCTION__);
+                       dbg("%s - Baud rate too high!", __func__);
+                       baud = 9600;
                        div_value = ftdi_232am_baud_to_divisor(9600);
                        div_okay = 0;
                }
                break;
        case FT232BM: /* FT232BM chip */
        case FT2232C: /* FT2232C chip */
+       case FT232RL:
                if (baud <= 3000000) {
                        div_value = ftdi_232bm_baud_to_divisor(baud);
                } else {
-                       dbg("%s - Baud rate too high!", __FUNCTION__);
+                       dbg("%s - Baud rate too high!", __func__);
                        div_value = ftdi_232bm_baud_to_divisor(9600);
                        div_okay = 0;
+                       baud = 9600;
                }
                break;
        } /* priv->chip_type */
 
        if (div_okay) {
                dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s",
-                       __FUNCTION__, baud, (unsigned long)div_value,
+                       __func__, baud, (unsigned long)div_value,
                        ftdi_chip_name[priv->chip_type]);
        }
 
+       tty_encode_baud_rate(port->tty, baud, baud);
        return(div_value);
 }
 
@@ -918,7 +755,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _
        /* Make the changes - these are privileged changes! */
 
        priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
-                      (new_serial.flags & ASYNC_FLAGS));       
+                      (new_serial.flags & ASYNC_FLAGS));
        priv->custom_divisor = new_serial.custom_divisor;
 
        port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
@@ -943,7 +780,7 @@ check_and_exit:
             (old_priv.custom_divisor != priv->custom_divisor))) {
                change_speed(port);
        }
-       
+
        return (0);
 
 } /* set_serial_info */
@@ -964,7 +801,7 @@ static void ftdi_determine_type(struct usb_serial_port *port)
 
        version = le16_to_cpu(udev->descriptor.bcdDevice);
        interfaces = udev->actconfig->desc.bNumInterfaces;
-       dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __FUNCTION__,
+       dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __func__,
                        version, interfaces);
        if (interfaces > 1) {
                int inter;
@@ -982,7 +819,7 @@ static void ftdi_determine_type(struct usb_serial_port *port)
                 * to 0x200 when iSerialNumber is 0.  */
                if (version < 0x500) {
                        dbg("%s: something fishy - bcdDevice too low for multi-interface device",
-                                       __FUNCTION__);
+                                       __func__);
                }
        } else if (version < 0x200) {
                /* Old device.  Assume its the original SIO. */
@@ -994,9 +831,12 @@ static void ftdi_determine_type(struct usb_serial_port *port)
                /* (It might be a BM because of the iSerialNumber bug,
                 * but it will still work as an AM device.) */
                priv->chip_type = FT8U232AM;
-       } else {
+       } else if (version < 0x600) {
                /* Assume its an FT232BM (or FT245BM) */
                priv->chip_type = FT232BM;
+       } else {
+               /* Assume its an FT232R  */
+               priv->chip_type = FT232RL;
        }
        info("Detected %s", ftdi_chip_name[priv->chip_type]);
 }
@@ -1012,23 +852,22 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev;
+       struct usb_device *udev = port->serial->dev;
        unsigned short latency = 0;
        int rv = 0;
-       
-       udev = to_usb_device(dev);
-       
-       dbg("%s",__FUNCTION__);
-       
+
+
+       dbg("%s",__func__);
+
        rv = usb_control_msg(udev,
                             usb_rcvctrlpipe(udev, 0),
                             FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
                             FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
-                            0, priv->interface, 
+                            0, priv->interface,
                             (char*) &latency, 1, WDR_TIMEOUT);
-       
+
        if (rv < 0) {
-               dev_err(dev, "Unable to read latency timer: %i", rv);
+               dev_err(dev, "Unable to read latency timer: %i\n", rv);
                return -EIO;
        }
        return sprintf(buf, "%i\n", latency);
@@ -1040,27 +879,25 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev;
+       struct usb_device *udev = port->serial->dev;
        char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
-       
-       udev = to_usb_device(dev);
-       
-       dbg("%s: setting latency timer = %i", __FUNCTION__, v);
-       
+
+       dbg("%s: setting latency timer = %i", __func__, v);
+
        rv = usb_control_msg(udev,
                             usb_sndctrlpipe(udev, 0),
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
-                            v, priv->interface, 
+                            v, priv->interface,
                             buf, 0, WDR_TIMEOUT);
-       
+
        if (rv < 0) {
-               dev_err(dev, "Unable to write latency timer: %i", rv);
+               dev_err(dev, "Unable to write latency timer: %i\n", rv);
                return -EIO;
        }
-       
+
        return count;
 }
 
@@ -1071,72 +908,70 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev;
+       struct usb_device *udev = port->serial->dev;
        char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
-       
-       udev = to_usb_device(dev);
-       
-       dbg("%s: setting event char = %i", __FUNCTION__, v);
-       
+
+       dbg("%s: setting event char = %i", __func__, v);
+
        rv = usb_control_msg(udev,
                             usb_sndctrlpipe(udev, 0),
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST,
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
-                            v, priv->interface, 
+                            v, priv->interface,
                             buf, 0, WDR_TIMEOUT);
-       
+
        if (rv < 0) {
                dbg("Unable to write event character: %i", rv);
                return -EIO;
        }
-       
+
        return count;
 }
 
 static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, store_latency_timer);
 static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
 
-static void create_sysfs_attrs(struct usb_serial *serial)
-{      
-       struct ftdi_private *priv;
-       struct usb_device *udev;
+static int create_sysfs_attrs(struct usb_serial_port *port)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       int retval = 0;
+
+       dbg("%s",__func__);
 
-       dbg("%s",__FUNCTION__);
-       
-       priv = usb_get_serial_port_data(serial->port[0]);
-       udev = serial->dev;
-       
        /* XXX I've no idea if the original SIO supports the event_char
         * sysfs parameter, so I'm playing it safe.  */
        if (priv->chip_type != SIO) {
                dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
-               device_create_file(&udev->dev, &dev_attr_event_char);
-               if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
-                       device_create_file(&udev->dev, &dev_attr_latency_timer);
+               retval = device_create_file(&port->dev, &dev_attr_event_char);
+               if ((!retval) &&
+                   (priv->chip_type == FT232BM ||
+                    priv->chip_type == FT2232C ||
+                    priv->chip_type == FT232RL)) {
+                       retval = device_create_file(&port->dev,
+                                                   &dev_attr_latency_timer);
                }
        }
+       return retval;
 }
 
-static void remove_sysfs_attrs(struct usb_serial *serial)
+static void remove_sysfs_attrs(struct usb_serial_port *port)
 {
-       struct ftdi_private *priv;
-       struct usb_device *udev;
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-       dbg("%s",__FUNCTION__); 
+       dbg("%s",__func__);
 
-       priv = usb_get_serial_port_data(serial->port[0]);
-       udev = serial->dev;
-       
        /* XXX see create_sysfs_attrs */
        if (priv->chip_type != SIO) {
-               device_remove_file(&udev->dev, &dev_attr_event_char);
-               if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
-                       device_remove_file(&udev->dev, &dev_attr_latency_timer);
+               device_remove_file(&port->dev, &dev_attr_event_char);
+               if (priv->chip_type == FT232BM ||
+                   priv->chip_type == FT2232C ||
+                   priv->chip_type == FT232RL) {
+                       device_remove_file(&port->dev, &dev_attr_latency_timer);
                }
        }
-       
+
 }
 
 /*
@@ -1148,23 +983,30 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
 /* Probe function to check for special devices */
 static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id)
 {
+       struct ftdi_sio_quirk *quirk = (struct ftdi_sio_quirk *)id->driver_info;
+
+       if (quirk && quirk->probe) {
+               int ret = quirk->probe(serial);
+               if (ret != 0)
+                       return ret;
+       }
+
        usb_set_serial_data(serial, (void *)id->driver_info);
 
-       return (0);
+       return 0;
 }
 
-/* attach subroutine */
-static int ftdi_sio_attach (struct usb_serial *serial)
+static int ftdi_sio_port_probe(struct usb_serial_port *port)
 {
-       struct usb_serial_port *port = serial->port[0];
        struct ftdi_private *priv;
-       struct ftdi_sio_quirk *quirk;
-       
-       dbg("%s",__FUNCTION__);
+       struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
+
+
+       dbg("%s",__func__);
 
        priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
        if (!priv){
-               err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
+               err("%s- kmalloc(%Zd) failed.", __func__, sizeof(struct ftdi_private));
                return -ENOMEM;
        }
 
@@ -1175,6 +1017,9 @@ static int ftdi_sio_attach (struct usb_serial *serial)
           than queue a task to deliver them */
        priv->flags = ASYNC_LOW_LATENCY;
 
+       if (quirk && quirk->port_probe)
+               quirk->port_probe(priv);
+
        /* Increase the size of read buffers */
        kfree(port->bulk_in_buffer);
        port->bulk_in_buffer = kmalloc (BUFSZ, GFP_KERNEL);
@@ -1187,7 +1032,8 @@ static int ftdi_sio_attach (struct usb_serial *serial)
                port->read_urb->transfer_buffer_length = BUFSZ;
        }
 
-       INIT_WORK(&priv->rx_work, ftdi_process_read, port);
+       INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read);
+       priv->port = port;
 
        /* Free port's existing write urb and transfer buffer. */
        if (port->write_urb) {
@@ -1197,92 +1043,116 @@ static int ftdi_sio_attach (struct usb_serial *serial)
        kfree(port->bulk_out_buffer);
        port->bulk_out_buffer = NULL;
 
-       usb_set_serial_port_data(serial->port[0], priv);
-
-       ftdi_determine_type (serial->port[0]);
-       create_sysfs_attrs(serial);
-
-       /* Check for device requiring special set up. */
-       quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial);
-       if (quirk && quirk->setup) {
-               quirk->setup(serial);
-       }
-       
-       return (0);
-} /* ftdi_sio_attach */
+       usb_set_serial_port_data(port, priv);
 
+       ftdi_determine_type (port);
+       create_sysfs_attrs(port);
+       return 0;
+}
 
 /* Setup for the USB-UIRT device, which requires hardwired
  * baudrate (38400 gets mapped to 312500) */
 /* Called from usbserial:serial_probe */
-static void ftdi_USB_UIRT_setup (struct usb_serial *serial)
+static void ftdi_USB_UIRT_setup (struct ftdi_private *priv)
 {
-       struct ftdi_private *priv;
-
-       dbg("%s",__FUNCTION__);
+       dbg("%s",__func__);
 
-       priv = usb_get_serial_port_data(serial->port[0]);
        priv->flags |= ASYNC_SPD_CUST;
        priv->custom_divisor = 77;
-       priv->force_baud = B38400;
+       priv->force_baud = 38400;
 } /* ftdi_USB_UIRT_setup */
 
 /* Setup for the HE-TIRA1 device, which requires hardwired
  * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled.  */
-static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
+static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv)
 {
-       struct ftdi_private *priv;
-
-       dbg("%s",__FUNCTION__);
+       dbg("%s",__func__);
 
-       priv = usb_get_serial_port_data(serial->port[0]);
        priv->flags |= ASYNC_SPD_CUST;
        priv->custom_divisor = 240;
-       priv->force_baud = B38400;
+       priv->force_baud = 38400;
        priv->force_rtscts = 1;
 } /* ftdi_HE_TIRA1_setup */
 
+/*
+ * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko
+ * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from
+ * userspace using openocd.
+ */
+static int ftdi_jtag_probe(struct usb_serial *serial)
+{
+       struct usb_device *udev = serial->dev;
+       struct usb_interface *interface = serial->interface;
+
+       dbg("%s",__func__);
+
+       if (interface == udev->actconfig->interface[0]) {
+               info("Ignoring serial port reserved for JTAG");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/*
+ * The Matrix Orbital VK204-25-USB has an invalid IN endpoint.
+ * We have to correct it if we want to read from it.
+ */
+static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
+{
+       struct usb_host_endpoint *ep = serial->dev->ep_in[1];
+       struct usb_endpoint_descriptor *ep_desc = &ep->desc;
+
+       if (ep->enabled && ep_desc->wMaxPacketSize == 0) {
+               ep_desc->wMaxPacketSize = 0x40;
+               info("Fixing invalid wMaxPacketSize on read pipe");
+       }
+
+       return 0;
+}
 
-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect 
+/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
  *   it is called when the usb device is disconnected
  *
  *   usbserial:usb_serial_disconnect
  *      calls __serial_close for each open of the port
  *      shutdown is called then (ie ftdi_shutdown)
  */
-
-
 static void ftdi_shutdown (struct usb_serial *serial)
-{ /* ftdi_shutdown */
-       
-       struct usb_serial_port *port = serial->port[0];
+{
+       dbg("%s", __func__);
+}
+
+static int ftdi_sio_port_remove(struct usb_serial_port *port)
+{
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
+
+       remove_sysfs_attrs(port);
 
-       remove_sysfs_attrs(serial);
-       
-       /* all open ports are closed at this point 
-         *    (by usbserial.c:__serial_close, which calls ftdi_close)  
+       /* all open ports are closed at this point
+         *    (by usbserial.c:__serial_close, which calls ftdi_close)
         */
 
        if (priv) {
                usb_set_serial_port_data(port, NULL);
                kfree(priv);
        }
-} /* ftdi_shutdown */
 
+       return 0;
+}
 
 static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
 { /* ftdi_open */
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-       
+
        int result = 0;
        char buf[1]; /* Needed for the usb_control_msg I think */
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
        spin_lock_irqsave(&priv->tx_lock, flags);
        priv->tx_bytes = 0;
@@ -1297,8 +1167,8 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
        /* No error checking for this (will get errors later anyway) */
        /* See ftdi_sio.h for description of what is reset */
        usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                       FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-                       FTDI_SIO_RESET_SIO, 
+                       FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+                       FTDI_SIO_RESET_SIO,
                        priv->interface, buf, 0, WDR_TIMEOUT);
 
        /* Termios defaults are set by usb_serial_init. We don't change
@@ -1307,7 +1177,7 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
 
        /* ftdi_set_termios  will send usb control messages */
        if (port->tty)
-               ftdi_set_termios(port, NULL);
+               ftdi_set_termios(port, port->tty->termios);
 
        /* FIXME: Flow control might be enabled, so it should be checked -
           we have no control of defaults! */
@@ -1327,7 +1197,7 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
                      ftdi_read_bulk_callback, port);
        result = usb_submit_urb(port->read_urb, GFP_KERNEL);
        if (result)
-               err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+               err("%s - failed submitting read urb, error %d", __func__, result);
 
 
        return result;
@@ -1335,12 +1205,12 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
 
 
 
-/* 
+/*
  * usbserial:__serial_close  only calls ftdi_close if the point is open
  *
  *   This only gets called when it is the last close
- *   
- *   
+ *
+ *
  */
 
 static void ftdi_close (struct usb_serial_port *port, struct file *filp)
@@ -1349,34 +1219,35 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        char buf[1];
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
-       if (c_cflag & HUPCL){
+       mutex_lock(&port->serial->disc_mutex);
+       if (c_cflag & HUPCL && !port->serial->disconnected){
                /* Disable flow control */
-               if (usb_control_msg(port->serial->dev, 
+               if (usb_control_msg(port->serial->dev,
                                    usb_sndctrlpipe(port->serial->dev, 0),
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0, priv->interface, buf, 0,
                                    WDR_TIMEOUT) < 0) {
                        err("error from flowcontrol urb");
-               }           
+               }
 
                /* drop RTS and DTR */
                clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
        } /* Note change no line if hupcl is off */
+       mutex_unlock(&port->serial->disc_mutex);
 
        /* cancel any scheduled reading */
        cancel_delayed_work(&priv->rx_work);
        flush_scheduled_work();
-       
+
        /* shutdown our bulk read */
-       if (port->read_urb)
-               usb_kill_urb(port->read_urb);
+       usb_kill_urb(port->read_urb);
 } /* ftdi_close */
 
 
-  
+
 /* The SIO requires the first byte to have:
  *  B0 1
  *  B1 0
@@ -1395,7 +1266,7 @@ static int ftdi_write (struct usb_serial_port *port,
        int transfer_size;
        unsigned long flags;
 
-       dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
+       dbg("%s port %d, %d bytes", __func__, port->number, count);
 
        if (count == 0) {
                dbg("write request of 0 bytes");
@@ -1404,11 +1275,12 @@ static int ftdi_write (struct usb_serial_port *port,
        spin_lock_irqsave(&priv->tx_lock, flags);
        if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
                spin_unlock_irqrestore(&priv->tx_lock, flags);
-               dbg("%s - write limit hit\n", __FUNCTION__);
+               dbg("%s - write limit hit\n", __func__);
                return 0;
        }
+       priv->tx_outstanding_urbs++;
        spin_unlock_irqrestore(&priv->tx_lock, flags);
-       
+
        data_offset = priv->write_offset;
         dbg("data_offset set to %d",data_offset);
 
@@ -1423,15 +1295,16 @@ static int ftdi_write (struct usb_serial_port *port,
 
        buffer = kmalloc (transfer_size, GFP_ATOMIC);
        if (!buffer) {
-               err("%s ran out of kernel memory for urb ...", __FUNCTION__);
-               return -ENOMEM;
+               err("%s ran out of kernel memory for urb ...", __func__);
+               count = -ENOMEM;
+               goto error_no_buffer;
        }
 
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
-               err("%s - no more free urbs", __FUNCTION__);
-               kfree (buffer);
-               return -ENOMEM;
+               err("%s - no more free urbs", __func__);
+               count = -ENOMEM;
+               goto error_no_urb;
        }
 
        /* Copy data */
@@ -1447,7 +1320,7 @@ static int ftdi_write (struct usb_serial_port *port,
                                user_pktsz = todo;
                        }
                        /* Write the control byte at the front of the packet*/
-                       *first_byte = 1 | ((user_pktsz) << 2); 
+                       *first_byte = 1 | ((user_pktsz) << 2);
                        /* Copy data for packet */
                        memcpy (first_byte + data_offset,
                                current_position, user_pktsz);
@@ -1461,22 +1334,21 @@ static int ftdi_write (struct usb_serial_port *port,
                memcpy (buffer, buf, count);
        }
 
-       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer);
+       usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, buffer);
 
        /* fill the buffer and send it */
-       usb_fill_bulk_urb(urb, port->serial->dev, 
+       usb_fill_bulk_urb(urb, port->serial->dev,
                      usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
                      buffer, transfer_size,
                      ftdi_write_bulk_callback, port);
 
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status) {
-               err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
+               err("%s - failed submitting write urb, error %d", __func__, status);
                count = status;
-               kfree (buffer);
+               goto error;
        } else {
                spin_lock_irqsave(&priv->tx_lock, flags);
-               ++priv->tx_outstanding_urbs;
                priv->tx_outstanding_bytes += count;
                priv->tx_bytes += count;
                spin_unlock_irqrestore(&priv->tx_lock, flags);
@@ -1484,36 +1356,46 @@ static int ftdi_write (struct usb_serial_port *port,
 
        /* we are done with this urb, so let the host driver
         * really free it when it is finished with it */
-       usb_free_urb (urb);
+       usb_free_urb(urb);
 
-       dbg("%s write returning: %d", __FUNCTION__, count);
+       dbg("%s write returning: %d", __func__, count);
+       return count;
+error:
+       usb_free_urb(urb);
+error_no_urb:
+       kfree (buffer);
+error_no_buffer:
+       spin_lock_irqsave(&priv->tx_lock, flags);
+       priv->tx_outstanding_urbs--;
+       spin_unlock_irqrestore(&priv->tx_lock, flags);
        return count;
 } /* ftdi_write */
 
 
 /* This function may get called when the device is closed */
 
-static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void ftdi_write_bulk_callback (struct urb *urb)
 {
        unsigned long flags;
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct ftdi_private *priv;
        int data_offset;       /* will be 1 for the SIO and 0 otherwise */
        unsigned long countback;
+       int status = urb->status;
 
        /* free up the transfer buffer, as usb_free_urb() does not do this */
        kfree (urb->transfer_buffer);
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
-       
-       if (urb->status) {
-               dbg("nonzero write bulk status received: %d", urb->status);
+       dbg("%s - port %d", __func__, port->number);
+
+       if (status) {
+               dbg("nonzero write bulk status received: %d", status);
                return;
        }
 
        priv = usb_get_serial_port_data(port);
        if (!priv) {
-               dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
+               dbg("%s - bad port private data pointer - exiting", __func__);
                return;
        }
        /* account for transferred data */
@@ -1521,7 +1403,7 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
        data_offset = priv->write_offset;
        if (data_offset > 0) {
                /* Subtract the control bytes */
-               countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ));
+               countback -= (data_offset * DIV_ROUND_UP(countback, PKTSZ));
        }
        spin_lock_irqsave(&priv->tx_lock, flags);
        --priv->tx_outstanding_urbs;
@@ -1538,7 +1420,7 @@ static int ftdi_write_room( struct usb_serial_port *port )
        int room;
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->tx_lock, flags);
        if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) {
@@ -1562,13 +1444,13 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port)
        int buffered;
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->tx_lock, flags);
        buffered = (int)priv->tx_outstanding_bytes;
        spin_unlock_irqrestore(&priv->tx_lock, flags);
        if (buffered < 0) {
-               err("%s outstanding tx bytes is negative!", __FUNCTION__);
+               err("%s outstanding tx bytes is negative!", __func__);
                buffered = 0;
        }
        return buffered;
@@ -1576,67 +1458,70 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port)
 
 
 
-static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+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 tty_struct *tty;
        struct ftdi_private *priv;
        unsigned long countread;
        unsigned long flags;
+       int status = urb->status;
 
        if (urb->number_of_packets > 0) {
-               err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
+               err("%s transfer_buffer_length %d actual_length %d number of packets %d",__func__,
                    urb->transfer_buffer_length, urb->actual_length, urb->number_of_packets );
-               err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags );
+               err("%s transfer_flags %x ", __func__,urb->transfer_flags );
        }
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        if (port->open_count <= 0)
                return;
 
        tty = port->tty;
        if (!tty) {
-               dbg("%s - bad tty pointer - exiting",__FUNCTION__);
+               dbg("%s - bad tty pointer - exiting",__func__);
                return;
        }
 
        priv = usb_get_serial_port_data(port);
        if (!priv) {
-               dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
+               dbg("%s - bad port private data pointer - exiting", __func__);
                return;
        }
 
        if (urb != port->read_urb) {
-               err("%s - Not my urb!", __FUNCTION__);
+               err("%s - Not my urb!", __func__);
        }
 
-       if (urb->status) {
+       if (status) {
                /* This will happen at close every time so it is a dbg not an err */
-               dbg("(this is ok on close) nonzero read bulk status received: %d", urb->status);
+               dbg("(this is ok on close) nonzero read bulk status received: "
+                   "%d", status);
                return;
        }
 
        /* count data bytes, but not status bytes */
        countread = urb->actual_length;
-       countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ);
+       countread -= 2 * DIV_ROUND_UP(countread, PKTSZ);
        spin_lock_irqsave(&priv->rx_lock, flags);
        priv->rx_bytes += countread;
        spin_unlock_irqrestore(&priv->rx_lock, flags);
 
-       ftdi_process_read(port);
+       ftdi_process_read(&priv->rx_work.work);
 
 } /* ftdi_read_bulk_callback */
 
 
-static void ftdi_process_read (void *param)
+static void ftdi_process_read (struct work_struct *work)
 { /* ftdi_process_read */
-       struct usb_serial_port *port = (struct usb_serial_port*)param;
+       struct ftdi_private *priv =
+               container_of(work, struct ftdi_private, rx_work.work);
+       struct usb_serial_port *port = priv->port;
        struct urb *urb;
        struct tty_struct *tty;
-       struct ftdi_private *priv;
        char error_flag;
-               unsigned char *data;
+       unsigned char *data;
 
        int i;
        int result;
@@ -1644,39 +1529,39 @@ static void ftdi_process_read (void *param)
        int packet_offset;
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        if (port->open_count <= 0)
                return;
 
        tty = port->tty;
        if (!tty) {
-               dbg("%s - bad tty pointer - exiting",__FUNCTION__);
+               dbg("%s - bad tty pointer - exiting",__func__);
                return;
        }
 
        priv = usb_get_serial_port_data(port);
        if (!priv) {
-               dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
+               dbg("%s - bad port private data pointer - exiting", __func__);
                return;
        }
 
        urb = port->read_urb;
        if (!urb) {
-               dbg("%s - bad read_urb pointer - exiting", __FUNCTION__);
+               dbg("%s - bad read_urb pointer - exiting", __func__);
                return;
        }
 
        data = urb->transfer_buffer;
 
        if (priv->rx_processed) {
-               dbg("%s - already processed: %d bytes, %d remain", __FUNCTION__,
+               dbg("%s - already processed: %d bytes, %d remain", __func__,
                                priv->rx_processed,
                                urb->actual_length - priv->rx_processed);
        } else {
                /* The first two bytes of every read packet are status */
                if (urb->actual_length > 2) {
-                       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+                       usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
                } else {
                        dbg("Status only: %03oo %03oo",data[0],data[1]);
                }
@@ -1706,17 +1591,17 @@ static void ftdi_process_read (void *param)
 
                length = min(PKTSZ, urb->actual_length-packet_offset)-2;
                if (length < 0) {
-                       err("%s - bad packet length: %d", __FUNCTION__, length+2);
+                       err("%s - bad packet length: %d", __func__, length+2);
                        length = 0;
                }
 
                if (priv->rx_flags & THROTTLED) {
-                       dbg("%s - throttled", __FUNCTION__);
+                       dbg("%s - throttled", __func__);
                        break;
                }
                if (tty_buffer_request_room(tty, length) < length) {
                        /* break out & wait for throttling/unthrottling to happen */
-                       dbg("%s - receive room low", __FUNCTION__);
+                       dbg("%s - receive room low", __func__);
                        break;
                }
 
@@ -1744,7 +1629,7 @@ static void ftdi_process_read (void *param)
                }
                if (length > 0) {
                        for (i = 2; i < length+2; i++) {
-                               /* Note that the error flag is duplicated for 
+                               /* 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);
@@ -1758,7 +1643,7 @@ static void ftdi_process_read (void *param)
                   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 
+                  However - this might make sense for framing errors and so on
                   so I am leaving the code in for now.
                */
                else {
@@ -1784,7 +1669,7 @@ static void ftdi_process_read (void *param)
                /* not completely processed - record progress */
                priv->rx_processed = packet_offset;
                dbg("%s - incomplete, %d bytes processed, %d remain",
-                               __FUNCTION__, packet_offset,
+                               __func__, packet_offset,
                                urb->actual_length - packet_offset);
                /* check if we were throttled while processing */
                spin_lock_irqsave(&priv->rx_lock, flags);
@@ -1792,7 +1677,7 @@ static void ftdi_process_read (void *param)
                        priv->rx_flags |= ACTUALLY_THROTTLED;
                        spin_unlock_irqrestore(&priv->rx_lock, flags);
                        dbg("%s - deferring remainder until unthrottled",
-                                       __FUNCTION__);
+                                       __func__);
                        return;
                }
                spin_unlock_irqrestore(&priv->rx_lock, flags);
@@ -1801,7 +1686,7 @@ static void ftdi_process_read (void *param)
                        /* delay processing of remainder */
                        schedule_delayed_work(&priv->rx_work, 1);
                } else {
-                       dbg("%s - port is closed", __FUNCTION__);
+                       dbg("%s - port is closed", __func__);
                }
                return;
        }
@@ -1812,14 +1697,14 @@ static void ftdi_process_read (void *param)
        /* if the port is closed stop trying to read */
        if (port->open_count > 0){
                /* Continue trying to always read  */
-               usb_fill_bulk_urb(port->read_urb, port->serial->dev, 
+               usb_fill_bulk_urb(port->read_urb, port->serial->dev,
                              usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
                              port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
                              ftdi_read_bulk_callback, port);
 
                result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                if (result)
-                       err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+                       err("%s - failed resubmitting read urb, error %d", __func__, result);
        }
 
        return;
@@ -1829,9 +1714,9 @@ static void ftdi_process_read (void *param)
 static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       __u16 urb_value = 0; 
+       __u16 urb_value = 0;
        char buf[1];
-       
+
        /* break_state = -1 to turn on break, and 0 to turn off break */
        /* see drivers/char/tty_io.c to see it used */
        /* last_set_data_urb_value NEVER has the break bit set in it */
@@ -1839,20 +1724,20 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
        if (break_state) {
                urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;
        } else {
-               urb_value = priv->last_set_data_urb_value; 
+               urb_value = priv->last_set_data_urb_value;
        }
 
-       
+
        if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
-                           FTDI_SIO_SET_DATA_REQUEST, 
+                           FTDI_SIO_SET_DATA_REQUEST,
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
                            urb_value , priv->interface,
                            buf, 0, WDR_TIMEOUT) < 0) {
-               err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
-       }          
+               err("%s FAILED to enable/disable break state (state was %d)", __func__,break_state);
+       }
+
+       dbg("%s break state is %d - urb is %d", __func__,break_state, urb_value);
 
-       dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
-       
 }
 
 
@@ -1861,50 +1746,53 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
  * WARNING: set_termios calls this with old_termios in kernel space
  */
 
-static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
 { /* ftdi_termios */
        struct usb_device *dev = port->serial->dev;
-       unsigned int cflag = port->tty->termios->c_cflag;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct ktermios *termios = port->tty->termios;
+       unsigned int cflag = termios->c_cflag;
        __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 int iflag = termios->c_iflag;
        unsigned char vstop;
        unsigned char vstart;
-       
-       dbg("%s", __FUNCTION__);
+
+       dbg("%s", __func__);
 
        /* 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;
+       if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
+               dbg("%s: forcing baud rate for this device", __func__);
+               tty_encode_baud_rate(port->tty, priv->force_baud,
+                                       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;
+               dbg("%s: forcing rtscts for this device", __func__);
+               termios->c_cflag |= CRTSCTS;
        }
 
-       cflag = port->tty->termios->c_cflag;
+       cflag = 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 
+       /* 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
           compare old_termios and tty->termios */
-       /* NOTE These routines can get interrupted by 
-          ftdi_sio_read_bulk_callback  - need to examine what this 
+       /* NOTE These routines can get interrupted by
+          ftdi_sio_read_bulk_callback  - need to examine what this
            means - don't see any problems yet */
-       
+
        /* Set number of data bits, parity, stop bits */
-       
+
+       termios->c_cflag &= ~CMSPAR;
+
        urb_value = 0;
        urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
                      FTDI_SIO_SET_DATA_STOP_BITS_1);
-       urb_value |= (cflag & PARENB ? 
-                     (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : 
+       urb_value |= (cflag & PARENB ?
+                     (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
                       FTDI_SIO_SET_DATA_PARITY_EVEN) :
                      FTDI_SIO_SET_DATA_PARITY_NONE);
        if (cflag & CSIZE) {
@@ -1921,31 +1809,31 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
        /* This is needed by the break command since it uses the same command - but is
         *  or'ed with this value  */
        priv->last_set_data_urb_value = urb_value;
-       
+
        if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                           FTDI_SIO_SET_DATA_REQUEST, 
+                           FTDI_SIO_SET_DATA_REQUEST,
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
                            urb_value , priv->interface,
                            buf, 0, WDR_SHORT_TIMEOUT) < 0) {
-               err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
-       }          
+               err("%s FAILED to set databits/stopbits/parity", __func__);
+       }
 
        /* Now do the baudrate */
        if ((cflag & CBAUD) == B0 ) {
                /* Disable flow control */
                if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                                   0, priv->interface, 
+                                   0, priv->interface,
                                    buf, 0, WDR_TIMEOUT) < 0) {
-                       err("%s error from disable flowcontrol urb", __FUNCTION__);
-               }           
+                       err("%s error from disable flowcontrol urb", __func__);
+               }
                /* Drop RTS and DTR */
                clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
        } else {
                /* set the baudrate determined before */
                if (change_speed(port)) {
-                       err("%s urb failed to set baudrate", __FUNCTION__);
+                       err("%s urb failed to set baudrate", __func__);
                }
                /* Ensure RTS and DTR are raised when baudrate changed from 0 */
                if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) {
@@ -1956,17 +1844,17 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
        /* Set flow control */
        /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
        if (cflag & CRTSCTS) {
-               dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);
-               if (usb_control_msg(dev, 
+               dbg("%s Setting to CRTSCTS flow control", __func__);
+               if (usb_control_msg(dev,
                                    usb_sndctrlpipe(dev, 0),
-                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
                                    buf, 0, WDR_TIMEOUT) < 0) {
                        err("urb failed to set to rts/cts flow control");
-               }               
-               
-       } else { 
+               }
+
+       } else {
                /*
                 * Xon/Xoff code
                 *
@@ -1974,13 +1862,13 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
                 * 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);
+                       dbg("%s  request to enable xonxoff iflag=%04x",__func__,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];
+                       vstart = termios->c_cc[VSTART];
+                       vstop = termios->c_cc[VSTOP];
                        urb_value=(vstop << 8) | (vstart);
 
                        if (usb_control_msg(dev,
@@ -1995,17 +1883,17 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
                } 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(dev, 
+                       dbg("%s Turning off hardware flow control", __func__);
+                       if (usb_control_msg(dev,
                                            usb_sndctrlpipe(dev, 0),
-                                           FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+                                           FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                                           0, priv->interface, 
+                                           0, priv->interface,
                                            buf, 0, WDR_TIMEOUT) < 0) {
                                err("urb failed to clear flow control");
-                       }                               
+                       }
                }
-               
+
        }
        return;
 } /* ftdi_termios */
@@ -2017,17 +1905,17 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
        unsigned char buf[2];
        int ret;
 
-       dbg("%s TIOCMGET", __FUNCTION__);
+       dbg("%s TIOCMGET", __func__);
        switch (priv->chip_type) {
        case SIO:
                /* Request the status from the device */
-               if ((ret = usb_control_msg(port->serial->dev, 
+               if ((ret = usb_control_msg(port->serial->dev,
                                           usb_rcvctrlpipe(port->serial->dev, 0),
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST,
                                           FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                                          0, 0, 
+                                          0, 0,
                                           buf, 1, WDR_TIMEOUT)) < 0 ) {
-                       err("%s Could not get modem status of device - err: %d", __FUNCTION__,
+                       err("%s Could not get modem status of device - err: %d", __func__,
                            ret);
                        return(ret);
                }
@@ -2035,15 +1923,16 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
        case FT8U232AM:
        case FT232BM:
        case FT2232C:
+       case FT232RL:
                /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
                   format as the data returned from the in point */
-               if ((ret = usb_control_msg(port->serial->dev, 
+               if ((ret = usb_control_msg(port->serial->dev,
                                           usb_rcvctrlpipe(port->serial->dev, 0),
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST,
                                           FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                                          0, priv->interface, 
+                                          0, priv->interface,
                                           buf, 2, WDR_TIMEOUT)) < 0 ) {
-                       err("%s Could not get modem status of device - err: %d", __FUNCTION__,
+                       err("%s Could not get modem status of device - err: %d", __func__,
                            ret);
                        return(ret);
                }
@@ -2052,17 +1941,17 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
                return -EFAULT;
                break;
        }
-       
+
        return  (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
                (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
                (buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |
                (buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0) |
-               priv->last_dtr_rts;                     
+               priv->last_dtr_rts;
 }
 
 static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
 {
-       dbg("%s TIOCMSET", __FUNCTION__);
+       dbg("%s TIOCMSET", __func__);
        return update_mctrl(port, set, clear);
 }
 
@@ -2071,7 +1960,7 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-       dbg("%s cmd 0x%04x", __FUNCTION__, cmd);
+       dbg("%s cmd 0x%04x", __func__, cmd);
 
        /* Based on code from acm.c and others */
        switch (cmd) {
@@ -2123,14 +2012,14 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
                break;
        default:
                break;
-               
+
        }
 
 
-       /* This is not necessarily an error - turns out the higher layers will do 
+       /* This is not necessarily an error - turns out the higher layers will do
         *  some ioctls itself (see comment above)
         */
-       dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
+       dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __func__, cmd);
 
        return(-ENOIOCTLCMD);
 } /* ftdi_ioctl */
@@ -2141,7 +2030,7 @@ static void ftdi_throttle (struct usb_serial_port *port)
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->rx_lock, flags);
        priv->rx_flags |= THROTTLED;
@@ -2155,7 +2044,7 @@ static void ftdi_unthrottle (struct usb_serial_port *port)
        int actually_throttled;
        unsigned long flags;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        spin_lock_irqsave(&priv->rx_lock, flags);
        actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
@@ -2163,14 +2052,14 @@ static void ftdi_unthrottle (struct usb_serial_port *port)
        spin_unlock_irqrestore(&priv->rx_lock, flags);
 
        if (actually_throttled)
-               schedule_work(&priv->rx_work);
+               schedule_delayed_work(&priv->rx_work, 0);
 }
 
 static int __init ftdi_init (void)
 {
        int retval;
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
        if (vendor > 0 && product > 0) {
                /* Add user specified VID/PID to reserved element of table. */
                int i;
@@ -2184,7 +2073,7 @@ static int __init ftdi_init (void)
        if (retval)
                goto failed_sio_register;
        retval = usb_register(&ftdi_driver);
-       if (retval) 
+       if (retval)
                goto failed_usb_register;
 
        info(DRIVER_VERSION ":" DRIVER_DESC);
@@ -2199,7 +2088,7 @@ failed_sio_register:
 static void __exit ftdi_exit (void)
 {
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
        usb_deregister (&ftdi_driver);
        usb_serial_deregister (&ftdi_sio_device);