fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / usb / serial / io_ti.c
index 4c87da4..980285c 100644 (file)
  *     (at your option) any later version.
  *
  * Supports the following devices:
- *     EP/1 EP/2 EP/4
+ *     EP/1 EP/2 EP/4 EP/21 EP/22 EP/221 EP/42 EP/421 WATCHPORT
+ *
+ * For questions or problems with this driver, contact Inside Out
+ * Networks technical support, or Peter Berger <pberger@brimson.com>,
+ * or Al Borchers <alborchers@steinerpoint.com>.
  *
  * Version history:
  *
@@ -20,7 +24,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
 #include <linux/errno.h>
 #include <linux/serial.h>
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 #include <linux/usb.h>
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
-       static int debug = 1;
-#else
-       static int debug;
-#endif
-
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
 
 #include "io_16654.h"
 #include "io_usbvend.h"
@@ -51,7 +48,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.2"
+#define DRIVER_VERSION "v0.7"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
 #define DRIVER_DESC "Edgeport USB Serial Driver"
 
@@ -79,6 +76,16 @@ struct edgeport_uart_buf_desc {
 #define TI_MODE_DOWNLOAD       2   // Made it to download mode
 #define TI_MODE_TRANSITIONING  3   // Currently in boot mode but transitioning to download mode
 
+/* read urb state */
+#define EDGE_READ_URB_RUNNING  0
+#define EDGE_READ_URB_STOPPING 1
+#define EDGE_READ_URB_STOPPED  2
+
+#define EDGE_LOW_LATENCY       1
+#define EDGE_CLOSING_WAIT      4000    /* in .01 sec */
+
+#define EDGE_OUT_BUF_SIZE      1024
+
 
 /* Product information read from the Edgeport */
 struct product_info
@@ -87,6 +94,13 @@ struct product_info
        __u8    hardware_type;          // Type of hardware
 } __attribute__((packed));
 
+/* circular buffer */
+struct edge_buf {
+       unsigned int    buf_size;
+       char            *buf_buf;
+       char            *buf_get;
+       char            *buf_put;
+};
 
 struct edgeport_port {
        __u16 uart_base;
@@ -108,12 +122,18 @@ struct edgeport_port {
                                                   happen */
        struct edgeport_serial  *edge_serial;
        struct usb_serial_port  *port;
+       __u8 bUartMode;         /* Port type, 0: RS232, etc. */ 
+       spinlock_t ep_lock;
+       int ep_read_urb_state;
+       int ep_write_urb_in_use;
+       struct edge_buf *ep_out_buf;
 };
 
 struct edgeport_serial {
        struct product_info product_info;
        u8 TI_I2C_Type;                 // Type of I2C in UMP
        u8 TiReadI2C;                   // Set to TRUE if we have read the I2c in Boot Mode
+       struct semaphore es_sem;
        int num_ports_open;
        struct usb_serial *serial;
 };
@@ -122,6 +142,21 @@ struct edgeport_serial {
 /* Devices that this driver supports */
 static struct usb_device_id edgeport_1port_id_table [] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) },
        { }
 };
 
@@ -130,56 +165,93 @@ static struct usb_device_id edgeport_2port_id_table [] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) },
+// The 4-port shows up as two 2-port devices
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) },
        { }
 };
 
 /* Devices that this driver supports */
 static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
-       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) },
+       { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) },
        { }
 };
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 static struct usb_driver io_driver = {
-       .owner =        THIS_MODULE,
        .name =         "io_ti",
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table_combined,
+       .no_dynamic_id =        1,
 };
 
 
 static struct EDGE_FIRMWARE_VERSION_INFO OperationalCodeImageVersion;
 
+static int debug;
+
 static int TIStayInBootMode = 0;
+static int low_latency = EDGE_LOW_LATENCY;
+static int closing_wait = EDGE_CLOSING_WAIT;
 static int ignore_cpu_rev = 0;
 
 
