Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / usb / serial / io_edgeport.c
index e727628..c49976c 100644 (file)
  *     Edgeport/4D8
  *     Edgeport/8i
  *
- * Version history:
- * 
- * 2003_04_03 al borchers
- *  - fixed a bug (that shows up with dosemu) where the tty struct is
- *    used in a callback after it has been freed
+ * 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>.
  *
- * 2.3 2002_03_08 greg kroah-hartman
- *     - fixed bug when multiple devices were attached at the same time.
- *
- * 2.2 2001_11_14 greg kroah-hartman
- *     - fixed bug in edge_close that kept the port from being used more
- *       than once.
- *     - fixed memory leak on device removal.
- *     - fixed potential double free of memory when command urb submitting
- *       failed.
- *     - other small cleanups when the device is removed
- *     
- * 2.1 2001_07_09 greg kroah-hartman
- *     - added support for TIOCMBIS and TIOCMBIC.
- *
- *     (04/08/2001) gb
- *     - Identify version on module load.
- *
- * 2.0 2001_03_05 greg kroah-hartman
- *     - reworked entire driver to fit properly in with the other usb-serial
- *       drivers.  Occasional oopses still happen, but it's a good start.
- *
- * 1.2.3 (02/23/2001) greg kroah-hartman
- *     - changed device table to work properly for 2.4.x final format.
- *     - fixed problem with dropping data at high data rates.
- *
- * 1.2.2 (11/27/2000) greg kroah-hartman
- *     - cleaned up more NTisms.
- *     - Added device table for 2.4.0-test11
- *
- * 1.2.1 (11/08/2000) greg kroah-hartman
- *     - Started to clean up NTisms.
- *     - Fixed problem with dev field of urb for kernels >= 2.4.0-test9
- *
- * 1.2 (10/17/2000) David Iacovelli
- *     Remove all EPIC code and GPL source
- *  Fix RELEVANT_IFLAG macro to include flow control 
- *  changes port configuration changes.
- *  Fix redefinition of SERIAL_MAGIC
- *  Change all timeout values to 5 seconds
- *  Tried to fix the UHCI multiple urb submission, but failed miserably.
- *  it seems to work fine with OHCI.
- *  ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must 
- *    find a way to work arount this UHCI bug )
- *
- * 1.1 (10/11/2000) David Iacovelli
- *  Fix XON/XOFF flow control to support both IXON and IXOFF
- *
- * 0.9.27 (06/30/2000) David Iacovelli
- *  Added transmit queue and now allocate urb for command writes.
- *
- * 0.9.26 (06/29/2000) David Iacovelli
- *  Add support for 80251 based edgeport
- *
- * 0.9.25 (06/27/2000) David Iacovelli
- *  Do not close the port if it has multiple opens.
- *
- * 0.9.24 (05/26/2000) David Iacovelli
- *  Add IOCTLs to support RXTX and JAVA POS 
- *  and first cut at running BlackBox Demo
- *
- * 0.9.23 (05/24/2000) David Iacovelli
- *  Add IOCTLs to support RXTX and JAVA POS
- *
- * 0.9.22 (05/23/2000) David Iacovelli
- *  fixed bug in enumeration.  If epconfig turns on mapping by
- *  path after a device is already plugged in, we now update
- *  the mapping correctly
- *
- * 0.9.21 (05/16/2000) David Iacovelli
- *  Added BlockUntilChaseResp() to also wait for txcredits
- *  Updated the way we allocate and handle write URBs 
- *     Add debug code to dump buffers
- *
- * 0.9.20 (05/01/2000) David Iacovelli
- *     change driver to use usb/tts/
- *
- * 0.9.19 (05/01/2000) David Iacovelli
- *  Update code to compile if DEBUG is off
- *
- * 0.9.18 (04/28/2000) David Iacovelli
- *  cleanup and test tty_register with devfs
- *
- * 0.9.17 (04/27/2000) greg kroah-hartman
- *     changed tty_register around to be like the way it
- *     was before, but now it works properly with devfs.
- *
- * 0.9.16 (04/26/2000) david iacovelli
- *  Fixed bug in GetProductInfo()
- *
- * 0.9.15 (04/25/2000) david iacovelli
- *     Updated enumeration
- *
- * 0.9.14 (04/24/2000) david iacovelli
- *  Removed all config/status IOCTLS and 
- *  converted to using /proc/edgeport
- *  still playing with devfs
- *
- * 0.9.13 (04/24/2000) david iacovelli
- *  Removed configuration based on ttyUSB0
- *  Added support for configuration using /prod/edgeport
- *  first attempt at using devfs (not working yet!)
- *  Added IOCTL to GetProductInfo()
- *  Added support for custom baud rates
- *     Add support for random port numbers
- *
- * 0.9.12 (04/18/2000) david iacovelli
- *     added additional configuration IOCTLs
- *  use ttyUSB0 for configuration
- *
- * 0.9.11 (04/17/2000) greg kroah-hartman
- *     fixed module initialization race conditions.
- *     made all urbs dynamically allocated.
- *     made driver devfs compatible. now it only registers the tty device
- *     when the device is actually plugged in.
- *
- * 0.9.10 (04/13/2000) greg kroah-hartman
- *     added proc interface framework.
- *
- * 0.9.9 (04/13/2000) david iacovelli
- *     added enumeration code and ioctls to configure the device
- *
- * 0.9.8 (04/12/2000) david iacovelli
- *  Change interrupt read start when device is plugged in
- *  and stop when device is removed
- *     process interrupt reads when all ports are closed 
- *  (keep value of rxBytesAvail consistent with the edgeport)
- *  set the USB_BULK_QUEUE flag so that we can shove a bunch 
- *  of urbs at once down the pipe 
- *
- * 0.9.7 (04/10/2000) david iacovelli
- *     start to add enumeration code.
- *  generate serial number for epic devices
- *  add support for kdb
- *
- * 0.9.6 (03/30/2000) david iacovelli
- *  add IOCTL to get string, manufacture, and boot descriptors
- *
- * 0.9.5 (03/14/2000) greg kroah-hartman
- *     more error checking added to SerialOpen to try to fix UHCI open problem
- *
- * 0.9.4 (03/09/2000) greg kroah-hartman
- *     added more error checking to handle oops when data is hanging
- *     around and tty is abruptly closed.
- *
- * 0.9.3 (03/09/2000) david iacovelli
- *     Add epic support for xon/xoff chars
- *     play with performance
- *
- * 0.9.2 (03/08/2000) greg kroah-hartman
- *     changed most "info" calls to "dbg"
- *     implemented flow control properly in the termios call
- *
- * 0.9.1 (03/08/2000) david iacovelli
- *     added EPIC support
- *     enabled bootloader update
- *
- * 0.9 (03/08/2000) greg kroah-hartman
- *     Release to IO networks.
- *     Integrated changes that David made
- *  made getting urbs for writing SMP safe
- *
- * 0.8 (03/07/2000) greg kroah-hartman
- *     Release to IO networks.
- *     Fixed problems that were seen in code by David.
- *  Now both Edgeport/4 and Edgeport/2 works properly.
- *  Changed most of the functions to use port instead of serial.
- *
- * 0.7 (02/27/2000) greg kroah-hartman
- *     Milestone 3 release.
- *     Release to IO Networks
- *     ioctl for waiting on line change implemented.
- *     ioctl for getting statistics implemented.
- *     multiport support working.
- *     lsr and msr registers are now handled properly.
- *     change break now hooked up and working.
- *     support for all known Edgeport devices.
- *
- * 0.6 (02/22/2000) greg kroah-hartman
- *     Release to IO networks.
- *     CHASE is implemented correctly when port is closed.
- *     SerialOpen now blocks correctly until port is fully opened.
- *
- * 0.5 (02/20/2000) greg kroah-hartman
- *     Release to IO networks.
- *     Known problems:
- *             modem status register changes are not sent on to the user
- *             CHASE is not implemented when the port is closed.
- *
- * 0.4 (02/16/2000) greg kroah-hartman
- *     Second cut at the CeBit demo.
- *     Doesn't leak memory on every write to the port
- *     Still small leaks on startup.
- *     Added support for Edgeport/2 and Edgeport/8
- *
- * 0.3 (02/15/2000) greg kroah-hartman
- *     CeBit demo release.
- *     Force the line settings to 4800, 8, 1, e for the demo.
- *     Warning! This version leaks memory like crazy!
- *
- * 0.2 (01/30/2000) greg kroah-hartman
- *     Milestone 1 release.
- *     Device is found by USB subsystem, enumerated, fimware is downloaded
- *     and the descriptors are printed to the debug log, config is set, and
- *     green light starts to blink. Open port works, and data can be sent
- *     and received at the default settings of the UART. Loopback connector
- *     and debug log confirms this.
- * 
- * 0.1 (01/23/2000) greg kroah-hartman
- *     Initial release to help IO Networks try to set up their test system. 
- *     Edgeport4 is recognized, firmware is downloaded, config is set so 
- *     device blinks green light every 3 sec. Port is bound, but opening,
- *     closing, and sending data do not work properly.
- * 
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
 #include <linux/serial.h>
 #include <linux/ioctl.h>
