USB serial: Add ID for Turtelizer, an FT2232L-based JTAG/RS-232 adapter.
[safe/jmp/linux-2.6] / drivers / usb / serial / ftdi_sio.c
index 8ff9d54..d5ea072 100644 (file)
  *     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 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.
  *
  */
 
 /* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
 /* Thanx to FTDI for so kindly providing details of the protocol required */
 /*   to talk to the device */
-/* Thanx to gkh and the rest of the usb dev group for all code I have assimilated :-) */
+/* Thanx to gkh and the rest of the usb dev group for all code I have
+   assimilated :-) */
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/serial.h>
 #include <linux/usb/serial.h>
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.4.3"
+#define DRIVER_VERSION "v1.5.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
@@ -271,20 +55,80 @@ static int debug;
 static __u16 vendor = FTDI_VID;
 static __u16 product;
 
+struct ftdi_private {
+       struct kref kref;
+       ftdi_chip_type_t chip_type;
+                               /* type of 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 varies 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, FT2232H or FT4232H 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 */
+
+       unsigned int latency;           /* latency setting in use */
+       spinlock_t tx_lock;     /* spinlock for transmit state */
+       unsigned long tx_bytes;
+       unsigned long tx_outstanding_bytes;
+       unsigned long tx_outstanding_urbs;
+       unsigned short max_packet_size;
+};
+
 /* 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 *);
+       /* Special settings for probed ports. */
+       void (*port_probe)(struct ftdi_private *);
 };
 
-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 int   ftdi_NDI_device_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_NDI_device_quirk = {
+       .probe  = ftdi_NDI_device_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,
 };
 
 /*
@@ -308,19 +152,32 @@ 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_CANDAPTER_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_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_4232H_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_SPROG_II) },
        { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) },
@@ -339,9 +196,275 @@ 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(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) },
        { 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) },
@@ -430,30 +553,30 @@ static struct usb_device_id id_table_combined [] = {
        { 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, 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, FTDI_ELV_HS485_PID) },
        { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
        { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
        { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -462,12 +585,16 @@ static struct usb_device_id id_table_combined [] = {
        { 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, FTDI_CCSLOAD_N_GO_3_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_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(FTDI_VID, FTDI_OCEANIC_PID) },
        { USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
@@ -497,11 +624,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) },
@@ -523,12 +653,55 @@ static struct usb_device_id id_table_combined [] = {
        { 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(FTDI_VID, FTDI_NDI_HUC_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
        { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_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 },
+       { USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
+       { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
+       { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
+       { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
+       { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) },
+       { USB_DEVICE(ATMEL_VID, STK541_PID) },
+       { USB_DEVICE(DE_VID, STB_PID) },
+       { USB_DEVICE(DE_VID, WHT_PID) },
+       { USB_DEVICE(ADI_VID, ADI_GNICE_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
+       { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
 
-MODULE_DEVICE_TABLE (usb, id_table_combined);
+MODULE_DEVICE_TABLE(usb, id_table_combined);
 
 static struct usb_driver ftdi_driver = {
        .name =         "ftdi_sio",
@@ -544,83 +717,59 @@ static const char *ftdi_chip_name[] = {
        [FT232BM] = "FT232BM",
        [FT2232C] = "FT2232C",
        [FT232RL] = "FT232RL",
+       [FT2232H] = "FT2232H",
+       [FT4232H] = "FT4232H"
 };
 
 
 /* Constants for read urb and write urb */
 #define BUFSZ 512
-#define PKTSZ 64
 
 /* rx_flags */
 #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 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) */