+static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length);
+
+static void stop_read(struct edgeport_port *edge_port);
+static int restart_read(struct edgeport_port *edge_port);
+
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
+static void edge_send(struct usb_serial_port *port);
+
+/* circular buffer */
+static struct edge_buf *edge_buf_alloc(unsigned int size);
+static void edge_buf_free(struct edge_buf *eb);
+static void edge_buf_clear(struct edge_buf *eb);
+static unsigned int edge_buf_data_avail(struct edge_buf *eb);
+static unsigned int edge_buf_space_avail(struct edge_buf *eb);
+static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
+       unsigned int count);
+static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
+       unsigned int count);
 
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);
 
 static int TIReadVendorRequestSync (struct usb_device *dev,
                                __u8            request,
@@ -200,7 +272,7 @@ static int TIReadVendorRequestSync (struct usb_device *dev,
                                index,
                                data,
                                size,
-                               HZ);
+                               1000);
        if (status < 0)
                return status;
        if (status != size) {
@@ -230,8 +302,7 @@ static int TISendVendorRequestSync (struct usb_device *dev,
                                index,
                                data,
                                size,
-                               HZ);
-
+                               1000);
        if (status < 0)
                return status;
        if (status != size) {
@@ -255,7 +326,6 @@ static int TIWriteCommandSync (struct usb_device *dev, __u8 command,
 
 }
 
-
 /* clear tx/rx buffers and fifo in TI UMP */
 static int TIPurgeDataSync (struct usb_serial_port *port, __u16 mask)
 {
@@ -279,12 +349,12 @@ static int TIPurgeDataSync (struct usb_serial_port *port, __u16 mask)
  * @address_type: Can read both XDATA and I2C
  * @buffer: pointer to input data buffer
  */
-int TIReadDownloadMemory (struct usb_device *dev, int start_address, int length,
-                         __u8 address_type, __u8 *buffer)
+static int TIReadDownloadMemory(struct usb_device *dev, int start_address,
+                               int length, __u8 address_type, __u8 *buffer)
 {
        int status = 0;
        __u8 read_length;
-       __u16 be_start_address;
+       __be16 be_start_address;
        
        dbg ("%s - @ %x for %d", __FUNCTION__, start_address, length);
 
@@ -305,7 +375,7 @@ int TIReadDownloadMemory (struct usb_device *dev, int start_address, int length,
                status = TIReadVendorRequestSync (dev,
                                                  UMPC_MEMORY_READ,     // Request
                                                  (__u16)address_type,  // wValue (Address type)
-                                                 be_start_address,     // wIndex (Address to read)
+                                                 (__force __u16)be_start_address,      // wIndex (Address to read)
                                                  buffer,               // TransferBuffer
                                                  read_length); // TransferBufferLength
 
@@ -315,8 +385,8 @@ int TIReadDownloadMemory (struct usb_device *dev, int start_address, int length,
                }
 
                if (read_length > 1) {
-                       usb_serial_debug_data (__FILE__, __FUNCTION__,
-                                              read_length, buffer);
+                       usb_serial_debug_data(debug, &dev->dev, __FUNCTION__,
+                                             read_length, buffer);
                }
 
                /* Update pointers/length */
@@ -328,7 +398,7 @@ int TIReadDownloadMemory (struct usb_device *dev, int start_address, int length,
        return status;
 }
 
-int TIReadRam (struct usb_device *dev, int start_address, int length, __u8 *buffer)
+static int TIReadRam (struct usb_device *dev, int start_address, int length, __u8 *buffer)
 {
        return TIReadDownloadMemory (dev,
                                     start_address,
@@ -357,7 +427,7 @@ static int TIReadBootMemory (struct edgeport_serial *serial, int start_address,
        }
 
        dbg ("%s - start_address = %x, length = %d", __FUNCTION__, start_address, length);
-       usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
+       usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, length, buffer);
 
        serial->TiReadI2C = 1;
 
@@ -390,7 +460,7 @@ static int TIWriteBootMemory (struct edgeport_serial *serial, int start_address,
        }
 
        dbg ("%s - start_sddr = %x, length = %d", __FUNCTION__, start_address, length);
-       usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
+       usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, length, buffer);
 
        return status;
 }
@@ -401,7 +471,7 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
 {
        int status = 0;
        int write_length;
-       __u16 be_start_address;
+       __be16 be_start_address;
 
        /* We can only send a maximum of 1 aligned byte page at a time */
        
@@ -412,14 +482,14 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
                write_length = length;
 
        dbg ("%s - BytesInFirstPage Addr = %x, length = %d", __FUNCTION__, start_address, write_length);
-       usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer);
+       usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, write_length, buffer);
 
        /* Write first page */
        be_start_address = cpu_to_be16 (start_address);
        status = TISendVendorRequestSync (serial->serial->dev,
                                        UMPC_MEMORY_WRITE,      // Request
                                        (__u16)address_type,    // wValue
-                                       be_start_address,       // wIndex
+                                       (__force __u16)be_start_address,        // wIndex
                                        buffer,                 // TransferBuffer
                                        write_length);
        if (status) {
@@ -439,18 +509,18 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
                        write_length = length;
 
                dbg ("%s - Page Write Addr = %x, length = %d", __FUNCTION__, start_address, write_length);
-               usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer);
+               usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, write_length, buffer);
 
                /* Write next page */
                be_start_address = cpu_to_be16 (start_address);
                status = TISendVendorRequestSync (serial->serial->dev,
                                                UMPC_MEMORY_WRITE,      // Request
                                                (__u16)address_type,    // wValue
-                                               be_start_address,       // wIndex
+                                               (__force __u16)be_start_address,        // wIndex
                                                buffer,                 // TransferBuffer
                                                write_length);          // TransferBufferLength
                if (status) {
-                       dbg ("%s - ERROR %d", __FUNCTION__, status);
+                       dev_err (&serial->serial->dev->dev, "%s - ERROR %d\n", __FUNCTION__, status);
                        return status;
                }
                
@@ -524,74 +594,54 @@ exit_is_tx_active:
        return bytes_left;
 }
 
-static void TIChasePort(struct edgeport_port *port)
+static void TIChasePort(struct edgeport_port *port, unsigned long timeout, int flush)
 {
-       int loops;
-       int last_count;
-       int write_size;
-
-restart_tx_loop:
-       // Base the LoopTime on the baud rate
-       if (port->baud_rate == 0)
-               port->baud_rate = 1200;
-
-       write_size = port->tx.count;
-       loops = max(100, (100*write_size)/(port->baud_rate/10));
-       dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__,
-            write_size, port->baud_rate, loops);
-
-       while (1) {
-               // Save Last count
-               last_count = port->tx.count;
-
-               dbg ("%s - Tx Buffer Size = %d loops = %d", __FUNCTION__,
-                    last_count, loops);
-
-               /* Is the Edgeport Buffer empty? */
-               if (port->tx.count == 0)
+       int baud_rate;
+       struct tty_struct *tty = port->port->tty;
+       wait_queue_t wait;
+       unsigned long flags;
+
+       if (!timeout)
+               timeout = (HZ*EDGE_CLOSING_WAIT)/100;
+
+       /* wait for data to drain from the buffer */
+       spin_lock_irqsave(&port->ep_lock, flags);
+       init_waitqueue_entry(&wait, current);
+       add_wait_queue(&tty->write_wait, &wait);
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (edge_buf_data_avail(port->ep_out_buf) == 0
+               || timeout == 0 || signal_pending(current)
+               || !usb_get_intfdata(port->port->serial->interface))  /* disconnect */
                        break;
-
-               /* Block the thread for 10ms */
-               wait_ms (10);
-
-               if (last_count == port->tx.count) {
-                       /* No activity.. count down. */
-                       --loops;
-                       if (loops == 0) {
-                               dbg ("%s - Wait for TxEmpty - TIMEOUT",
-                                    __FUNCTION__);
-                               return;
-                       }
-               } else {
-                       /* Reset timeout value back to a minimum of 1 second */
-                       dbg ("%s - Wait for TxEmpty  Reset Count", __FUNCTION__);
-                       goto restart_tx_loop;
-               }
+               spin_unlock_irqrestore(&port->ep_lock, flags);
+               timeout = schedule_timeout(timeout);
+               spin_lock_irqsave(&port->ep_lock, flags);
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tty->write_wait, &wait);
+       if (flush)
+               edge_buf_clear(port->ep_out_buf);
+       spin_unlock_irqrestore(&port->ep_lock, flags);
+
+       /* wait for data to drain from the device */
+       timeout += jiffies;
+       while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
+       && usb_get_intfdata(port->port->serial->interface)) {  /* not disconnected */
+               if (!TIIsTxActive(port))
+                       break;
+               msleep(10);
        }
 