+#include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
 #include "io_edgeport.h"
 #include "io_ionsp.h"          /* info for the iosp messages */
 #include "io_16654.h"          /* 16654 UART defines */
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v2.7"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
 #define DRIVER_DESC "Edgeport USB Serial Driver"
 
 #define OPEN_TIMEOUT           (5*HZ)          /* 5 seconds */
 #define COMMAND_TIMEOUT                (5*HZ)          /* 5 seconds */
 
-static int debug;
-
 /* receive port state */
 enum RXSTATE {
        EXPECT_HDR1 = 0,        /* Expect header byte 1 */
@@ -329,6 +112,7 @@ struct edgeport_port {
        struct TxFifo           txfifo;                 /* transmit fifo -- size will be maxTxCredits */
        struct urb              *write_urb;             /* write URB for this port */
        char                    write_in_progress;      /* TRUE while a write URB is outstanding */
+       spinlock_t              ep_lock;
 
        __u8                    shadowLCR;              /* last LCR value received */
        __u8                    shadowMCR;              /* last MCR value received */
@@ -357,7 +141,7 @@ struct edgeport_port {
 
 /* This structure holds all of the individual device information */
 struct edgeport_serial {
-       char                    name[MAX_NAME_LEN+1];           /* string name of this device */
+       char                    name[MAX_NAME_LEN+2];           /* string name of this device */
 
        struct edge_manuf_descriptor    manuf_descriptor;       /* the manufacturer descriptor */
        struct edge_boot_descriptor     boot_descriptor;        /* the boot firmware descriptor */
@@ -370,6 +154,8 @@ struct edgeport_serial {
        __u8                    bulk_in_endpoint;               /* the bulk in endpoint handle */
        unsigned char *         bulk_in_buffer;                 /* the buffer we use for the bulk in endpoint */
        struct urb *            read_urb;                       /* our bulk read urb */
+       int                     read_in_progress;
+       spinlock_t              es_lock;
 
        __u8                    bulk_out_endpoint;              /* the bulk out endpoint handle */
 
@@ -397,7 +183,7 @@ struct divisor_table_entry {
 // These assume a 3.6864MHz crystal, the standard /16, and
 // MCR.7 = 0.
 //
-static struct divisor_table_entry divisor_table[] = {
+static const struct divisor_table_entry divisor_table[] = {
        {   50,         4608},  
        {   75,         3072},  
        {   110,        2095},          /* 2094.545455 => 230450   => .0217 % over */
@@ -420,7 +206,11 @@ static struct divisor_table_entry divisor_table[] = {
 };
 
 /* local variables */
-static int     CmdUrbs = 0;                                                    /* Number of outstanding Command Write Urbs */
+static int debug;
+
+static int low_latency = 1;    /* tty low latency flag, on by default */
+
+static int CmdUrbs = 0;                /* Number of outstanding Command Write Urbs */
 
 
 /* local function prototypes */
@@ -434,7 +224,7 @@ static void edge_bulk_out_cmd_callback      (struct urb *urb, struct pt_regs *regs);
 /* function prototypes for the usbserial callbacks */
 static int  edge_open                  (struct usb_serial_port *port, struct file *filp);
 static void edge_close                 (struct usb_serial_port *port, struct file *filp);
-static int  edge_write                 (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  edge_write                 (struct usb_serial_port *port, const unsigned char *buf, int count);
 static int  edge_write_room            (struct usb_serial_port *port);
 static int  edge_chars_in_buffer       (struct usb_serial_port *port);
 static void edge_throttle              (struct usb_serial_port *port);
@@ -451,16 +241,17 @@ static void edge_shutdown         (struct usb_serial *serial);
 #include "io_tables.h" /* all of the devices that this driver supports */
 
 static struct usb_driver io_driver = {
-       .owner =        THIS_MODULE,
        .name =         "io_edgeport",
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table_combined,
+       .no_dynamic_id =        1,
 };
 
 /* function prototypes for all of our local functions */
-static int  process_rcvd_data          (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
+static void  process_rcvd_data         (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
 static void process_rcvd_status                (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
+static void edge_tty_recv                      (struct device *dev, struct tty_struct *tty, unsigned char *data, int length);
 static void handle_new_msr             (struct edgeport_port *edge_port, __u8 newMsr);
 static void handle_new_lsr             (struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data);
 static int  send_iosp_ext_cmd          (struct edgeport_port *edge_port, __u8 command, __u8 param);
@@ -478,11 +269,7 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial);
 static void get_boot_desc              (struct edgeport_serial *edge_serial);
 static void load_application_firmware  (struct edgeport_serial *edge_serial);
 
-
-static void unicode_to_ascii           (char *string, short *unicode, int unicode_size);
-
-
-
+static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size);
 
 
 // ************************************************************************
@@ -504,7 +291,7 @@ static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
        __u32 BootNewVer;
        __u8 BootMajorVersion;                  
        __u8 BootMinorVersion;                  
-       __u16 BootBuildNumber;
+       __le16 BootBuildNumber;
        __u8 *BootImage;      
        __u32 BootSize;
        struct edge_firmware_image_record *record;
@@ -585,7 +372,7 @@ static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
  *  Get string descriptor from device                                  *
  *                                                                     *
  ************************************************************************/
-static int get_string (struct usb_device *dev, int Id, char *string)
+static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
 {
        struct usb_string_descriptor StringDesc;
        struct usb_string_descriptor *pStringDesc;
@@ -607,7 +394,7 @@ static int get_string (struct usb_device *dev, int Id, char *string)
                return 0;
        }
 
-       unicode_to_ascii(string,  pStringDesc->wData,     pStringDesc->bLength/2-1);
+       unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
 
        kfree(pStringDesc);
        return strlen(string);
@@ -653,7 +440,7 @@ static void get_product_info(struct edgeport_serial *edge_serial)
 
        memset (product_info, 0, sizeof(struct edgeport_product_info));
 
-       product_info->ProductId         = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_GENERATION_2);
+       product_info->ProductId         = (__u16)(le16_to_cpu(edge_serial->serial->dev->descriptor.idProduct) & ~ION_DEVICE_ID_80251_NETCHIP);
        product_info->NumPorts          = edge_serial->manuf_descriptor.NumPorts;
        product_info->ProdInfoVer       = 0;
 
@@ -669,7 +456,7 @@ static void get_product_info(struct edgeport_serial *edge_serial)
        memcpy(product_info->ManufactureDescDate, edge_serial->manuf_descriptor.DescDate, sizeof(edge_serial->manuf_descriptor.DescDate));
 
        // check if this is 2nd generation hardware
-       if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_GENERATION_2) {
+       if (le16_to_cpu(edge_serial->serial->dev->descriptor.idProduct) & ION_DEVICE_ID_80251_NETCHIP) {
                product_info->FirmwareMajorVersion      = OperationalCodeImageVersion_GEN2.MajorVersion;
                product_info->FirmwareMinorVersion      = OperationalCodeImageVersion_GEN2.MinorVersion;
                product_info->FirmwareBuildNumber       = cpu_to_le16(OperationalCodeImageVersion_GEN2.BuildNumber);
@@ -784,20 +571,24 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
                if (length > 1) {
                        bytes_avail = data[0] | (data[1] << 8);
                        if (bytes_avail) {
+                               spin_lock(&edge_serial->es_lock);
                                edge_serial->rxBytesAvail += bytes_avail;
-                               dbg("%s - bytes_avail = %d, rxBytesAvail %d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail);
+                               dbg("%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress);
 
-                               if ((edge_serial->rxBytesAvail > 0) &&
-                                   (edge_serial->read_urb->status != -EINPROGRESS)) {
-                                       dbg(" --- Posting a read");
+                               if (edge_serial->rxBytesAvail > 0 &&
+                                   !edge_serial->read_in_progress) {
+                                       dbg("%s - posting a read", __FUNCTION__);
+                                       edge_serial->read_in_progress = TRUE;
 
                                        /* we have pending bytes on the bulk in pipe, send a request */
                                        edge_serial->read_urb->dev = edge_serial->serial->dev;
                                        result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
                                        if (result) {
-                                               dbg("%s - usb_submit_urb(read bulk) failed with result = %d", __FUNCTION__, result);
+                                               dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __FUNCTION__, result);
+                                               edge_serial->read_in_progress = FALSE;
                                        }
                                }
+                               spin_unlock(&edge_serial->es_lock);
                        }
                }
                /* grab the txcredits for the ports if available */
@@ -809,12 +600,14 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
                                port = edge_serial->serial->port[portNumber];
                                edge_port = usb_get_serial_port_data(port);
                                if (edge_port->open) {
+                                       spin_lock(&edge_port->ep_lock);
                                        edge_port->txCredits += txCredits;
+                                       spin_unlock(&edge_port->ep_lock);
                                        dbg("%s - txcredits for port%d = %d", __FUNCTION__, portNumber, edge_port->txCredits);
 
                                        /* tell the tty driver that something has changed */
                                        if (edge_port->port->tty)
-                                               wake_up_interruptible(&edge_port->port->tty->write_wait);
+                                               tty_wakeup(edge_port->port->tty);
 
                                        // Since we have more credit, check if more data can be sent
                                        send_more_port_data(edge_serial, edge_port);
@@ -849,34 +642,43 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
 
        if (urb->status) {
                dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+               edge_serial->read_in_progress = FALSE;
                return;
        }
 
-       if (urb->actual_length) {
-               raw_data_length = urb->actual_length;
+       if (urb->actual_length == 0) {
+               dbg("%s - read bulk callback with no data", __FUNCTION__);
+               edge_serial->read_in_progress = FALSE;
+               return;
+       }
 
-               usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, raw_data_length, data);
+       raw_data_length = urb->actual_length;
 
-               /* decrement our rxBytes available by the number that we just got */
-               edge_serial->rxBytesAvail -= raw_data_length;
+       usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, raw_data_length, data);
 
-               dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length, edge_serial->rxBytesAvail);
+       spin_lock(&edge_serial->es_lock);
 
-               process_rcvd_data (edge_serial, data, urb->actual_length);
+       /* decrement our rxBytes available by the number that we just got */
+       edge_serial->rxBytesAvail -= raw_data_length;
 
-               /* check to see if there's any more data for us to read */
-               if ((edge_serial->rxBytesAvail > 0) &&
-                   (edge_serial->read_urb->status != -EINPROGRESS)) {
-                       dbg(" --- Posting a read");
+       dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length, edge_serial->rxBytesAvail);
 
-                       /* there is, so resubmit our urb */
-                       edge_serial->read_urb->dev = edge_serial->serial->dev;
-                       status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
-                       if (status) {
-                               dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status);
-                       }
+       process_rcvd_data (edge_serial, data, urb->actual_length);
+
+       /* check to see if there's any more data for us to read */
+       if (edge_serial->rxBytesAvail > 0) {
+               dbg("%s - posting a read", __FUNCTION__);
+               edge_serial->read_urb->dev = edge_serial->serial->dev;
+               status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
+               if (status) {
+                       dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status);
+                       edge_serial->read_in_progress = FALSE;
                }
+       } else {
+               edge_serial->read_in_progress = FALSE;
        }
+
+       spin_unlock(&edge_serial->es_lock);
 }
 
 
@@ -900,12 +702,7 @@ static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs)
 
        if (tty && edge_port->open) {
                /* 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);
+               tty_wakeup(tty);
        }
 
        // Release the Write URB
@@ -934,9 +731,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs)
 
 
        /* clean up the transfer buffer */
-       if (urb->transfer_buffer != NULL) {
-               kfree(urb->transfer_buffer);
-       }
+       kfree(urb->transfer_buffer);
 
        /* Free the command urb */
        usb_free_urb (urb);
@@ -951,11 +746,11 @@ static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs)
 
        /* tell the tty driver that something has changed */
        if (tty && edge_port->open)
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
 
        /* we have completed the command */
        edge_port->commandPending = FALSE;
-       wake_up_interruptible(&edge_port->wait_command);
+       wake_up(&edge_port->wait_command);
 }
 
 
@@ -975,18 +770,14 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
        struct usb_serial *serial;
        struct edgeport_serial *edge_serial;
        int response;
-       int timeout;
 
        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;
 
        /* see if we've set up our endpoint info yet (can't set it up in edge_startup
           as the structures were not set up at that time.) */
@@ -1024,6 +815,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
                                  port0->bulk_in_buffer,
                                  edge_serial->read_urb->transfer_buffer_length,
                                  edge_bulk_in_callback, edge_serial);
+               edge_serial->read_in_progress = FALSE;
 
                /* start interrupt read for this edgeport
                 * this interrupt will continue as long as the edgeport is connected */
@@ -1059,10 +851,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
        }
 
        /* now wait for the port to be completely opened */
-       timeout = OPEN_TIMEOUT;
-       while (timeout && edge_port->openPending == TRUE) {
-               timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
-       }
+       wait_event_timeout(edge_port->wait_open, (edge_port->openPending != TRUE), OPEN_TIMEOUT);
 
        if (edge_port->open == FALSE) {
                /* open timed out */
@@ -1086,6 +875,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
 
        /* Allocate a URB for the write */
        edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
+       edge_port->write_in_progress = FALSE;
 
        if (!edge_port->write_urb) {
                dbg("%s - no memory", __FUNCTION__);
@@ -1113,9 +903,10 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
  ************************************************************************/
 static void block_until_chase_response(struct edgeport_port *edge_port)
 {
+       DEFINE_WAIT(wait);
        __u16 lastCredits;
        int timeout = 1*HZ;
-       int wait = 10;
+       int loop = 10;
 
        while (1) {
                // Save Last credits
@@ -1133,12 +924,14 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
                }
 
                // Block the thread for a while
-               interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+               prepare_to_wait(&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE);
+               schedule_timeout(timeout);
+               finish_wait(&edge_port->wait_chase, &wait);
 
                if (lastCredits == edge_port->txCredits) {
                        // No activity.. count down.
-                       wait--;
-                       if (wait == 0) {
+                       loop--;
+                       if (loop == 0) {
                                edge_port->chaseResponsePending = FALSE;
                                dbg("%s - Chase TIMEOUT", __FUNCTION__);
                                return;
@@ -1146,7 +939,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
                } else {
                        // Reset timout value back to 10 seconds
                        dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
-                       wait = 10;
+                       loop = 10;
                }
        }
 }
@@ -1164,10 +957,11 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
  ************************************************************************/
 static void block_until_tx_empty (struct edgeport_port *edge_port)
 {
+       DEFINE_WAIT(wait);
        struct TxFifo *fifo = &edge_port->txfifo;
        __u32 lastCount;
        int timeout = HZ/10;
-       int wait = 30;
+       int loop = 30;
 
        while (1) {
                // Save Last count
@@ -1180,20 +974,22 @@ static void block_until_tx_empty (struct edgeport_port *edge_port)
                }
 
                // Block the thread for a while
-               interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+               prepare_to_wait (&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE);
+               schedule_timeout(timeout);
+               finish_wait(&edge_port->wait_chase, &wait);
 
                dbg("%s wait", __FUNCTION__);
 
                if (lastCount == fifo->count) {
                        // No activity.. count down.
-                       wait--;
-                       if (wait == 0) {
+                       loop--;
+                       if (loop == 0) {
                                dbg("%s - TIMEOUT", __FUNCTION__);
                                return;
                        }
                } else {
                        // Reset timout value back to seconds
-                       wait = 30;
+                       loop = 30;
                }
        }
 }
@@ -1243,19 +1039,17 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
        edge_port->openPending = FALSE;
 
        if (edge_port->write_urb) {
-               usb_unlink_urb (edge_port->write_urb);
+               usb_kill_urb(edge_port->write_urb);
        }
 
        if (edge_port->write_urb) {
                /* if this urb had a transfer buffer already (old transfer) free it */
-               if (edge_port->write_urb->transfer_buffer != NULL) {
-                       kfree(edge_port->write_urb->transfer_buffer);
-               }
-               usb_free_urb   (edge_port->write_urb);
-       }
-       if (edge_port->txfifo.fifo) {
-               kfree(edge_port->txfifo.fifo);
+               kfree(edge_port->write_urb->transfer_buffer);
+               usb_free_urb(edge_port->write_urb);
+               edge_port->write_urb = NULL;
        }
+       kfree(edge_port->txfifo.fifo);
+       edge_port->txfifo.fifo = NULL;
 
        dbg("%s exited", __FUNCTION__);
 }   
@@ -1267,14 +1061,15 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
  *     If successful, we return the number of bytes written, otherwise we return
  *     a negative error number.
  *****************************************************************************/
-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 edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        struct TxFifo *fifo;
        int copySize;
        int bytesleft;
        int firsthalf;
        int secondhalf;
+       unsigned long flags;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -1284,6 +1079,8 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign
        // get a pointer to the Tx fifo
        fifo = &edge_port->txfifo;
 
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
+
        // calculate number of bytes to put in fifo
        copySize = min ((unsigned int)count, (edge_port->txCredits - fifo->count));
 
@@ -1293,7 +1090,7 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign
        /* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */
        if (copySize == 0) {
                dbg("%s - copySize = Zero", __FUNCTION__);
-               return 0;
+               goto finish_write;
        }
 
        // queue the data       
@@ -1307,12 +1104,7 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign
        dbg("%s - copy %d bytes of %d into fifo ", __FUNCTION__, firsthalf, bytesleft);
 
        /* now copy our data */
-       if (from_user) {
-               if (copy_from_user(&fifo->fifo[fifo->head], data, firsthalf))
-                       return -EFAULT;
-       } else {
-               memcpy(&fifo->fifo[fifo->head], data, firsthalf);
-       }  
+       memcpy(&fifo->fifo[fifo->head], data, firsthalf);
        usb_serial_debug_data(debug, &port->dev, __FUNCTION__, firsthalf, &fifo->fifo[fifo->head]);
 
        // update the index and size
@@ -1328,12 +1120,7 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign
 
        if (secondhalf) {
                dbg("%s - copy rest of data %d", __FUNCTION__, secondhalf);
-               if (from_user) {
-                       if (copy_from_user(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf))
-                               return -EFAULT;
-               } else {
-                       memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
-               }
+               memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
                usb_serial_debug_data(debug, &port->dev, __FUNCTION__, secondhalf, &fifo->fifo[fifo->head]);
                // update the index and size
                fifo->count += secondhalf;
@@ -1341,6 +1128,9 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign
                // No need to check for wrap since we can not get to end of fifo in this part
        }
 
+finish_write:
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
        send_more_port_data((struct edgeport_serial *)usb_get_serial_data(port->serial), edge_port);
 
        dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __FUNCTION__, copySize, edge_port->txCredits, fifo->count);
@@ -1372,14 +1162,17 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
        int             bytesleft;
        int             firsthalf;
        int             secondhalf;
+       unsigned long   flags;
 
        dbg("%s(%d)", __FUNCTION__, edge_port->port->number);
 
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
+
        if (edge_port->write_in_progress ||
            !edge_port->open             ||
            (fifo->count == 0)) {
                dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->write_in_progress);
-               return;
+               goto exit_send;
        }
 
        // since the amount of data in the fifo will always fit into the
@@ -1389,9 +1182,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
        //      to bother queueing a write. If it's too small, say a few bytes,
        //      it's better to wait for more credits so we can do a larger
        //      write.
-       if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) {
+       if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits,EDGE_FW_BULK_MAX_PACKET_SIZE)) {
                dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits );
-               return;
+               goto exit_send;
        }
 
        // lock this write
@@ -1400,11 +1193,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
        // get a pointer to the write_urb
        urb = edge_port->write_urb;
 
-       /* if this urb had a transfer buffer already (old transfer) free it */
-       if (urb->transfer_buffer != NULL) {
-               kfree(urb->transfer_buffer);
-               urb->transfer_buffer = NULL;
-       }
+       /* make sure transfer buffer is freed */
+       kfree(urb->transfer_buffer);
+       urb->transfer_buffer = NULL;
 
        /* build the data header for the buffer and port that we are about to send out */
        count = fifo->count;
@@ -1412,7 +1203,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
        if (buffer == NULL) {
                dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __FUNCTION__);
                edge_port->write_in_progress = FALSE;
-               return;
+               goto exit_send;
        }
        buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number - edge_port->port->serial->minor, count);
        buffer[1] = IOSP_BUILD_DATA_HDR2 (edge_port->port->number - edge_port->port->serial->minor, count);