-
-       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);
-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);
-static void ftdi_break_ctl             (struct usb_serial_port *port, int break_state );
-static void ftdi_throttle              (struct usb_serial_port *port);
-static void ftdi_unthrottle            (struct usb_serial_port *port);
-
-static unsigned short int ftdi_232am_baud_base_to_divisor (int baud, int base);
-static unsigned short int ftdi_232am_baud_to_divisor (int baud);
-static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
-static __u32 ftdi_232bm_baud_to_divisor (int baud);
+static int  ftdi_sio_probe(struct usb_serial *serial,
+                                       const struct usb_device_id *id);
+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 tty_struct *tty,
+                       struct usb_serial_port *port, struct file *filp);
+static void ftdi_close(struct usb_serial_port *port);
+static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
+static int  ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
+                       const unsigned char *buf, int count);
+static int  ftdi_write_room(struct tty_struct *tty);
+static int  ftdi_chars_in_buffer(struct tty_struct *tty);
+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 tty_struct *tty,
+                       struct usb_serial_port *port, struct ktermios *old);
+static int  ftdi_tiocmget(struct tty_struct *tty, struct file *file);
+static int  ftdi_tiocmset(struct tty_struct *tty, struct file *file,
+                       unsigned int set, unsigned int clear);
+static int  ftdi_ioctl(struct tty_struct *tty, struct file *file,
+                       unsigned int cmd, unsigned long arg);
+static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
+static void ftdi_throttle(struct tty_struct *tty);
+static void ftdi_unthrottle(struct tty_struct *tty);
+
+static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
+static unsigned short int ftdi_232am_baud_to_divisor(int baud);
+static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base);
+static __u32 ftdi_232bm_baud_to_divisor(int baud);
+static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base);
+static __u32 ftdi_2232h_baud_to_divisor(int baud);
 
 static struct usb_serial_driver ftdi_sio_device = {
        .driver = {
@@ -630,15 +779,13 @@ static struct usb_serial_driver ftdi_sio_device = {
        .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,
+       .dtr_rts =              ftdi_dtr_rts,
        .throttle =             ftdi_throttle,
        .unthrottle =           ftdi_unthrottle,
        .write =                ftdi_write,
@@ -651,8 +798,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,
 };
 
 
@@ -668,51 +813,91 @@ static struct usb_serial_driver ftdi_sio_device = {
 
 /*
  * ***************************************************************************
- * Utlity functions
+ * Utility functions
  * ***************************************************************************
  */
 
 static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
 {
        unsigned short int divisor;
-       int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
-       if ((divisor3 & 0x7) == 7) divisor3 ++; // round x.7/8 up to x+1
+       /* divisor shifted 3 bits to the left */
+       int divisor3 = base / 2 / baud;
+       if ((divisor3 & 0x7) == 7)
+               divisor3++; /* round x.7/8 up to x+1 */
        divisor = divisor3 >> 3;
        divisor3 &= 0x7;
-       if (divisor3 == 1) divisor |= 0xc000; else // 0.125
-       if (divisor3 >= 4) divisor |= 0x4000; else // 0.5
-       if (divisor3 != 0) divisor |= 0x8000;      // 0.25
-       if (divisor == 1) divisor = 0;  /* special case for maximum baud rate */
+       if (divisor3 == 1)
+               divisor |= 0xc000;
+       else if (divisor3 >= 4)
+               divisor |= 0x4000;
+       else if (divisor3 != 0)
+               divisor |= 0x8000;
+       else if (divisor == 1)
+               divisor = 0;    /* special case for maximum baud rate */
        return divisor;
 }
 
 static unsigned short int ftdi_232am_baud_to_divisor(int baud)
 {
-        return(ftdi_232am_baud_base_to_divisor(baud, 48000000));
+        return ftdi_232am_baud_base_to_divisor(baud, 48000000);
 }
 
 static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
 {
        static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
        __u32 divisor;
-       int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
+       /* divisor shifted 3 bits to the left */
+       int divisor3 = base / 2 / baud;
        divisor = divisor3 >> 3;
        divisor |= (__u32)divfrac[divisor3 & 0x7] << 14;
        /* Deal with special cases for highest baud rates. */
-       if (divisor == 1) divisor = 0; else     // 1.0
-       if (divisor == 0x4001) divisor = 1;     // 1.5
+       if (divisor == 1)
+               divisor = 0;
+       else if (divisor == 0x4001)
+               divisor = 1;
        return divisor;
 }
 
 static __u32 ftdi_232bm_baud_to_divisor(int baud)
 {
-        return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
+        return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
+}
+
+static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
+{
+       static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
+       __u32 divisor;
+       int divisor3;
+
+       /* hi-speed baud rate is 10-bit sampling instead of 16-bit */
+       divisor3 = (base / 10 / baud) * 8;
+
+       divisor = divisor3 >> 3;
+       divisor |= (__u32)divfrac[divisor3 & 0x7] << 14;
+       /* Deal with special cases for highest baud rates. */
+       if (divisor == 1)
+               divisor = 0;
+       else if (divisor == 0x4001)
+               divisor = 1;
+       /*
+        * Set this bit to turn off a divide by 2.5 on baud rate generator
+        * This enables baud rates up to 12Mbaud but cannot reach below 1200
+        * baud with this bit set
+        */
+       divisor |= 0x00020000;
+       return divisor;
+}
+
+static __u32 ftdi_2232h_baud_to_divisor(int baud)
+{
+        return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
 }
 
 #define set_mctrl(port, set)           update_mctrl((port), (set), 0)
 #define clear_mctrl(port, clear)       update_mctrl((port), 0, (clear))
 
-static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear)
+static int update_mctrl(struct usb_serial_port *port, unsigned int set,
+                                                       unsigned int clear)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        char *buf;
@@ -720,14 +905,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;
@@ -748,60 +932,27 @@ 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__,
+               dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+                               __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;
 }
 
 
-static __u32 get_ftdi_divisor(struct usb_serial_port * port);
-
-
-static int change_speed(struct usb_serial_port *port)
-{
-       struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char *buf;
-        __u16 urb_value;
-       __u16 urb_index;
-       __u32 urb_index_value;
-       int rv;
-
-       buf = kmalloc(1, GFP_NOIO);
-       if (!buf)
-               return -ENOMEM;
-
-       urb_index_value = get_ftdi_divisor(port);
-       urb_value = (__u16)urb_index_value;
-       urb_index = (__u16)(urb_index_value >> 16);
-       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,
-                           FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
-                           urb_value, urb_index,
-                           buf, 0, WDR_SHORT_TIMEOUT);
-
-       kfree(buf);
-       return rv;
-}
-
-
-static __u32 get_ftdi_divisor(struct usb_serial_port * port)
+static __u32 get_ftdi_divisor(struct tty_struct *tty,
+                                               struct usb_serial_port *port)
 { /* get_ftdi_divisor */
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        __u32 div_value = 0;
@@ -809,48 +960,56 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
        int baud;
 
        /*
-        * The logic involved in setting the baudrate can be cleanly split in 3 steps.
-        * Obtaining the actual baud rate is a little tricky since unix traditionally
-        * somehow ignored the possibility to set non-standard baud rates.
+        * The logic involved in setting the baudrate can be cleanly split into
+        * 3 steps.
         * 1. Standard baud rates are set in tty->termios->c_cflag
-        * 2. If these are not enough, you can set any speed using alt_speed as follows:
+        * 2. If these are not enough, you can set any speed using alt_speed as
+        * follows:
         *    - set tty->termios->c_cflag speed to B38400
         *    - set your real speed in tty->alt_speed; it gets ignored when
         *      alt_speed==0, (or)
-        *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as follows:
-        *      flags & ASYNC_SPD_MASK == ASYNC_SPD_[HI, VHI, SHI, WARP], this just
-        *      sets alt_speed to (HI: 57600, VHI: 115200, SHI: 230400, WARP: 460800)
+        *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as
+        *      follows:
+        *      flags & ASYNC_SPD_MASK == ASYNC_SPD_[HI, VHI, SHI, WARP],
+        *      this just sets alt_speed to (HI: 57600, VHI: 115200,
+        *      SHI: 230400, WARP: 460800)
         * ** Steps 1, 2 are done courtesy of tty_get_baud_rate
         * 3. You can also set baud rate by setting custom divisor as follows
         *    - set tty->termios->c_cflag speed to B38400
-        *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as follows:
+        *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as
+        *      follows:
         *      o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
         *      o custom_divisor set to baud_base / your_new_baudrate
-        * ** Step 3 is done courtesy of code borrowed from serial.c - I should really
-        *    spend some time and separate+move this common code to serial.c, it is
-        *    replicated in nearly every serial driver you see.
+        * ** Step 3 is done courtesy of code borrowed from serial.c
+        *    I should really spend some time and separate + move this common
+        *    code to serial.c, it is replicated in nearly every serial driver
+        *    you see.
         */
 
-       /* 1. Get the baud rate from the tty settings, this observes alt_speed hack */
+       /* 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);
+       baud = tty_get_baud_rate(tty);
+       dbg("%s - tty_get_baud_rate reports speed %d", __func__, baud);
 
-       /* 2. Observe async-compatible custom_divisor hack, update baudrate if needed */
+       /* 2. Observe async-compatible custom_divisor hack, update baudrate
+          if needed */
 
        if (baud == 38400 &&
            ((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;
-       switch(priv->chip_type) {
+       if (!baud)
+               baud = 9600;
+       switch (priv->chip_type) {
        case SIO: /* SIO chip */
-               switch(baud) {
+               switch (baud) {
                case 300: div_value = ftdi_sio_b300; break;
                case 600: div_value = ftdi_sio_b600; break;
                case 1200: div_value = ftdi_sio_b1200; break;
@@ -863,8 +1022,10 @@ 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;
@@ -872,7 +1033,8 @@ 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;
                }
@@ -881,26 +1043,131 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
        case FT2232C: /* FT2232C chip */
        case FT232RL:
                if (baud <= 3000000) {
+                       __u16 product_id = le16_to_cpu(
+                               port->serial->dev->descriptor.idProduct);
+                       if (((FTDI_NDI_HUC_PID == product_id) ||
+                            (FTDI_NDI_SPECTRA_SCU_PID == product_id) ||
+                            (FTDI_NDI_FUTURE_2_PID == product_id) ||
+                            (FTDI_NDI_FUTURE_3_PID == product_id) ||
+                            (FTDI_NDI_AURORA_SCU_PID == product_id)) &&
+                           (baud == 19200)) {
+                               baud = 1200000;
+                       }
+                       div_value = ftdi_232bm_baud_to_divisor(baud);
+               } else {
+                       dbg("%s - Baud rate too high!", __func__);
+                       div_value = ftdi_232bm_baud_to_divisor(9600);
+                       div_okay = 0;
+                       baud = 9600;
+               }
+               break;
+       case FT2232H: /* FT2232H chip */
+       case FT4232H: /* FT4232H chip */
+               if ((baud <= 12000000) & (baud >= 1200)) {
+                       div_value = ftdi_2232h_baud_to_divisor(baud);
+               } else if (baud < 1200) {
                        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]);
        }
 
-       return(div_value);
+       tty_encode_baud_rate(tty, baud, baud);
+       return div_value;
+}
+
+static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       char *buf;
+       __u16 urb_value;
+       __u16 urb_index;
+       __u32 urb_index_value;
+       int rv;
+
+       buf = kmalloc(1, GFP_NOIO);
+       if (!buf)
+               return -ENOMEM;
+
+       urb_index_value = get_ftdi_divisor(tty, port);
+       urb_value = (__u16)urb_index_value;
+       urb_index = (__u16)(urb_index_value >> 16);
+       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,
+                           FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+                           urb_value, urb_index,
+                           buf, 0, WDR_SHORT_TIMEOUT);
+
+       kfree(buf);
+       return rv;
 }
 
+static int write_latency_timer(struct usb_serial_port *port)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *udev = port->serial->dev;
+       char buf[1];
+       int rv = 0;
+       int l = priv->latency;
+
+       if (priv->flags & ASYNC_LOW_LATENCY)
+               l = 1;
 
-static int get_serial_info(struct usb_serial_port * port, struct serial_struct __user * retinfo)
+       dbg("%s: setting latency timer = %i", __func__, l);
+
+       rv = usb_control_msg(udev,
+                            usb_sndctrlpipe(udev, 0),
+                            FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
+                            FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
+                            l, priv->interface,
+                            buf, 0, WDR_TIMEOUT);
+
+       if (rv < 0)
+               dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
+       return rv;
+}
+
+static int read_latency_timer(struct usb_serial_port *port)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *udev = port->serial->dev;
+       unsigned short latency = 0;
+       int rv = 0;
+
+
+       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,
+                            (char *) &latency, 1, WDR_TIMEOUT);
+
+       if (rv < 0) {
+               dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
+               return -EIO;
+       }
+       return latency;
+}
+
+static int get_serial_info(struct usb_serial_port *port,
+                               struct serial_struct __user *retinfo)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct serial_struct tmp;
@@ -917,7 +1184,8 @@ static int get_serial_info(struct usb_serial_port * port, struct serial_struct _
 } /* get_serial_info */
 
 