-       dbg ("%s - Local Tx Buffer Empty -- Waiting for TI UMP to EMPTY X/Y and FIFO",
-            __FUNCTION__);
-
-       write_size = TIIsTxActive (port);
-       loops = max(50, (100*write_size)/(port->baud_rate/10));
-       dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__, 
-            write_size, port->baud_rate, loops);
-
-       while (1) {
-               /* This function takes 4 ms; */
-               if (!TIIsTxActive (port)) {
-                       /* Delay a few char times */
-                       wait_ms (50);
-                       dbg ("%s - Empty", __FUNCTION__);
-                       return;
-               }
+       /* disconnected */
+       if (!usb_get_intfdata(port->port->serial->interface))
+               return;
 
-               --loops;
-               if (loops == 0) {
-                       dbg ("%s - TIMEOUT", __FUNCTION__);
-                       return;
-               }
-       }
+       /* wait one more character time, based on baud rate */
+       /* (TIIsTxActive doesn't seem to wait for the last byte) */
+       if ((baud_rate=port->baud_rate) == 0)
+               baud_rate = 50;
+       msleep(max(1,(10000+baud_rate-1)/baud_rate));
 }
 
 static int TIChooseConfiguration (struct usb_device *dev)
@@ -612,7 +662,7 @@ static int TIChooseConfiguration (struct usb_device *dev)
        return 0;
 }
 
-int TIReadRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
+static int TIReadRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
 {
        int status;
 
@@ -632,7 +682,7 @@ int TIReadRom (struct edgeport_serial *serial, int start_address, int length, __
        return status;
 }
 
-int TIWriteRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
+static int TIWriteRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
 {
        if (serial->product_info.TiMode == TI_MODE_BOOT)
                return TIWriteBootMemory (serial,
@@ -702,6 +752,7 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
        struct ti_i2c_desc *rom_desc;
        int start_address = 2;
        __u8 *buffer;
+       __u16 ttype;
 
        rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
        if (!rom_desc) {
@@ -715,12 +766,12 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
                return -ENOMEM;
        }
 
-       // Read the first byte (Signature0) must be 0x52
+       // Read the first byte (Signature0) must be 0x52 or 0x10
        status = TIReadRom (serial, 0, 1, buffer);
        if (status)
                goto ExitTiValidateI2cImage; 
 
-       if (*buffer != 0x52) {
+       if (*buffer != UMP5152 && *buffer != UMP3410) {
                dev_err (dev, "%s - invalid buffer signature\n", __FUNCTION__);
                status = -ENODEV;
                goto ExitTiValidateI2cImage;
@@ -744,7 +795,9 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
                dbg ("%s Type = 0x%x", __FUNCTION__, rom_desc->Type);
 
                // Skip type 2 record
-               if ((rom_desc->Type & 0x0f) != I2C_DESC_TYPE_FIRMWARE_BASIC) {
+               ttype = rom_desc->Type & 0x0f;
+               if ( ttype != I2C_DESC_TYPE_FIRMWARE_BASIC
+                       && ttype != I2C_DESC_TYPE_FIRMWARE_AUTO ) {
                        // Read the descriptor data
                        status = TIReadRom(serial,
                                                start_address+sizeof(struct ti_i2c_desc),
@@ -854,7 +907,7 @@ static int BuildI2CFirmwareHeader (__u8 *header, struct device *dev)
 
        memcpy (buffer + sizeof(struct ti_i2c_firmware_rec),
                &PagableOperationalCodeImage[sizeof(struct ti_i2c_image_header)],
-               img_header->Length);
+               le16_to_cpu(img_header->Length));
 
        for (i=0; i < buffer_size; i++) {
                cs = (__u8)(cs + buffer[i]);
@@ -892,7 +945,7 @@ static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial)
                dbg ("%s - read 2 status error = %d", __FUNCTION__, status);
        else
                dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
-       if ((!status) && data == 0x52) {
+       if ((!status) && (data == UMP5152 || data == UMP3410)) {
                dbg ("%s - ROM_TYPE_II", __FUNCTION__);
                serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
                return 0;
@@ -909,7 +962,7 @@ static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial)
                dbg ("%s - read 3 status error = %d", __FUNCTION__, status);
        else
                dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
-       if ((!status) && data == 0x52) {
+       if ((!status) && (data == UMP5152 || data == UMP3410)) {
                dbg ("%s - ROM_TYPE_III", __FUNCTION__);
                serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
                return 0;
@@ -930,7 +983,7 @@ static int TISendBulkTransferSync (struct usb_serial *serial, void *buffer, int
                                buffer,
                                length,
                                num_sent,
-                               HZ);
+                               1000);
        return status;
 }
 
@@ -995,9 +1048,9 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
        if (status)
                return status;
 
-       interface = &serial->serial->dev->config->interface[0]->altsetting->desc;
+       interface = &serial->serial->interface->cur_altsetting->desc;
        if (!interface) {
-               dev_err (&serial->serial->dev->dev, "%s - no interface set, error!", __FUNCTION__);
+               dev_err (dev, "%s - no interface set, error!\n", __FUNCTION__);
                return -ENODEV;
        }
 
@@ -1263,7 +1316,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
 
                        dbg ("%s - Update complete 0x%x", __FUNCTION__, status);
                        if (status) {
-                               dbg ("%s - UMPC_COPY_DNLD_TO_I2C failed", __FUNCTION__);
+                               dev_err (dev, "%s - UMPC_COPY_DNLD_TO_I2C failed\n", __FUNCTION__);
                                kfree (rom_desc);
                                kfree (ti_manuf_desc);
                                return status;
@@ -1287,9 +1340,9 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
        if (status)
                return status;
 
-       if (serial->serial->dev->descriptor.idVendor != USB_VENDOR_ID_ION) {
+       if (le16_to_cpu(serial->serial->dev->descriptor.idVendor) != USB_VENDOR_ID_ION) {
                dbg ("%s - VID = 0x%x", __FUNCTION__,
-                    serial->serial->dev->descriptor.idVendor);
+                    le16_to_cpu(serial->serial->dev->descriptor.idVendor));
                serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
                goto StayInBootMode;
        }
@@ -1370,7 +1423,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
                header = (struct ti_i2c_image_header *)buffer;
                
                // update length and checksum after padding
-               header->Length   = (__u16)(buffer_size - sizeof(struct ti_i2c_image_header));
+               header->Length   = cpu_to_le16((__u16)(buffer_size - sizeof(struct ti_i2c_image_header)));
                header->CheckSum = cs;
 
                // Download the operational code 
@@ -1574,6 +1627,7 @@ static __u8 MapLineStatus (__u8 ti_lsr)
 static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr)
 {
        struct async_icount *icount;
+       struct tty_struct *tty;
 
        dbg ("%s - %02x", __FUNCTION__, msr);
 
@@ -1595,6 +1649,17 @@ static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr)
        /* Save the new modem status */
        edge_port->shadow_msr = msr & 0xf0;
 
+       tty = edge_port->port->tty;
+       /* handle CTS flow control */
+       if (tty && C_CRTSCTS(tty)) {
+               if (msr & EDGEPORT_MSR_CTS) {
+                       tty->hw_stopped = 0;
+                       tty_wakeup(tty);
+               } else {
+                       tty->hw_stopped = 1;
+               }
+       }
+
        return;
 }
 
@@ -1616,10 +1681,8 @@ static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8
        }
 
        /* Place LSR data byte into Rx buffer */
-       if (lsr_data && edge_port->port->tty) {
-               tty_insert_flip_char(edge_port->port->tty, data, 0);
-               tty_flip_buffer_push(edge_port->port->tty);
-       }
+       if (lsr_data && edge_port->port->tty)
+               edge_tty_recv(&edge_port->port->dev, edge_port->port->tty, &data, 1);
 
        /* update input line counters */
        icount = &edge_port->icount;
@@ -1634,7 +1697,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8
 }
 
 
-static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_interrupt_callback (struct urb *urb)
 {
        struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
        struct usb_serial_port *port;
@@ -1649,10 +1712,6 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
 
        dbg("%s", __FUNCTION__);
 
-       if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
-               return;
-       }
-
        switch (urb->status) {
        case 0:
                /* success */
@@ -1664,7 +1723,7 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
                dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
                return;
        default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               dev_err(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status);
                goto exit;
        }
 
@@ -1673,7 +1732,7 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
                goto exit;
        }
                
-       usb_serial_debug_data (__FILE__, __FUNCTION__, length, data);
+       usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, length, data);
                
        if (length != 2) {
                dbg ("%s - expecting packet of size 2, got %d", __FUNCTION__, length);
@@ -1685,11 +1744,6 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
        dbg ("%s - port_number %d, function %d, info 0x%x",
             __FUNCTION__, port_number, function, data[1]);
        port = edge_serial->serial->port[port_number];
-       if (port_paranoia_check (port, __FUNCTION__)) {
-               dbg ("%s - change found for port that is not present",
-                    __FUNCTION__);
-               return;
-       }
        edge_port = usb_get_serial_port_data(port);
        if (!edge_port) {
                dbg ("%s - edge_port not found", __FUNCTION__);
@@ -1733,29 +1787,36 @@ exit:
                         __FUNCTION__, status);
 }
 
-static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_bulk_in_callback (struct urb *urb)
 {
        struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
        unsigned char *data = urb->transfer_buffer;
        struct tty_struct *tty;
-       int status;
-       int i;
+       int status = 0;
        int port_number;
 
        dbg("%s", __FUNCTION__);
 
-       if (port_paranoia_check (edge_port->port, __FUNCTION__))
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
                return;
+       default:
+               dev_err (&urb->dev->dev,"%s - nonzero read bulk status received: %d\n",
+                    __FUNCTION__, urb->status );
+       }
 
-       if (urb->status) {
-               dbg ("%s - nonzero read bulk status received: %d",
-                    __FUNCTION__, urb->status);
+       if (urb->status == -EPIPE)
+               goto exit;
 
-               if (urb->status == -EPIPE) {
-                       /* clear any problem that might have happened on this pipe */
-                       usb_clear_halt (edge_port->port->serial->dev, urb->pipe);
-                       goto exit;
-               }
+       if (urb->status) {
+               dev_err(&urb->dev->dev,"%s - stopping read!\n", __FUNCTION__);
                return;
        }
 
@@ -1773,68 +1834,77 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
 
        tty = edge_port->port->tty;
        if (tty && urb->actual_length) {
-               usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+               usb_serial_debug_data(debug, &edge_port->port->dev, __FUNCTION__, urb->actual_length, data);
 
                if (edge_port->close_pending) {
                        dbg ("%s - close is pending, dropping data on the floor.", __FUNCTION__);
                } else {
-                       for (i = 0; i < urb->actual_length ; ++i) {
-                               /* if we insert more than TTY_FLIPBUF_SIZE characters,
-                                * we drop them. */
-                               if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                                       tty_flip_buffer_push(tty);
-                               }
-                               /* this doesn't actually push the data through unless
-                                * tty->low_latency is set */
-                               tty_insert_flip_char(tty, data[i], 0);
-                       }
-                       tty_flip_buffer_push(tty);
+                       edge_tty_recv(&edge_port->port->dev, tty, data, urb->actual_length);
                }
                edge_port->icount.rx += urb->actual_length;
        }
 
 exit:
-       /* continue always trying to read */
-       status = usb_submit_urb (urb, GFP_ATOMIC);
+       /* continue read unless stopped */
+       spin_lock(&edge_port->ep_lock);
+       if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) {
+               urb->dev = edge_port->port->serial->dev;
+               status = usb_submit_urb(urb, GFP_ATOMIC);
+       } else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) {
+               edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED;
+       }
+       spin_unlock(&edge_port->ep_lock);
        if (status)
                dev_err (&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
                         __FUNCTION__, status);
 }
 