@@ -1450,7 +1241,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status) {
                /* something went wrong */
-               dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
+               dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __FUNCTION__, status);
                edge_port->write_in_progress = FALSE;
 
                /* revert the credits as something bad happened. */
@@ -1458,6 +1249,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
                edge_port->icount.tx -= count;
        }
        dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count, edge_port->txCredits, fifo->count);
+
+exit_send:
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 }
 
 
@@ -1471,8 +1265,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
  *****************************************************************************/
 static int edge_write_room (struct usb_serial_port *port)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        int room;
+       unsigned long flags;
 
        dbg("%s", __FUNCTION__);
 
@@ -1489,7 +1284,9 @@ static int edge_write_room (struct usb_serial_port *port)
        }
 
        // total of both buffers is still txCredit
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
        room = edge_port->txCredits - edge_port->txfifo.count;
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
        dbg("%s - returns %d", __FUNCTION__, room);
        return room;
@@ -1507,8 +1304,9 @@ static int edge_write_room (struct usb_serial_port *port)
  *****************************************************************************/
 static int edge_chars_in_buffer (struct usb_serial_port *port)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        int num_chars;
+       unsigned long flags;
 
        dbg("%s", __FUNCTION__);
 
@@ -1522,7 +1320,9 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
                return -EINVAL;
        }
 
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
        num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count;
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
        if (num_chars) {
                dbg("%s(port %d) - returns %d", __FUNCTION__, port->number, num_chars);
        }