-static int set_serial_info(struct usb_serial_port * port, struct serial_struct __user * newinfo)
+static int set_serial_info(struct tty_struct *tty,
+       struct usb_serial_port *port, struct serial_struct __user *newinfo)
 { /* set_serial_info */
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct serial_struct new_serial;
@@ -925,14 +1193,18 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _
 
        if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
                return -EFAULT;
-       old_priv = * priv;
+
+       lock_kernel();
+       old_priv = *priv;
 
        /* Do error checking and permission checking */
 
        if (!capable(CAP_SYS_ADMIN)) {
                if (((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (priv->flags & ~ASYNC_USR_MASK)))
+                    (priv->flags & ~ASYNC_USR_MASK))) {
+                       unlock_kernel();
                        return -EPERM;
+               }
                priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
                               (new_serial.flags & ASYNC_USR_MASK));
                priv->custom_divisor = new_serial.custom_divisor;
@@ -940,39 +1212,44 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _
        }
 
        if ((new_serial.baud_base != priv->baud_base) &&
-           (new_serial.baud_base < 9600))
+           (new_serial.baud_base < 9600)) {
+               unlock_kernel();
                return -EINVAL;
+       }
 
        /* 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;
+       tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       write_latency_timer(port);
 
 check_and_exit:
        if ((old_priv.flags & ASYNC_SPD_MASK) !=
             (priv->flags & ASYNC_SPD_MASK)) {
                if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-                       port->tty->alt_speed = 57600;
+                       tty->alt_speed = 57600;
                else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-                       port->tty->alt_speed = 115200;
+                       tty->alt_speed = 115200;
                else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-                       port->tty->alt_speed = 230400;
+                       tty->alt_speed = 230400;
                else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-                       port->tty->alt_speed = 460800;
+                       tty->alt_speed = 460800;
                else
-                       port->tty->alt_speed = 0;
+                       tty->alt_speed = 0;
        }
        if (((old_priv.flags & ASYNC_SPD_MASK) !=
             (priv->flags & ASYNC_SPD_MASK)) ||
            (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
             (old_priv.custom_divisor != priv->custom_divisor))) {
-               change_speed(port);
+               unlock_kernel();
+               change_speed(tty, port);
        }
-
-       return (0);
+       else
+               unlock_kernel();
+       return 0;
 
 } /* set_serial_info */
 
@@ -992,25 +1269,39 @@ 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;
 
-               /* Multiple interfaces.  Assume FT2232C. */
-               priv->chip_type = FT2232C;
+               /* Multiple interfaces.*/
+               if (version == 0x0800) {
+                       priv->chip_type = FT4232H;
+                       /* Hi-speed - baud clock runs at 120MHz */
+                       priv->baud_base = 120000000 / 2;
+               } else if (version == 0x0700) {
+                       priv->chip_type = FT2232H;
+                       /* Hi-speed - baud clock runs at 120MHz */
+                       priv->baud_base = 120000000 / 2;
+               } else
+                       priv->chip_type = FT2232C;
+
                /* Determine interface code. */
                inter = serial->interface->altsetting->desc.bInterfaceNumber;
                if (inter == 0) {
-                       priv->interface = PIT_SIOA;
-               } else {
-                       priv->interface = PIT_SIOB;
+                       priv->interface = INTERFACE_A;
+               } else  if (inter == 1) {
+                       priv->interface = INTERFACE_B;
+               } else  if (inter == 2) {
+                       priv->interface = INTERFACE_C;
+               } else  if (inter == 3) {
+                       priv->interface = INTERFACE_D;
                }
                /* BM-type devices have a bug where bcdDevice gets set
                 * 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. */
@@ -1029,7 +1320,46 @@ static void ftdi_determine_type(struct usb_serial_port *port)
                /* Assume its an FT232R  */
                priv->chip_type = FT232RL;
        }