-static void edge_bulk_out_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length)
+{
+       int cnt;
+
+       do {
+               cnt = tty_buffer_request_room(tty, length);
+               if (cnt < length) {
+                       dev_err(dev, "%s - dropping data, %d bytes lost\n",
+                               __FUNCTION__, length - cnt);
+                       if(cnt == 0)
+                               break;
+               }
+               tty_insert_flip_string(tty, data, cnt);
+               data += cnt;
+               length -= cnt;
+       } while (length > 0);
+
+       tty_flip_buffer_push(tty);
+}
+
+static void edge_bulk_out_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-       struct tty_struct *tty;
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 
        dbg ("%s - port %d", __FUNCTION__, port->number);
 
-       if (!serial) {
-               dbg ("%s - bad serial pointer, exiting", __FUNCTION__);
-               return;
-       }
-
-       if (urb->status) {
-               dbg ("%s - nonzero write bulk status received: %d",
-                    __FUNCTION__, urb->status);
+       edge_port->ep_write_urb_in_use = 0;
 
-               if (urb->status == -EPIPE) {
-                       /* clear any problem that might have happened on this pipe */
-                       usb_clear_halt (serial->dev, urb->pipe);
-               }
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
                return;
+       default:
+               dev_err (&urb->dev->dev,"%s - nonzero write bulk status received: %d\n",
+                    __FUNCTION__, urb->status);
        }
 
-       tty = port->tty;
-       if (tty) {
-               /* let the tty driver wakeup if it has a special write_wakeup function */
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-                       (tty->ldisc.write_wakeup)(tty);
-               }
-
-               /* tell the tty driver that something has changed */
-               wake_up_interruptible(&tty->write_wait);
-       }
+       /* send any buffered data */
+       edge_send(port);
 }
 
 static int edge_open (struct usb_serial_port *port, struct file * filp)