@@ -1538,7 +1338,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
  *****************************************************************************/
 static void edge_throttle (struct usb_serial_port *port)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        struct tty_struct *tty;
        int status;
 
@@ -1561,7 +1361,7 @@ static void edge_throttle (struct usb_serial_port *port)
        /* 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;
                }
@@ -1587,7 +1387,7 @@ static void edge_throttle (struct usb_serial_port *port)
  *****************************************************************************/
 static void edge_unthrottle (struct usb_serial_port *port)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        struct tty_struct *tty;
        int status;
 
@@ -1610,7 +1410,7 @@ 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;
                }
@@ -1635,7 +1435,7 @@ static void edge_unthrottle (struct usb_serial_port *port)
  *****************************************************************************/
 static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        struct tty_struct *tty = port->tty;
        unsigned int cflag;
 
@@ -1647,20 +1447,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);
@@ -1693,12 +1491,15 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
 static int get_lsr_info(struct edgeport_port *edge_port, unsigned int __user *value)
 {
        unsigned int result = 0;
+       unsigned long flags;
 
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
        if (edge_port->maxTxCredits == edge_port->txCredits &&
            edge_port->txfifo.count == 0) {
                dbg("%s -- Empty", __FUNCTION__);
                result = TIOCSER_TEMT;
        }
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
        if (copy_to_user(value, &result, sizeof(int)))
                return -EFAULT;
@@ -1724,7 +1525,7 @@ static int get_number_bytes_avail(struct edgeport_port *edge_port, unsigned int
 
 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);
@@ -1753,7 +1554,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;
@@ -1810,12 +1611,12 @@ static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct
  *****************************************************************************/
 static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       DEFINE_WAIT(wait);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        struct async_icount cnow;
        struct async_icount cprev;
        struct serial_icounter_struct icount;
 
-
        dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
 
        switch (cmd) {
@@ -1842,7 +1643,9 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
                        dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
                        cprev = edge_port->icount;
                        while (1) {
-                               interruptible_sleep_on(&edge_port->delta_msr_wait);
+                               prepare_to_wait(&edge_port->delta_msr_wait, &wait, TASK_INTERRUPTIBLE);
+                               schedule();
+                               finish_wait(&edge_port->delta_msr_wait, &wait);
                                /* see if a signal did it */
                                if (signal_pending(current))
                                        return -ERESTARTSYS;
@@ -1892,7 +1695,7 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
  *****************************************************************************/
 static void edge_break (struct usb_serial_port *port, int break_state)
 {
-        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        int status;
 
        /* flush and chase */
@@ -1926,14 +1729,13 @@ static void edge_break (struct usb_serial_port *port, int break_state)
  * process_rcvd_data
  *     this function handles the data received on the bulk in pipe.
  *****************************************************************************/
-static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char * buffer, __u16 bufferLength)
+static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char * buffer, __u16 bufferLength)
 {
        struct usb_serial_port *port;
        struct edgeport_port *edge_port;
        struct tty_struct *tty;
        __u16 lastBufferLength;
        __u16 rxLen;
-       int i;
 
        dbg("%s", __FUNCTION__);
 
@@ -1988,7 +1790,6 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char
 
                                        // We have all the header bytes, process the status now
                                        process_rcvd_status (edge_serial, edge_serial->rxHeader2, 0);
-
                                        edge_serial->rxState = EXPECT_HDR1;
                                        break;
                                } else {
@@ -2029,15 +1830,7 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char
                                                tty = edge_port->port->tty;
                                                if (tty) {
                                                        dbg("%s - Sending %d bytes to TTY for port %d", __FUNCTION__, rxLen, edge_serial->rxPort);
-                                                       for (i = 0; i < rxLen ; ++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, buffer[i], 0);
-                                                       }
-                                                       tty_flip_buffer_push(tty);
+                                                       edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
                                                }
                                                edge_port->icount.rx += rxLen;
                                        }
@@ -2058,8 +1851,6 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char
 
                }
        }