-       info("Detected %s", ftdi_chip_name[priv->chip_type]);
+       dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
+}
+
+
+/* Determine the maximum packet size for the device.  This depends on the chip
+ * type and the USB host capabilities.  The value should be obtained from the
+ * device descriptor as the chip will use the appropriate values for the host.*/
+static void ftdi_set_max_packet_size(struct usb_serial_port *port)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct usb_serial *serial = port->serial;
+       struct usb_device *udev = serial->dev;
+
+       struct usb_interface *interface = serial->interface;
+       struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
+
+       unsigned num_endpoints;
+       int i = 0;
+
+       num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
+       dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
+
+       /* NOTE: some customers have programmed FT232R/FT245R devices
+        * with an endpoint size of 0 - not good.  In this case, we
+        * want to override the endpoint descriptor setting and use a
+        * value of 64 for wMaxPacketSize */
+       for (i = 0; i < num_endpoints; i++) {
+               dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
+                       interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
+               ep_desc = &interface->cur_altsetting->endpoint[i].desc;
+               if (ep_desc->wMaxPacketSize == 0) {
+                       ep_desc->wMaxPacketSize = cpu_to_le16(0x40);
+                       dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i);
+               }
+       }
+
+       /* set max packet size based on descriptor */
+       priv->max_packet_size = ep_desc->wMaxPacketSize;
+
+       dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
 }
 
 
@@ -1039,63 +1369,39 @@ static void ftdi_determine_type(struct usb_serial_port *port)
  * ***************************************************************************
  */
 
-static ssize_t show_latency_timer(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_latency_timer(struct device *dev,
+                               struct device_attribute *attr, char *buf)
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev = port->serial->dev;
-       unsigned short latency = 0;
-       int rv = 0;
-
-
-       dbg("%s",__FUNCTION__);
-
-       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,
-                            (char*) &latency, 1, WDR_TIMEOUT);
-
-       if (rv < 0) {
-               dev_err(dev, "Unable to read latency timer: %i", rv);
-               return -EIO;
-       }
-       return sprintf(buf, "%i\n", latency);
+       if (priv->flags & ASYNC_LOW_LATENCY)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "%i\n", priv->latency);
 }
 
+
 /* Write a new value of the latency timer, in units of milliseconds. */
-static ssize_t store_latency_timer(struct device *dev, struct device_attribute *attr, const char *valbuf,
-                                  size_t count)
+static ssize_t store_latency_timer(struct device *dev,
+                       struct device_attribute *attr, const char *valbuf,
+                       size_t count)
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct usb_device *udev = port->serial->dev;
-       char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
 
-       dbg("%s: setting latency timer = %i", __FUNCTION__, 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,
-                            buf, 0, WDR_TIMEOUT);
-
-       if (rv < 0) {
-               dev_err(dev, "Unable to write latency timer: %i", rv);
+       priv->latency = v;
+       rv = write_latency_timer(port);
+       if (rv < 0)
                return -EIO;
-       }
-
        return count;
 }
 
 /* Write an event character directly to the FTDI register.  The ASCII
    value is in the low 8 bits, with the enable bit in the 9th bit. */
-static ssize_t store_event_char(struct device *dev, struct device_attribute *attr, const char *valbuf,
-                               size_t count)
+static ssize_t store_event_char(struct device *dev,
+       struct device_attribute *attr, const char *valbuf, size_t count)
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1104,7 +1410,7 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
 
-       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),
@@ -1121,7 +1427,8 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
        return count;
 }
 
-static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, store_latency_timer);
+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 int create_sysfs_attrs(struct usb_serial_port *port)
@@ -1129,7 +1436,7 @@ 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",__FUNCTION__);
+       dbg("%s", __func__);
 
        /* XXX I've no idea if the original SIO supports the event_char
         * sysfs parameter, so I'm playing it safe.  */
@@ -1137,7 +1444,11 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
                dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
                retval = device_create_file(&port->dev, &dev_attr_event_char);
                if ((!retval) &&
-                   (priv->chip_type == FT232BM || priv->chip_type == FT2232C)) {
+                   (priv->chip_type == FT232BM ||
+                    priv->chip_type == FT2232C ||
+                    priv->chip_type == FT232RL ||
+                    priv->chip_type == FT2232H ||
+                    priv->chip_type == FT4232H)) {
                        retval = device_create_file(&port->dev,
                                                    &dev_attr_latency_timer);
                }
@@ -1149,12 +1460,16 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-       dbg("%s",__FUNCTION__);
+       dbg("%s", __func__);
 
        /* XXX see create_sysfs_attrs */
        if (priv->chip_type != SIO) {
                device_remove_file(&port->dev, &dev_attr_event_char);
-               if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+               if (priv->chip_type == FT232BM ||
+                   priv->chip_type == FT2232C ||
+                   priv->chip_type == FT232RL ||
+                   priv->chip_type == FT2232H ||
+                   priv->chip_type == FT4232H) {
                        device_remove_file(&port->dev, &dev_attr_latency_timer);
                }
        }
@@ -1168,37 +1483,54 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
  */
 
 /* Probe function to check for special devices */
-static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id)
+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;
 }
 
 static int ftdi_sio_port_probe(struct usb_serial_port *port)
 {
        struct ftdi_private *priv;
+       struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
+
 
-       dbg("%s",__FUNCTION__);
+       dbg("%s", __func__);
 
        priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
-       if (!priv){
-               err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
+       if (!priv) {
+               dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
+                                       sizeof(struct ftdi_private));
                return -ENOMEM;
        }
 
+       kref_init(&priv->kref);
        spin_lock_init(&priv->rx_lock);
        spin_lock_init(&priv->tx_lock);
-        init_waitqueue_head(&priv->delta_msr_wait);
+       init_waitqueue_head(&priv->delta_msr_wait);
        /* This will push the characters through immediately rather
           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);
+       port->bulk_in_buffer = kmalloc(BUFSZ, GFP_KERNEL);
        if (!port->bulk_in_buffer) {
-               kfree (priv);
+               kfree(priv);
                return -ENOMEM;
        }
        if (port->read_urb) {
@@ -1211,7 +1543,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
 
        /* Free port's existing write urb and transfer buffer. */
        if (port->write_urb) {
-               usb_free_urb (port->write_urb);
+               usb_free_urb(port->write_urb);
                port->write_urb = NULL;
        }
        kfree(port->bulk_out_buffer);
@@ -1219,88 +1551,132 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
 
        usb_set_serial_port_data(port, priv);
 
-       ftdi_determine_type (port);
+       ftdi_determine_type(port);
+       ftdi_set_max_packet_size(port);
+       read_latency_timer(port);
        create_sysfs_attrs(port);
        return 0;
 }
 