@@ -1848,19 +1918,13 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
        u16 open_settings;
        u8 transaction_timeout;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return -ENODEV;
-       
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (edge_port == NULL)
                return -ENODEV;
 
-       /* force low_latency on so that our tty_push actually forces the data through, 
-          otherwise it is scheduled, and with high data rates (like with OHCI) data
-          can get lost. */
        if (port->tty)
-               port->tty->low_latency = 1;
+               port->tty->low_latency = low_latency;
 
        port_number = port->number - port->serial->minor;
        switch (port_number) {
@@ -1887,8 +1951,11 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
 
        /* turn off loopback */
        status = TIClearLoopBack (edge_port);
-       if (status)
+       if (status) {
+               dev_err(&port->dev,"%s - cannot send clear loopback command, %d\n",
+                       __FUNCTION__, status);
                return status;
+       }
        
        /* set up the port settings */
        edge_set_termios (port, NULL);
@@ -1914,8 +1981,10 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
                                        open_settings,
                                        NULL,
                                        0);
-       if (status)
+       if (status) {
+               dev_err(&port->dev,"%s - cannot send open command, %d\n", __FUNCTION__, status);
                return status;
+       }
 
        /* Start the DMA? */
        status = TIWriteCommandSync (dev,
@@ -1924,13 +1993,17 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
                                        0,
                                        NULL,
                                        0);
-       if (status)
+       if (status) {
+               dev_err(&port->dev,"%s - cannot send start DMA command, %d\n", __FUNCTION__, status);
                return status;
+       }
 
        /* Clear TX and RX buffers in UMP */
        status = TIPurgeDataSync (port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN);
-       if (status)
+       if (status) {
+               dev_err(&port->dev,"%s - cannot send clear buffers command, %d\n", __FUNCTION__, status);
                return status;
+       }
 
        /* Read Initial MSR */
        status = TIReadVendorRequestSync (dev,
@@ -1939,18 +2012,27 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
                                        (__u16)(UMPM_UART1_PORT + port_number), // wIndex (Address)
                                        &edge_port->shadow_msr,                 // TransferBuffer
                                        1);                                     // TransferBufferLength
-       if (status)
+       if (status) {
+               dev_err(&port->dev,"%s - cannot send read MSR command, %d\n", __FUNCTION__, status);
                return status;
+       }
 
        dbg ("ShadowMSR 0x%X", edge_port->shadow_msr);
  
+       /* Set Initial MCR */
+       edge_port->shadow_mcr = MCR_RTS | MCR_DTR;
+       dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr);
+
        edge_serial = edge_port->edge_serial;
+       if (down_interruptible(&edge_serial->es_sem))
+               return -ERESTARTSYS;
        if (edge_serial->num_ports_open == 0) {
                /* we are the first port to be opened, let's post the interrupt urb */
                urb = edge_serial->serial->port[0]->interrupt_in_urb;
                if (!urb) {
                        dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__);
-                       return -EINVAL;
+                       status = -EINVAL;
+                       goto up_es_sem;
                }
                urb->complete = edge_interrupt_callback;
                urb->context = edge_serial;
@@ -1958,7 +2040,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
                status = usb_submit_urb (urb, GFP_KERNEL);
                if (status) {
                        dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
-                       return status;
+                       goto up_es_sem;
                }
        }
 
@@ -1973,83 +2055,85 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
        urb = port->read_urb;
        if (!urb) {
                dev_err (&port->dev, "%s - no read urb present, exiting\n", __FUNCTION__);
-               return -EINVAL;
+               status = -EINVAL;
+               goto unlink_int_urb;
        }
+       edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
        urb->complete = edge_bulk_in_callback;
        urb->context = edge_port;
        urb->dev = dev;
        status = usb_submit_urb (urb, GFP_KERNEL);
        if (status) {
                dev_err (&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status);
-               return status;
+               goto unlink_int_urb;
        }
 
        ++edge_serial->num_ports_open;
 
        dbg("%s - exited", __FUNCTION__);
 
-       return 0;
+       goto up_es_sem;
+
+unlink_int_urb:
+       if (edge_port->edge_serial->num_ports_open == 0)
+               usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
+up_es_sem:
+       up(&edge_serial->es_sem);
+       return status;
 }
 
-static void edge_close (struct usb_serial_port *port, struct file * filp)
+static void edge_close (struct usb_serial_port *port, struct file *filp)
 {
-       struct usb_serial *serial;
        struct edgeport_serial *edge_serial;
        struct edgeport_port *edge_port;
        int port_number;
        int status;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return;
-       
        dbg("%s - port %d", __FUNCTION__, port->number);
                         
-       serial = get_usb_serial (port, __FUNCTION__);
-       if (!serial)
-               return;
-       
-       edge_serial = usb_get_serial_data(serial);
+       edge_serial = usb_get_serial_data(port->serial);
        edge_port = usb_get_serial_port_data(port);
        if ((edge_serial == NULL) || (edge_port == NULL))
                return;
        
-       if (serial->dev) {
-               /* The bulkreadcompletion routine will check 
-                * this flag and dump add read data */
-               edge_port->close_pending = 1;
-
-               /* chase the port close */
-               TIChasePort (edge_port);
-
-               usb_unlink_urb (port->read_urb);
-
-               /* assuming we can still talk to the device,
-                * send a close port command to it */
-               dbg("%s - send umpc_close_port", __FUNCTION__);
-               port_number = port->number - port->serial->minor;
-               status = TIWriteCommandSync (port->serial->dev,
-                                            UMPC_CLOSE_PORT,
-                                            (__u8)(UMPM_UART1_PORT + port_number),
-                                            0,
-                                            NULL,
-                                            0);
-               --edge_port->edge_serial->num_ports_open;
-               if (edge_port->edge_serial->num_ports_open <= 0) {
-                       /* last port is now closed, let's shut down our interrupt urb */
-                       usb_unlink_urb (serial->port[0]->interrupt_in_urb);
-                       edge_port->edge_serial->num_ports_open = 0;
-               }
+       /* The bulkreadcompletion routine will check 
+        * this flag and dump add read data */
+       edge_port->close_pending = 1;
+
+       /* chase the port close and flush */
+       TIChasePort (edge_port, (HZ*closing_wait)/100, 1);
+
+       usb_kill_urb(port->read_urb);
+       usb_kill_urb(port->write_urb);
+       edge_port->ep_write_urb_in_use = 0;
+
+       /* assuming we can still talk to the device,
+        * send a close port command to it */
+       dbg("%s - send umpc_close_port", __FUNCTION__);
+       port_number = port->number - port->serial->minor;
+       status = TIWriteCommandSync (port->serial->dev,
+                                    UMPC_CLOSE_PORT,
+                                    (__u8)(UMPM_UART1_PORT + port_number),
+                                    0,
+                                    NULL,
+                                    0);
+       down(&edge_serial->es_sem);
+       --edge_port->edge_serial->num_ports_open;
+       if (edge_port->edge_serial->num_ports_open <= 0) {
+               /* last port is now closed, let's shut down our interrupt urb */
+               usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
+               edge_port->edge_serial->num_ports_open = 0;
+       }
+       up(&edge_serial->es_sem);
        edge_port->close_pending = 0;
-       }
 
        dbg("%s - exited", __FUNCTION__);
 }
 