-
-       return 0;
 }
 
 
@@ -2075,7 +1866,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
 
        /* switch the port pointer to the one being currently talked about */
        port = edge_serial->serial->port[edge_serial->rxPort];
-        edge_port = usb_get_serial_port_data(port);
+       edge_port = usb_get_serial_port_data(port);
        if (edge_port == NULL) {
                dev_err(&edge_serial->serial->dev->dev, "%s - edge_port == NULL for port %d\n", __FUNCTION__, edge_serial->rxPort);
                return;
@@ -2094,7 +1885,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
                                // We could choose to do something else when Byte3 says Timeout on Chase from Edgeport,
                                // like wait longer in block_until_chase_response, but for now we don't. 
                                edge_port->chaseResponsePending = FALSE;
-                               wake_up_interruptible (&edge_port->wait_chase);
+                               wake_up (&edge_port->wait_chase);
                                return;
 
                        case IOSP_EXT_STATUS_RX_CHECK_RSP:
@@ -2117,7 +1908,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
                /* we have completed the open */
                edge_port->openPending = FALSE;
                edge_port->open = TRUE;
-               wake_up_interruptible(&edge_port->wait_open);
+               wake_up(&edge_port->wait_open);
                return;
        }
 
@@ -2164,6 +1955,31 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
 }
 
 