-/* attach subroutine */
-static int ftdi_sio_attach (struct usb_serial *serial)
-{
-       /* Check for device requiring special set up. */
-       struct ftdi_sio_quirk *quirk = usb_get_serial_data(serial);
-
-       if (quirk && quirk->setup)
-               quirk->setup(serial);
-
-       return 0;
-} /* ftdi_sio_attach */
-
-
 /* 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", __func__);
 
-       dbg("%s",__FUNCTION__);
-
-       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)
-{
-       struct ftdi_private *priv;
 
-       dbg("%s",__FUNCTION__);
+static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
+{
+       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 */
 
+/*
+ * Module parameter to control latency timer for NDI FTDI-based USB devices.
+ * If this value is not set in modprobe.conf.local its value will be set to 1ms.
+ */
+static int ndi_latency_timer = 1;
 
-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
- *   it is called when the usb device is disconnected
+/* Setup for the NDI FTDI-based USB devices, which requires hardwired
+ * baudrate (19200 gets mapped to 1200000).
  *
- *   usbserial:usb_serial_disconnect
- *      calls __serial_close for each open of the port
- *      shutdown is called then (ie ftdi_shutdown)
+ * Called from usbserial:serial_probe.
+ */
+static int ftdi_NDI_device_setup(struct usb_serial *serial)
+{
+       struct usb_device *udev = serial->dev;
+       int latency = ndi_latency_timer;
+       int rv = 0;
+       char buf[1];
+
+       if (latency == 0)
+               latency = 1;
+       if (latency > 99)
+               latency = 99;
+
+       dbg("%s setting NDI device latency to %d", __func__, latency);
+       dev_info(&udev->dev, "NDI device with a latency value of %d", latency);
+
+       rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
+                               FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
+                               latency, 0, buf, 0, WDR_TIMEOUT);
+       return 0;
+}
+
+/*
+ * 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]) {
+               dev_info(&udev->dev,
+                        "Ignoring serial port reserved for JTAG\n");
+               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 void ftdi_shutdown (struct usb_serial *serial)
+static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
 {
-       dbg("%s", __FUNCTION__);
+       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 = cpu_to_le16(0x40);
+               dev_info(&serial->dev->dev,
+                        "Fixing invalid wMaxPacketSize on read pipe\n");
+       }
+
+       return 0;
+}
+
+static void ftdi_sio_priv_release(struct kref *k)
+{
+       struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
+
+       kfree(priv);
 }
 
 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);
 
-       /* 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);
-       }
+       kref_put(&priv->kref, ftdi_sio_priv_release);
 
        return 0;
 }
 
-static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
+static int ftdi_open(struct tty_struct *tty,
+                       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);
@@ -1309,7 +1685,7 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
        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;
@@ -1318,8 +1694,10 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
        priv->rx_bytes = 0;
        spin_unlock_irqrestore(&priv->rx_lock, flags);
 
-       if (port->tty)
-               port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       if (tty)
+               tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+       write_latency_timer(port);
 
        /* No error checking for this (will get errors later anyway) */
        /* See ftdi_sio.h for description of what is reset */
@@ -1329,17 +1707,12 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
                        priv->interface, buf, 0, WDR_TIMEOUT);
 
        /* Termios defaults are set by usb_serial_init. We don't change
-          port->tty->termios - this would loose speed settings, etc.
+          port->tty->termios - this would lose speed settings, etc.
           This is same behaviour as serial.c/rs_open() - Kuba */
 
        /* ftdi_set_termios  will send usb control messages */
-       if (port->tty)
-               ftdi_set_termios(port, NULL);
-
-       /* FIXME: Flow control might be enabled, so it should be checked -
-          we have no control of defaults! */
-       /* Turn on RTS and DTR since we are not flow controlling by default */
-       set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       if (tty)
+               ftdi_set_termios(tty, port, tty->termios);
 
        /* Not throttled */
        spin_lock_irqsave(&priv->rx_lock, flags);
@@ -1349,18 +1722,46 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
        /* Start reading from the device */
        priv->rx_processed = 0;
        usb_fill_bulk_urb(port->read_urb, dev,
-                     usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
-                     port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-                     ftdi_read_bulk_callback, port);
+                       usb_rcvbulkpipe(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_KERNEL);
        if (result)
-               err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
-
+               dev_err(&port->dev,
+                       "%s - failed submitting read urb, error %d\n",
+                       __func__, result);
+       else
+               kref_get(&priv->kref);
 
        return result;
 } /* ftdi_open */
 
 
+static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       char buf[1];
+
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected) {
+               /* Disable flow control */
+               if (!on && 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) {
+                           dev_err(&port->dev, "error from flowcontrol urb\n");
+               }
+               /* drop RTS and DTR */
+               if (on)
+                       set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+               else
+                       clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+       }
+       mutex_unlock(&port->serial->disc_mutex);
+}
 
 /*
  * usbserial:__serial_close  only calls ftdi_close if the point is open
@@ -1370,35 +1771,19 @@ 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 void ftdi_close(struct usb_serial_port *port)
 { /* ftdi_close */
-       unsigned int c_cflag = port->tty->termios->c_cflag;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char buf[1];
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
-       if (c_cflag & HUPCL){
-               /* Disable flow control */
-               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 */
 
        /* cancel any scheduled reading */
-       cancel_delayed_work(&priv->rx_work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&priv->rx_work);
 
        /* shutdown our bulk read */
        usb_kill_urb(port->read_urb);
+       kref_put(&priv->kref, ftdi_sio_priv_release);
 } /* ftdi_close */
 
 
@@ -1410,7 +1795,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
  *
  * The new devices do not require this byte
  */
-static int ftdi_write (struct usb_serial_port *port,
+static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
                           const unsigned char *buf, int count)
 { /* ftdi_write */
        struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1421,7 +1806,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");
@@ -1430,52 +1815,55 @@ 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);
+       dbg("data_offset set to %d", data_offset);
 
        /* Determine total transfer size */
        transfer_size = count;
        if (data_offset > 0) {
                /* Original sio needs control bytes too... */
                transfer_size += (data_offset *
-                               ((count + (PKTSZ - 1 - data_offset)) /
-                                (PKTSZ - data_offset)));
+                               ((count + (priv->max_packet_size - 1 - data_offset)) /
+                                (priv->max_packet_size - data_offset)));
        }
 