-static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count)
+static int edge_write (struct usb_serial_port *port, const unsigned char *data, int count)
 {
-       struct usb_serial *serial = port->serial;
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-       int result;
+       unsigned long flags;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -2062,26 +2146,51 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign
                return -ENODEV;
        if (edge_port->close_pending == 1)
                return -ENODEV;
-       
-       if (port->write_urb->status == -EINPROGRESS) {
-               dbg ("%s - already writing", __FUNCTION__);
-               return 0;
+
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
+       count = edge_buf_put(edge_port->ep_out_buf, data, count);
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
+       edge_send(port);
+
+       return count;
+}
+
+static void edge_send(struct usb_serial_port *port)
+{
+       int count, result;
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct tty_struct *tty = port->tty;
+       unsigned long flags;
+
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
+
+       if (edge_port->ep_write_urb_in_use) {
+               spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+               return;
        }
 
-       count = min (count, port->bulk_out_size);
+       count = edge_buf_get(edge_port->ep_out_buf,
+                               port->write_urb->transfer_buffer,
+                               port->bulk_out_size);
 
-       if (from_user) {
-               if (copy_from_user(port->write_urb->transfer_buffer, data, count))
-                       return -EFAULT;
-       } else {
-               memcpy (port->write_urb->transfer_buffer, data, count);
+       if (count == 0) {
+               spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+               return;
        }
 
-       usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
+       edge_port->ep_write_urb_in_use = 1;
+
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
 
        /* set up our urb */
-       usb_fill_bulk_urb (port->write_urb, serial->dev,
-                          usb_sndbulkpipe (serial->dev,
+       usb_fill_bulk_urb (port->write_urb, port->serial->dev,
+                          usb_sndbulkpipe (port->serial->dev,
                                            port->bulk_out_endpointAddress),
                           port->write_urb->transfer_buffer, count,
                           edge_bulk_out_callback,
@@ -2089,33 +2198,38 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign
 
        /* send the data out the bulk port */
        result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-       if (result)
+       if (result) {
                dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
-       else
-               result = count;
-
-       if (result > 0)
+               edge_port->ep_write_urb_in_use = 0;
+               // TODO: reschedule edge_send
+       } else {
                edge_port->icount.tx += count;
+       }
 
-       return result;
+       /* wakeup any process waiting for writes to complete */
+       /* there is now more room in the buffer for new writes */
+       if (tty) {
+               /* let the tty driver wakeup if it has a special write_wakeup function */
+               tty_wakeup(tty);
+       }
 }
 
 static int edge_write_room (struct usb_serial_port *port)
 {
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        int room = 0;
+       unsigned long flags;
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (edge_port == NULL)
                return -ENODEV;
        if (edge_port->close_pending == 1)
                return -ENODEV;
-       
-       dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (port->write_urb->status != -EINPROGRESS)
-               room = port->bulk_out_size;
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
+       room = edge_buf_space_avail(edge_port->ep_out_buf);
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
        dbg("%s - returns %d", __FUNCTION__, room);
        return room;
@@ -2125,18 +2239,18 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
 {
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        int chars = 0;
+       unsigned long flags;
 
-       dbg("%s", __FUNCTION__);
+       dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (edge_port == NULL)
                return -ENODEV;
        if (edge_port->close_pending == 1)
                return -ENODEV;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
-
-       if (port->write_urb->status == -EINPROGRESS)
-               chars = port->write_urb->transfer_buffer_length;
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
+       chars = edge_buf_data_avail(edge_port->ep_out_buf);
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
        dbg ("%s - returns %d", __FUNCTION__, chars);
        return chars;
@@ -2158,21 +2272,21 @@ static void edge_throttle (struct usb_serial_port *port)
                dbg ("%s - no tty available", __FUNCTION__);
                return;
        }
+
        /* if we are implementing XON/XOFF, send the stop character */
        if (I_IXOFF(tty)) {
                unsigned char stop_char = STOP_CHAR(tty);
-               status = edge_write (port, 0, &stop_char, 1);
+               status = edge_write (port, &stop_char, 1);
                if (status <= 0) {
-                       return;
+                       dev_err(&port->dev, "%s - failed to write stop character, %d\n", __FUNCTION__, status);
                }
        }
 
-       /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               status = TIClearRts (edge_port);
-       }
+       /* if we are implementing RTS/CTS, stop reads */
+       /* and the Edgeport will clear the RTS line */
+       if (C_CRTSCTS(tty))
+               stop_read(edge_port);
 
-       usb_unlink_urb (port->read_urb);
 }
 
 static void edge_unthrottle (struct usb_serial_port *port)
@@ -2195,31 +2309,63 @@ static void edge_unthrottle (struct usb_serial_port *port)
        /* if we are implementing XON/XOFF, send the start character */
        if (I_IXOFF(tty)) {
                unsigned char start_char = START_CHAR(tty);
-               status = edge_write (port, 0, &start_char, 1);
+               status = edge_write (port, &start_char, 1);
                if (status <= 0) {
-                       return;
+                       dev_err(&port->dev, "%s - failed to write start character, %d\n", __FUNCTION__, status);
                }
        }
 
-       /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               status = TISetRts (edge_port);
+       /* if we are implementing RTS/CTS, restart reads */
+       /* are the Edgeport will assert the RTS line */
+       if (C_CRTSCTS(tty)) {
+               status = restart_read(edge_port);
+               if (status)
+                       dev_err(&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status);
        }
 
-       port->read_urb->dev = port->serial->dev;
-       status = usb_submit_urb (port->read_urb, GFP_ATOMIC);
-       if (status) {
-               dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
-       }
 }
 
+static void stop_read(struct edgeport_port *edge_port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
+
+       if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING)
+               edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPING;
+       edge_port->shadow_mcr &= ~MCR_RTS;
+
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+}
 
-static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
+static int restart_read(struct edgeport_port *edge_port)
+{
+       struct urb *urb;
+       int status = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
+
+       if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPED) {
+               urb = edge_port->port->read_urb;
+               urb->complete = edge_bulk_in_callback;
+               urb->context = edge_port;
+               urb->dev = edge_port->port->serial->dev;
+               status = usb_submit_urb(urb, GFP_KERNEL);
+       }
+       edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
+       edge_port->shadow_mcr |= MCR_RTS;
+
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
+       return status;
+}
+
+static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
 {
        struct ump_uart_config *config;
        struct tty_struct *tty;
        int baud;
-       int round;
        unsigned cflag;
        int status;
        int port_number = edge_port->port->number - edge_port->port->serial->minor;
@@ -2246,7 +2392,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
        /* These flags must be set */
        config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT;
        config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR;
-       config->bUartMode = 0;
+       config->bUartMode = (__u8)(edge_port->bUartMode);
 
        switch (cflag & CSIZE) {
                case CS5:
@@ -2298,6 +2444,8 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
                dbg("%s - RTS/CTS is enabled", __FUNCTION__);
        } else {
                dbg("%s - RTS/CTS is disabled", __FUNCTION__);
+               tty->hw_stopped = 0;
+               restart_read(edge_port);
        }
 
        /* if we are implementing XON/XOFF, set the start and stop character in the device */
@@ -2330,10 +2478,8 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
                /* pick a default, any default... */
                baud = 9600;
        }
-       config->wBaudRate = (__u16)(461550L / baud);
-       round = 4615500L / baud;
-       if ((round - (config->wBaudRate * 10)) >= 5)
-               config->wBaudRate++;
+       edge_port->baud_rate = baud;
+       config->wBaudRate = (__u16)((461550L + baud/2) / baud);
 
        dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
 
@@ -2366,7 +2512,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
        return;
 }
 
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
 {
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        struct tty_struct *tty = port->tty;
@@ -2380,20 +2526,18 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
        cflag = tty->termios->c_cflag;
        /* check that they really want us to change something */
        if (old_termios) {
-               if ((cflag == old_termios->c_cflag) &&
-                   (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+               if (cflag == old_termios->c_cflag &&
+                   tty->termios->c_iflag == old_termios->c_iflag) {
                        dbg ("%s - nothing to change", __FUNCTION__);
                        return;
                }
        }
 
        dbg("%s - clfag %08x iflag %08x", __FUNCTION__, 
-           tty->termios->c_cflag,
-           RELEVANT_IFLAG(tty->termios->c_iflag));
+           tty->termios->c_cflag, tty->termios->c_iflag);
        if (old_termios) {
                dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
-                   old_termios->c_cflag,
-                   RELEVANT_IFLAG(old_termios->c_iflag));
+                   old_termios->c_cflag, old_termios->c_iflag);
        }
 
        dbg("%s - port %d", __FUNCTION__, port->number);