+/*****************************************************************************
+ * edge_tty_recv
+ *     this function passes data on to the tty flip buffer
+ *****************************************************************************/
+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);
+}
+
+
 /*****************************************************************************
  * handle_new_msr
  *     this function handles any change to the msr register for a port.
@@ -2223,10 +2039,8 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 l
        }
 
        /* Place LSR data byte into Rx buffer */
-       if (lsrData && edge_port->port->tty) {
-               tty_insert_flip_char(edge_port->port->tty, data, 0);
-               tty_flip_buffer_push(edge_port->port->tty);
-       }
+       if (lsrData && 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;
@@ -2447,18 +2261,17 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
 
        if (status) {
                /* something went wrong */
-               dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
-               usb_unlink_urb (urb);
-               usb_free_urb   (urb);
+               dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command) failed, status = %d\n", __FUNCTION__, status);
+               usb_kill_urb(urb);
+               usb_free_urb(urb);
+               CmdUrbs--;
                return status;
        }
 
        // wait for command to finish
        timeout = COMMAND_TIMEOUT;
 #if 0
-       while (timeout && edge_port->commandPending == TRUE) {
-               timeout = interruptible_sleep_on_timeout (&edge_port->wait_command, timeout);
-       }
+       wait_event (&edge_port->wait_command, (edge_port->commandPending == FALSE));
 
        if (edge_port->commandPending == TRUE) {
                /* command timed out */
@@ -2529,13 +2342,11 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
 {
        int i;
        __u16 custom;
-       __u16 round1;
-       __u16 round;
 
 
        dbg("%s - %d", __FUNCTION__, baudrate);
 
-       for (i = 0; i < NUM_ENTRIES(divisor_table); i++) {
+       for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
                if ( divisor_table[i].BaudRate == baudrate ) {
                        *divisor = divisor_table[i].Divisor;
                        return 0;
@@ -2545,16 +2356,10 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
        // We have tried all of the standard baud rates
        // lets try to calculate the divisor for this baud rate
        // Make sure the baud rate is reasonable
-       if (baudrate < 230400) {
+       if (baudrate > 50 && baudrate < 230400) {
                // get divisor
-               custom = (__u16)(230400L  / baudrate);
+               custom = (__u16)((230400L + baudrate/2) / baudrate);
 
-               // Check for round off
-               round1 = (__u16)(2304000L / baudrate);
-               round = (__u16)(round1 - (custom * 10));
-               if (round > 4) {
-                       custom++;
-               }
                *divisor = custom;
 
                dbg("%s - Baud %d = %d\n", __FUNCTION__, baudrate, custom);
@@ -2606,6 +2411,9 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
  *     This routine is called to set the UART on the device to match the specified
  *     new settings.
  *****************************************************************************/
+#ifndef CMSPAR
+#define CMSPAR 0
+#endif
 static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
 {
        struct tty_struct *tty;
@@ -2646,7 +2454,15 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
 
        lParity = LCR_PAR_NONE;
        if (cflag & PARENB) {
-               if (cflag & PARODD) {
+               if (cflag & CMSPAR) {
+                       if (cflag & PARODD) {
+                               lParity = LCR_PAR_MARK;
+                               dbg("%s - parity = mark", __FUNCTION__);
+                       } else {
+                               lParity = LCR_PAR_SPACE;
+                               dbg("%s - parity = space", __FUNCTION__);
+                       }
+               } else if (cflag & PARODD) {
                        lParity = LCR_PAR_ODD;
                        dbg("%s - parity = odd", __FUNCTION__);
                } else {
@@ -2747,13 +2563,20 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
  *     ASCII range, but it's only for debugging...
  *     NOTE: expects the unicode in LE format
  ****************************************************************************/
-static void unicode_to_ascii (char *string, short *unicode, int unicode_size)
+static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size)
 {
        int i;
-       for (i = 0; i < unicode_size; ++i) {
+
+       if (buflen <= 0)        /* never happens, but... */
+               return;
+       --buflen;               /* space for nul */
+
+       for (i = 0; i < unicode_size; i++) {
+               if (i >= buflen)
+                       break;
                string[i] = (char)(le16_to_cpu(unicode[i]));
        }
-       string[unicode_size] = 0x00;
+       string[i] = 0x00;
 }
 
 
@@ -2783,11 +2606,17 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial)
                dbg("  BoardRev:       %d", edge_serial->manuf_descriptor.BoardRev);
                dbg("  NumPorts:       %d", edge_serial->manuf_descriptor.NumPorts);
                dbg("  DescDate:       %d/%d/%d", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900);
-               unicode_to_ascii (string, edge_serial->manuf_descriptor.SerialNumber, edge_serial->manuf_descriptor.SerNumLength/2-1);
+               unicode_to_ascii(string, sizeof(string),
+                   edge_serial->manuf_descriptor.SerialNumber,
+                   edge_serial->manuf_descriptor.SerNumLength/2);
                dbg("  SerialNumber: %s", string);
-               unicode_to_ascii (string, edge_serial->manuf_descriptor.AssemblyNumber, edge_serial->manuf_descriptor.AssemblyNumLength/2-1);
+               unicode_to_ascii(string, sizeof(string),
+                   edge_serial->manuf_descriptor.AssemblyNumber,
+                   edge_serial->manuf_descriptor.AssemblyNumLength/2);
                dbg("  AssemblyNumber: %s", string);
-               unicode_to_ascii (string, edge_serial->manuf_descriptor.OemAssyNumber, edge_serial->manuf_descriptor.OemAssyNumLength/2-1);
+               unicode_to_ascii(string, sizeof(string),
+                   edge_serial->manuf_descriptor.OemAssyNumber,
+                   edge_serial->manuf_descriptor.OemAssyNumLength/2);
                dbg("  OemAssyNumber:  %s", string);
                dbg("  UartType:       %d", edge_serial->manuf_descriptor.UartType);
                dbg("  IonPid:         %d", edge_serial->manuf_descriptor.IonPid);
@@ -2873,7 +2702,7 @@ static void load_application_firmware (struct edgeport_serial *edge_serial)
                record = (struct edge_firmware_image_record *)firmware;
                response = sram_write (edge_serial->serial, le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len), &record->Data[0]);
                if (response < 0) {
-                       dev_err(&edge_serial->serial->dev->dev, "sram_write failed (%x, %x, %d)\n", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), record->Len);
+                       dev_err(&edge_serial->serial->dev->dev, "sram_write failed (%x, %x, %d)\n", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len));
                        break;
                }
                firmware += sizeof (struct edge_firmware_image_record) + le16_to_cpu(record->Len);
@@ -2892,8 +2721,6 @@ static void load_application_firmware (struct edgeport_serial *edge_serial)
 }
 
 
-
-
 /****************************************************************************
  * edge_startup
  ****************************************************************************/
@@ -2902,26 +2729,26 @@ static int edge_startup (struct usb_serial *serial)
        struct edgeport_serial *edge_serial;
        struct edgeport_port *edge_port;
        struct usb_device *dev;
-       int i;
+       int i, j;
 
        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", __FUNCTION__);
+               dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset (edge_serial, 0, sizeof(struct edgeport_serial));
+       spin_lock_init(&edge_serial->es_lock);
        edge_serial->serial = serial;
        usb_set_serial_data(serial, edge_serial);
 
        /* get the name for the device from the device */
-       if ( (i = get_string(dev, dev->descriptor.iManufacturer, &edge_serial->name[0])) != 0) {
-               edge_serial->name[i-1] = ' ';
-       }
-
-       get_string(dev, dev->descriptor.iProduct, &edge_serial->name[i]);
+       i = get_string(dev, dev->descriptor.iManufacturer,
+           &edge_serial->name[0], MAX_NAME_LEN+1);
+       edge_serial->name[i++] = ' ';
+       get_string(dev, dev->descriptor.iProduct,
+           &edge_serial->name[i], MAX_NAME_LEN+2 - i);
 
        dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
@@ -2965,12 +2792,17 @@ static int edge_startup (struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; ++i) {
                edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
                if (edge_port == NULL) {
-                       dev_err(&serial->dev->dev, "%s - Out of memory", __FUNCTION__);
+                       dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+                       for (j = 0; j < i; ++j) {
+                               kfree (usb_get_serial_port_data(serial->port[j]));
+                               usb_set_serial_port_data(serial->port[j],  NULL);
+                       }
                        usb_set_serial_data(serial, NULL);
                        kfree(edge_serial);
                        return -ENOMEM;
                }
                memset (edge_port, 0, sizeof(struct edgeport_port));
+               spin_lock_init(&edge_port->ep_lock);
                edge_port->port = serial->port[i];
                usb_set_serial_port_data(serial->port[i], edge_port);
        }
@@ -2979,7 +2811,6 @@ static int edge_startup (struct usb_serial *serial)
 }
 
 
-
 /****************************************************************************
  * edge_shutdown
  *     This function is called whenever the device is removed from the usb bus.
@@ -3007,9 +2838,7 @@ static void edge_shutdown (struct usb_serial *serial)
 static int __init edgeport_init(void)
 {
        int retval;
-       retval = usb_serial_register(&edgeport_1port_device);
-       if (retval) 
-               goto failed_1port_device_register;
+
        retval = usb_serial_register(&edgeport_2port_device);
        if (retval)
                goto failed_2port_device_register;
@@ -3024,6 +2853,7 @@ static int __init edgeport_init(void)
                goto failed_usb_register;
        info(DRIVER_DESC " " DRIVER_VERSION);
        return 0;
+
 failed_usb_register:
        usb_serial_deregister(&edgeport_8port_device);
 failed_8port_device_register:
@@ -3031,13 +2861,10 @@ failed_8port_device_register:
 failed_4port_device_register:
        usb_serial_deregister(&edgeport_2port_device);
 failed_2port_device_register:
-       usb_serial_deregister(&edgeport_1port_device);
-failed_1port_device_register:
        return retval;
 }
 
 
-
 /****************************************************************************
  * edgeport_exit
  *     Called when the driver is about to be unloaded.
@@ -3045,7 +2872,6 @@ failed_1port_device_register:
 static void __exit edgeport_exit (void)
 {
        usb_deregister (&io_driver);
-       usb_serial_deregister (&edgeport_1port_device);
        usb_serial_deregister (&edgeport_2port_device);
        usb_serial_deregister (&edgeport_4port_device);
        usb_serial_deregister (&edgeport_8port_device);
@@ -3061,3 +2887,6 @@ MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+module_param(low_latency, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(low_latency, "Low latency enabled or not");