-       buffer = kmalloc (transfer_size, GFP_ATOMIC);
+       buffer = kmalloc(transfer_size, GFP_ATOMIC);
        if (!buffer) {
-               err("%s ran out of kernel memory for urb ...", __FUNCTION__);
-               return -ENOMEM;
+               dev_err(&port->dev,
+                       "%s ran out of kernel memory for urb ...\n", __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;
+               dev_err(&port->dev, "%s - no more free urbs\n", __func__);
+               count = -ENOMEM;
+               goto error_no_urb;
        }
 
        /* Copy data */
        if (data_offset > 0) {
-               /* Original sio requires control byte at start of each packet. */
-               int user_pktsz = PKTSZ - data_offset;
+               /* Original sio requires control byte at start of
+                  each packet. */
+               int user_pktsz = priv->max_packet_size - data_offset;
                int todo = count;
                unsigned char *first_byte = buffer;
                const unsigned char *current_position = buf;
 
                while (todo > 0) {
-                       if (user_pktsz > todo) {
+                       if (user_pktsz > todo)
                                user_pktsz = todo;
-                       }
                        /* Write the control byte at the front of the packet*/
                        *first_byte = 1 | ((user_pktsz) << 2);
                        /* Copy data for packet */
-                       memcpy (first_byte + data_offset,
+                       memcpy(first_byte + data_offset,
                                current_position, user_pktsz);
                        first_byte += user_pktsz + data_offset;
                        current_position += user_pktsz;
@@ -1484,25 +1872,28 @@ static int ftdi_write (struct usb_serial_port *port,
        } else {
                /* No control byte required. */
                /* Copy in the data to send */
-               memcpy (buffer, buf, count);
+               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_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
-                     buffer, transfer_size,
-                     ftdi_write_bulk_callback, port);
+                       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);
+               dev_err(&port->dev,
+                       "%s - failed submitting write urb, error %d\n",
+                       __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);
@@ -1510,36 +1901,41 @@ 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)
+static void ftdi_write_bulk_callback(struct urb *urb)
 {
        unsigned long flags;
-       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial_port *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);
+       kfree(urb->transfer_buffer);
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
-
-       if (urb->status) {
-               dbg("nonzero write bulk status received: %d", urb->status);
-               return;
-       }
+       dbg("%s - port %d", __func__, port->number);
 
        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 */
@@ -1547,24 +1943,30 @@ static void ftdi_write_bulk_callback (struct urb *urb)
        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, priv->max_packet_size));
        }
        spin_lock_irqsave(&priv->tx_lock, flags);
        --priv->tx_outstanding_urbs;
        priv->tx_outstanding_bytes -= countback;
        spin_unlock_irqrestore(&priv->tx_lock, flags);
 
+       if (status) {
+               dbg("nonzero write bulk status received: %d", status);
+               return;
+       }
+
        usb_serial_port_softint(port);
 } /* ftdi_write_bulk_callback */
 
 
-static int ftdi_write_room( struct usb_serial_port *port )
+static int ftdi_write_room(struct tty_struct *tty)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(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) {
@@ -1579,83 +1981,87 @@ static int ftdi_write_room( struct usb_serial_port *port )
        }
        spin_unlock_irqrestore(&priv->tx_lock, flags);
        return room;
-} /* ftdi_write_room */
-
+}
 
-static int ftdi_chars_in_buffer (struct usb_serial_port *port)
-{ /* ftdi_chars_in_buffer */
+static int ftdi_chars_in_buffer(struct tty_struct *tty)
+{
+       struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(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__);
+               dev_err(&port->dev, "%s outstanding tx bytes is negative!\n",
+                       __func__);
                buffered = 0;
        }
        return buffered;
-} /* ftdi_chars_in_buffer */
-
-
+}
 
-static void ftdi_read_bulk_callback (struct urb *urb)
-{ /* ftdi_read_bulk_callback */
-       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+static void ftdi_read_bulk_callback(struct urb *urb)
+{
+       struct usb_serial_port *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__,
-                   urb->transfer_buffer_length, urb->actual_length, urb->number_of_packets );
-               err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags );
+               dev_err(&port->dev, "%s transfer_buffer_length %d "
+                       "actual_length %d number of packets %d\n", __func__,
+                       urb->transfer_buffer_length,
+                       urb->actual_length, urb->number_of_packets);
+               dev_err(&port->dev, "%s transfer_flags %x\n", __func__,
+                       urb->transfer_flags);
        }
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
-       if (port->open_count <= 0)
+       if (port->port.count <= 0)
                return;
 
-       tty = port->tty;
+       tty = tty_port_tty_get(&port->port);
        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__);
-               return;
+               dbg("%s - bad port private data pointer - exiting", __func__);
+               goto out;
        }
 
-       if (urb != port->read_urb) {
-               err("%s - Not my urb!", __FUNCTION__);
-       }
+       if (urb != port->read_urb)
+               dev_err(&port->dev, "%s - Not my urb!\n", __func__);
 
-       if (urb->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);
-               return;
+       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", status);
+               goto out;
        }
 
        /* count data bytes, but not status bytes */
        countread = urb->actual_length;
-       countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ);
+       countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size);
        spin_lock_irqsave(&priv->rx_lock, flags);
        priv->rx_bytes += countread;
        spin_unlock_irqrestore(&priv->rx_lock, flags);
 
        ftdi_process_read(&priv->rx_work.work);
-
+out:
+       tty_kref_put(tty);
 } /* ftdi_read_bulk_callback */
 
 
-static void ftdi_process_read (struct work_struct *work)
+static void ftdi_process_read(struct work_struct *work)
 { /* ftdi_process_read */
        struct ftdi_private *priv =
                container_of(work, struct ftdi_private, rx_work.work);
@@ -1671,42 +2077,42 @@ static void ftdi_process_read (struct work_struct *work)
        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)
+       if (port->port.count <= 0)
                return;
 
-       tty = port->tty;
+       tty = tty_port_tty_get(&port->port);
        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__);
-               return;
+               dbg("%s - bad port private data pointer - exiting", __func__);
+               goto out;
        }
 
        urb = port->read_urb;
        if (!urb) {
-               dbg("%s - bad read_urb pointer - exiting", __FUNCTION__);
-               return;
+               dbg("%s - bad read_urb pointer - exiting", __func__);
+               goto out;
        }
 
        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);
-               } else {
-                       dbg("Status only: %03oo %03oo",data[0],data[1]);
-               }
+               if (urb->actual_length > 2)
+                       usb_serial_debug_data(debug, &port->dev, __func__,
+                                               urb->actual_length, data);
+               else
+                       dbg("Status only: %03oo %03oo", data[0], data[1]);
        }
 
 
@@ -1716,56 +2122,60 @@ static void ftdi_process_read (struct work_struct *work)
        /* if CD is dropped and the line is not CLOCAL then we should hangup */
 
        need_flip = 0;
-       for (packet_offset = priv->rx_processed; packet_offset < urb->actual_length; packet_offset += PKTSZ) {
+       for (packet_offset = priv->rx_processed;
+               packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
                int length;
 
-               /* Compare new line status to the old one, signal if different */
-               /* N.B. packet may be processed more than once, but differences
-                * are only processed once.  */
-               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;
-                       }
+               /* Compare new line status to the old one, signal if different/
+                  N.B. packet may be processed more than once, but differences
+                  are only processed once.  */
+               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;
                }
 
-               length = min(PKTSZ, urb->actual_length-packet_offset)-2;
+               length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2;
                if (length < 0) {
-                       err("%s - bad packet length: %d", __FUNCTION__, length+2);
+                       dev_err(&port->dev, "%s - bad packet length: %d\n",
+                               __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__);
+                       /* break out & wait for throttling/unthrottling to
+                          happen */
+                       dbg("%s - receive room low", __func__);
                        break;
                }
 
                /* 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  */