@@ -2409,7 +2553,7 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
 
 static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        unsigned int mcr;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
@@ -2438,7 +2582,7 @@ static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsig
 
 static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        unsigned int result = 0;
        unsigned int msr;
        unsigned int mcr;
@@ -2460,7 +2604,7 @@ static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
        return result;
 }
 
-static int get_serial_info (struct edgeport_port *edge_port, struct serial_struct retinfo)
+static int get_serial_info (struct edgeport_port *edge_port, struct serial_struct __user *retinfo)
 {
        struct serial_struct tmp;
 
@@ -2477,7 +2621,7 @@ static int get_serial_info (struct edgeport_port *edge_port, struct serial_struc
        tmp.xmit_fifo_size      = edge_port->port->bulk_out_size;
        tmp.baud_base           = 9600;
        tmp.close_delay         = 5*HZ;
-       tmp.closing_wait        = 30*HZ;
+       tmp.closing_wait        = closing_wait;
 //     tmp.custom_divisor      = state->custom_divisor;
 //     tmp.hub6                = state->hub6;
 //     tmp.io_type             = state->io_type;
@@ -2509,7 +2653,7 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
 
                case TIOCGSERIAL:
                        dbg("%s - (%d) TIOCGSERIAL", __FUNCTION__, port->number);
-                       return get_serial_info(edge_port, (struct serial_struct *) arg);
+                       return get_serial_info(edge_port, (struct serial_struct __user *) arg);
                        break;
 
                case TIOCSSERIAL:
@@ -2542,7 +2686,7 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
                case TIOCGICOUNT:
                        dbg ("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
                             port->number, edge_port->icount.rx, edge_port->icount.tx);
-                       if (copy_to_user((void *)arg, &edge_port->icount, sizeof(edge_port->icount)))
+                       if (copy_to_user((void __user *)arg, &edge_port->icount, sizeof(edge_port->icount)))
                                return -EFAULT;
                        return 0;
        }
@@ -2558,7 +2702,7 @@ static void edge_break (struct usb_serial_port *port, int break_state)
        dbg ("%s - state = %d", __FUNCTION__, break_state);
 
        /* chase the port close */
-       TIChasePort (edge_port);
+       TIChasePort (edge_port, 0, 0);
 
        if (break_state == -1) {
                status = TISetBreak (edge_port);
@@ -2582,12 +2726,12 @@ static int edge_startup (struct usb_serial *serial)
        dev = serial->dev;
 
        /* create our private serial structure */
-       edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+       edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
        if (edge_serial == NULL) {
                dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset (edge_serial, 0, sizeof(struct edgeport_serial));
+       sema_init(&edge_serial->es_sem, 1);
        edge_serial->serial = serial;
        usb_set_serial_data(serial, edge_serial);
 
@@ -2599,28 +2743,51 @@ static int edge_startup (struct usb_serial *serial)
 
        /* set up our port private structures */
        for (i = 0; i < serial->num_ports; ++i) {
-               edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
+               edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL);
                if (edge_port == NULL) {
                        dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
-                       return -ENOMEM;
+                       goto cleanup;
+               }
+               spin_lock_init(&edge_port->ep_lock);
+               edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE);
+               if (edge_port->ep_out_buf == NULL) {
+                       dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+                       kfree(edge_port);
+                       goto cleanup;
                }
-               memset (edge_port, 0, sizeof(struct edgeport_port));
                edge_port->port = serial->port[i];
                edge_port->edge_serial = edge_serial;
                usb_set_serial_port_data(serial->port[i], edge_port);
+               edge_port->bUartMode = 0;       /* Default is RS232 */
        }
        
        return 0;
+
+cleanup:
+       for (--i; i>=0; --i) {
+               edge_port = usb_get_serial_port_data(serial->port[i]);
+               edge_buf_free(edge_port->ep_out_buf);
+               kfree(edge_port);
+               usb_set_serial_port_data(serial->port[i], NULL);
+       }
+       kfree (edge_serial);
+       usb_set_serial_data(serial, NULL);
+       return -ENOMEM;
 }
 
 static void edge_shutdown (struct usb_serial *serial)
 {
        int i;
+       struct edgeport_port *edge_port;
 
        dbg ("%s", __FUNCTION__);
 
        for (i=0; i < serial->num_ports; ++i) {
-               kfree (usb_get_serial_port_data(serial->port[i]));
+               edge_port = usb_get_serial_port_data(serial->port[i]);
+               if (edge_port) {
+                       edge_buf_free(edge_port->ep_out_buf);
+                       kfree(edge_port);
+               }
                usb_set_serial_port_data(serial->port[i], NULL);
        }
        kfree (usb_get_serial_data(serial));
@@ -2628,10 +2795,190 @@ static void edge_shutdown (struct usb_serial *serial)
 }
 
 