+               /* 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 ) {
+               if (data[packet_offset+1] & FTDI_RS_OE) {
                        error_flag = TTY_OVERRUN;
                        dbg("OVERRRUN error");
                }
-               if ( data[packet_offset+1] & FTDI_RS_BI ) {
+               if (data[packet_offset+1] & FTDI_RS_BI) {
                        error_flag = TTY_BREAK;
                        dbg("BREAK received");
+                       usb_serial_handle_break(port);
                }
-               if ( data[packet_offset+1] & FTDI_RS_PE ) {
+               if (data[packet_offset+1] & FTDI_RS_PE) {
                        error_flag = TTY_PARITY;
                        dbg("PARITY error");
                }
-               if ( data[packet_offset+1] & FTDI_RS_FE ) {
+               if (data[packet_offset+1] & FTDI_RS_FE) {
                        error_flag = TTY_FRAME;
                        dbg("FRAMING error");
                }
@@ -1774,7 +2184,11 @@ static void ftdi_process_read (struct work_struct *work)
                                /* 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);
+                               if (!usb_serial_handle_sysrq_char(tty, port,
+                                               data[packet_offset + i]))
+                                       tty_insert_flip_char(tty,
+                                               data[packet_offset + i],
+                                               error_flag);
                        }
                        need_flip = 1;
                }
@@ -1782,19 +2196,19 @@ static void ftdi_process_read (struct work_struct *work)
 #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.
+                  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){
+                       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) {
+                               /* 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);
                                need_flip = 1;
                        }
@@ -1803,15 +2217,14 @@ static void ftdi_process_read (struct work_struct *work)
        } /* "for(packet_offset=0..." */
 
        /* Low latency */
-       if (need_flip) {
+       if (need_flip)
                tty_flip_buffer_push(tty);
-       }
 
        if (packet_offset < urb->actual_length) {
                /* 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);
@@ -1819,42 +2232,46 @@ static void ftdi_process_read (struct work_struct *work)
                        priv->rx_flags |= ACTUALLY_THROTTLED;
                        spin_unlock_irqrestore(&priv->rx_lock, flags);
                        dbg("%s - deferring remainder until unthrottled",
-                                       __FUNCTION__);
-                       return;
+                                       __func__);
+                       goto out;
                }
                spin_unlock_irqrestore(&priv->rx_lock, flags);
                /* if the port is closed stop trying to read */
-               if (port->open_count > 0){
+               if (port->port.count > 0)
                        /* delay processing of remainder */
                        schedule_delayed_work(&priv->rx_work, 1);
-               } else {
-                       dbg("%s - port is closed", __FUNCTION__);
-               }
-               return;
+               else
+                       dbg("%s - port is closed", __func__);
+               goto out;
        }
 
        /* urb is completely processed */
        priv->rx_processed = 0;
 
        /* if the port is closed stop trying to read */
-       if (port->open_count > 0){
+       if (port->port.count > 0) {
                /* Continue trying to always read  */
                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);
+                       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);
+                       dev_err(&port->dev,
+                               "%s - failed resubmitting read urb, error %d\n",
+                               __func__, result);
        }
-
-       return;
+out:
+       tty_kref_put(tty);
 } /* ftdi_process_read */
 
 
-static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
+static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        __u16 urb_value = 0;
        char buf[1];
@@ -1863,22 +2280,23 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
        /* see drivers/char/tty_io.c to see it used */
        /* last_set_data_urb_value NEVER has the break bit set in it */
 
-       if (break_state) {
+       if (break_state)
                urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;
-       } else {
+       else
                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_TYPE,
-                           urb_value , priv->interface,
-                           buf, 0, WDR_TIMEOUT) < 0) {
-               err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
+       if (usb_control_msg(port->serial->dev,
+                       usb_sndctrlpipe(port->serial->dev, 0),
+                       FTDI_SIO_SET_DATA_REQUEST,
+                       FTDI_SIO_SET_DATA_REQUEST_TYPE,
+                       urb_value , priv->interface,
+                       buf, 0, WDR_TIMEOUT) < 0) {
+               dev_err(&port->dev, "%s FAILED to enable/disable break state "
+                       "(state was %d)\n", __func__, break_state);
        }
 
-       dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
+       dbg("%s break state is %d - urb is %d", __func__,
+                                               break_state, urb_value);
 
 }
 
@@ -1888,45 +2306,50 @@ 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 ktermios *old_termios)
+static void ftdi_set_termios(struct tty_struct *tty,
+               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 = 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;
+       /* Added for xon/xoff support */
+       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;
+       /* Force baud rate if this device requires it, unless it is set to
+          B0. */
+       if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
+               dbg("%s: forcing baud rate for this device", __func__);
+               tty_encode_baud_rate(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
           compare old_termios and tty->termios */
        /* NOTE These routines can get interrupted by
-          ftdi_sio_read_bulk_callback  - need to examine what this
-           means - don't see any problems yet */
+          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);
@@ -1941,12 +2364,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
                case CS7: urb_value |= 7; dbg("Setting CS7"); break;
                case CS8: urb_value |= 8; dbg("Setting CS8"); break;
                default:
-                       err("CSIZE was set but not CS5-CS8");
+                       dev_err(&port->dev, "CSIZE was set but not CS5-CS8\n");
                }
        }
 
-       /* This is needed by the break command since it uses the same command - but is
-         or'ed with this value  */
+       /* 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),
@@ -1954,61 +2377,68 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
                            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__);
+               dev_err(&port->dev, "%s FAILED to set "
+                       "databits/stopbits/parity\n", __func__);
        }
 
        /* Now do the baudrate */
-       if ((cflag & CBAUD) == B0 ) {
+       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_TYPE,
                                    0, priv->interface,
                                    buf, 0, WDR_TIMEOUT) < 0) {
-                       err("%s error from disable flowcontrol urb", __FUNCTION__);
+                       dev_err(&port->dev,
+                               "%s error from disable flowcontrol urb\n",
+                               __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__);
-               }
+               if (change_speed(tty, port))
+                       dev_err(&port->dev, "%s urb failed to set baudrate\n",
+                               __func__);
                /* Ensure RTS and DTR are raised when baudrate changed from 0 */
-               if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) {
+               if (!old_termios || (old_termios->c_cflag & CBAUD) == B0)
                        set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-               }
        }
 
        /* 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__);
+               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_TYPE,
                                    0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
                                    buf, 0, WDR_TIMEOUT) < 0) {
-                       err("urb failed to set to rts/cts flow control");
+                       dev_err(&port->dev,
+                               "urb failed to set to rts/cts flow control\n");
                }
 
        } else {
                /*
                 * 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.
-               */
+                * 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);
+                       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 = termios->c_cc[VSTART];
+                       vstop = termios->c_cc[VSTOP];
+                       urb_value = (vstop << 8) | (vstart);
 
                        if (usb_control_msg(dev,
                                            usb_sndctrlpipe(dev, 0),
@@ -2017,67 +2447,69 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
                                            urb_value , (FTDI_SIO_XON_XOFF_HS
                                                         | priv->interface),
                                            buf, 0, WDR_TIMEOUT) < 0) {
-                               err("urb failed to set to xon/xoff flow control");
+                               dev_err(&port->dev, "urb failed to set to "
+                                       "xon/xoff flow control\n");
                        }
                } 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__);
+                       /* else clause to only run if cflag ! CRTSCTS and iflag
+                        * ! XOFF. CHECKME Assuming XON/XOFF handled by tty
+                        * stack - not by device */
+                       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_TYPE,
                                            0, priv->interface,
                                            buf, 0, WDR_TIMEOUT) < 0) {
-                               err("urb failed to clear flow control");
+                               dev_err(&port->dev,
+                                       "urb failed to clear flow control\n");
                        }
                }
 
        }
        return;
-} /* ftdi_termios */
-
+}
 
-static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
+static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        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,
-                                          usb_rcvctrlpipe(port->serial->dev, 0),
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST,
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                                          0, 0,
-                                          buf, 1, WDR_TIMEOUT)) < 0 ) {
-                       err("%s Could not get modem status of device - err: %d", __FUNCTION__,
-                           ret);
-                       return(ret);
-               }
+               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_TYPE,
+                          0, 0,
+                          buf, 1, WDR_TIMEOUT);
+               if (ret < 0)
+                       return ret;
                break;
        case FT8U232AM:
        case FT232BM:
        case FT2232C:
-               /* 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,
-                                          usb_rcvctrlpipe(port->serial->dev, 0),
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST,
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                                          0, priv->interface,
-                                          buf, 2, WDR_TIMEOUT)) < 0 ) {
-                       err("%s Could not get modem status of device - err: %d", __FUNCTION__,
-                           ret);
-                       return(ret);
-               }
+       case FT232RL:
+       case FT2232H:
+       case FT4232H:
+               /* 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 */
+               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_TYPE,
+                                  0, priv->interface,
+                                  buf, 2, WDR_TIMEOUT);
+               if (ret < 0)
+                       return ret;
                break;
        default:
                return -EFAULT;
-               break;
        }
 
        return  (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
@@ -2087,27 +2519,33 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
                priv->last_dtr_rts;
 }
 
-static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
+static int ftdi_tiocmset(struct tty_struct *tty, struct file *file,
+                       unsigned int set, unsigned int clear)
 {
-       dbg("%s TIOCMSET", __FUNCTION__);
+       struct usb_serial_port *port = tty->driver_data;
+       dbg("%s TIOCMSET", __func__);
        return update_mctrl(port, set, clear);
 }
 
 
-static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+static int ftdi_ioctl(struct tty_struct *tty, struct file *file,
+                                       unsigned int cmd, unsigned long arg)
 {
+       struct usb_serial_port *port = tty->driver_data;
        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) {
 
        case TIOCGSERIAL: /* gets serial port data */
-               return get_serial_info(port, (struct serial_struct __user *) arg);
+               return get_serial_info(port,
+                                       (struct serial_struct __user *) arg);
 
        case TIOCSSERIAL: /* sets serial port data */
-               return set_serial_info(port, (struct serial_struct __user *) arg);
+               return set_serial_info(tty, port,
+                                       (struct serial_struct __user *) arg);
 
        /*
         * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
@@ -2126,49 +2564,45 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
                        else {
                                char diff = priv->diff_status;
 
-                               if (diff == 0) {
+                               if (diff == 0)
                                        return -EIO; /* no change => error */
-                               }
 
                                /* Consume all events */
                                priv->diff_status = 0;
 
-                               /* Return 0 if caller wanted to know about these bits */
-                               if ( ((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) ||
-                                    ((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) ||
-                                    ((arg & TIOCM_CD)  && (diff & FTDI_RS0_RLSD)) ||
-                                    ((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS)) ) {
+                               /* Return 0 if caller wanted to know about
+                                  these bits */
+                               if (((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) ||
+                                   ((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) ||
+                                   ((arg & TIOCM_CD)  && (diff & FTDI_RS0_RLSD)) ||
+                                   ((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS))) {
                                        return 0;
                                }
                                /*
-                                * Otherwise caller can't care less about what happened,
-                                * and so we continue to wait for more events.
+                                * Otherwise caller can't care less about what
+                                * happened,and so we continue to wait for more
+                                * events.
                                 */
                        }
                }
-               return(0);
-               break;
+               return 0;
        default:
                break;
-
        }
-
-
-       /* This is not necessarily an error - turns out the higher layers will do
-        *  some ioctls itself (see comment above)
+       /* This is not necessarily an error - turns out the higher layers
+        * will do some ioctls themselves (see comment above)
         */
-       dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
-
-       return(-ENOIOCTLCMD);
-} /* ftdi_ioctl */
-
+       dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __func__, cmd);
+       return -ENOIOCTLCMD;
+}
 
-static void ftdi_throttle (struct usb_serial_port *port)
+static void ftdi_throttle(struct tty_struct *tty)
 {
+       struct usb_serial_port *port = tty->driver_data;
        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;
@@ -2176,13 +2610,14 @@ static void ftdi_throttle (struct usb_serial_port *port)
 }
 
 
-static void ftdi_unthrottle (struct usb_serial_port *port)
+static void ftdi_unthrottle(struct tty_struct *tty)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(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;
@@ -2193,11 +2628,11 @@ static void ftdi_unthrottle (struct usb_serial_port *port)
                schedule_delayed_work(&priv->rx_work, 0);
 }
 
-static int __init ftdi_init (void)
+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;
@@ -2214,7 +2649,8 @@ static int __init ftdi_init (void)
        if (retval)
                goto failed_usb_register;
 
-       info(DRIVER_VERSION ":" DRIVER_DESC);
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+              DRIVER_DESC "\n");
        return 0;
 failed_usb_register:
        usb_serial_deregister(&ftdi_sio_device);
@@ -2223,13 +2659,13 @@ failed_sio_register:
 }
 
 
-static void __exit ftdi_exit (void)
+static void __exit ftdi_exit(void)
 {
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
 
-       usb_deregister (&ftdi_driver);
-       usb_serial_deregister (&ftdi_sio_device);
+       usb_deregister(&ftdi_driver);
+       usb_serial_deregister(&ftdi_sio_device);
 
 }
 
@@ -2237,8 +2673,8 @@ static void __exit ftdi_exit (void)
 module_init(ftdi_init);
 module_exit(ftdi_exit);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
@@ -2247,5 +2683,7 @@ module_param(vendor, ushort, 0);
 MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
                __MODULE_STRING(FTDI_VID)")");
 module_param(product, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified product ID");
+MODULE_PARM_DESC(product, "User specified product ID");
 
+module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override");