-static struct usb_serial_device_type edgeport_1port_device = {
-       .owner                  = THIS_MODULE,
-       .name                   = "Edgeport TI 1 port adapter",
-       .short_name             = "edgeport_ti_1",
+/* Circular Buffer */
+
+/*
+ * edge_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+
+static struct edge_buf *edge_buf_alloc(unsigned int size)
+{
+       struct edge_buf *eb;
+
+
+       if (size == 0)
+               return NULL;
+
+       eb = kmalloc(sizeof(struct edge_buf), GFP_KERNEL);
+       if (eb == NULL)
+               return NULL;
+
+       eb->buf_buf = kmalloc(size, GFP_KERNEL);
+       if (eb->buf_buf == NULL) {
+               kfree(eb);
+               return NULL;
+       }
+
+       eb->buf_size = size;
+       eb->buf_get = eb->buf_put = eb->buf_buf;
+
+       return eb;
+}
+
+
+/*
+ * edge_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+
+static void edge_buf_free(struct edge_buf *eb)
+{
+       if (eb) {
+               kfree(eb->buf_buf);
+               kfree(eb);
+       }
+}
+
+
+/*
+ * edge_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+
+static void edge_buf_clear(struct edge_buf *eb)
+{
+        if (eb != NULL)
+                eb->buf_get = eb->buf_put;
+                /* equivalent to a get of all data available */
+}
+
+
+/*
+ * edge_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+
+static unsigned int edge_buf_data_avail(struct edge_buf *eb)
+{
+       if (eb != NULL)
+               return ((eb->buf_size + eb->buf_put - eb->buf_get) % eb->buf_size);
+       else
+               return 0;
+}
+
+
+/*
+ * edge_buf_space_avail
+ *
+ * Return the number of bytes of space available in the circular
+ * buffer.
+ */
+
+static unsigned int edge_buf_space_avail(struct edge_buf *eb)
+{
+       if (eb != NULL)
+               return ((eb->buf_size + eb->buf_get - eb->buf_put - 1) % eb->buf_size);
+       else
+               return 0;
+}
+
+
+/*
+ * edge_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+
+static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
+       unsigned int count)
+{
+       unsigned int len;
+
+
+       if (eb == NULL)
+               return 0;
+
+       len  = edge_buf_space_avail(eb);
+       if (count > len)
+               count = len;
+
+       if (count == 0)
+               return 0;
+
+       len = eb->buf_buf + eb->buf_size - eb->buf_put;
+       if (count > len) {
+               memcpy(eb->buf_put, buf, len);
+               memcpy(eb->buf_buf, buf+len, count - len);
+               eb->buf_put = eb->buf_buf + count - len;
+       } else {
+               memcpy(eb->buf_put, buf, count);
+               if (count < len)
+                       eb->buf_put += count;
+               else /* count == len */
+                       eb->buf_put = eb->buf_buf;
+       }
+
+       return count;
+}
+
+
+/*
+ * edge_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+
+static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
+       unsigned int count)
+{
+       unsigned int len;
+
+
+       if (eb == NULL)
+               return 0;
+
+       len = edge_buf_data_avail(eb);
+       if (count > len)
+               count = len;
+
+       if (count == 0)
+               return 0;
+
+       len = eb->buf_buf + eb->buf_size - eb->buf_get;
+       if (count > len) {
+               memcpy(buf, eb->buf_get, len);
+               memcpy(buf+len, eb->buf_buf, count - len);
+               eb->buf_get = eb->buf_buf + count - len;
+       } else {
+               memcpy(buf, eb->buf_get, count);
+               if (count < len)
+                       eb->buf_get += count;
+               else /* count == len */
+                       eb->buf_get = eb->buf_buf;
+       }
+
+       return count;
+}
+
+
+static struct usb_serial_driver edgeport_1port_device = {
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = "edgeport_ti_1",
+       },
+       .description            = "Edgeport TI 1 port adapter",
        .id_table               = edgeport_1port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -2651,12 +2998,17 @@ static struct usb_serial_device_type edgeport_1port_device = {
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
        .break_ctl              = edge_break,
+       .read_int_callback      = edge_interrupt_callback,
+       .read_bulk_callback     = edge_bulk_in_callback,
+       .write_bulk_callback    = edge_bulk_out_callback,
 };
 
-static struct usb_serial_device_type edgeport_2port_device = {
-       .owner                  = THIS_MODULE,
-       .name                   = "Edgeport TI 2 port adapter",
-       .short_name             = "edgeport_ti_2",
+static struct usb_serial_driver edgeport_2port_device = {
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = "edgeport_ti_2",
+       },
+       .description            = "Edgeport TI 2 port adapter",
        .id_table               = edgeport_2port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 2,
@@ -2676,6 +3028,9 @@ static struct usb_serial_device_type edgeport_2port_device = {
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
        .break_ctl              = edge_break,
+       .read_int_callback      = edge_interrupt_callback,
+       .read_bulk_callback     = edge_bulk_in_callback,
+       .write_bulk_callback    = edge_bulk_out_callback,
 };
 
 
@@ -2716,9 +3071,15 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(debug, "i");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
-MODULE_PARM(ignore_cpu_rev, "i");
+module_param(low_latency, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(low_latency, "Low latency enabled or not");
+
+module_param(closing_wait, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs");
+
+module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device");