--- linux-2.6.13/drivers/usb/serial/ftdi_sio.h
+++ linux-2.6.13/drivers/usb/serial/ftdi_sio.h
@@ -44,6 +44,15 @@
 #define FTDI_XF_635_PID 0xFC0D	/* 635: 20x4 Character Display */
 #define FTDI_XF_640_PID 0xFC0E	/* 640: Two line Display */
 #define FTDI_XF_642_PID 0xFC0F	/* 642: Two line Display */
+#define WBE_VID                      0x104F
+#define WBE_SMARTMOUSE_PID1   0x0001  /* Smartmouse USB */
+#define WBE_SMARTMOUSE_PID2   0x0002  /* Smartmouse USB */
+#define WBE_SMARTMOUSE_PID3   0x0003  /* Smartmouse USB */
+#define WBE_SMARTMOUSE_PID4   0x0004  /* Smartmouse USB */
+#define FTDI_8U232AM_PID1 0x6001 /* FTDI USB2Serial */
+#define FTDI_8U232AM_PID2 0x6002 /* FTDI USB2Serial */
+#define FTDI_8U232AM_PID3 0x6003 /* FTDI USB2Serial */
+#define FTDI_8U232AM_PID4 0x6004 /* FTDI USB2Serial */
 
 /* Video Networks Limited / Homechoice in the UK use an ftdi-based device for their 1Mb */
 /* broadband internet service.  The following PID is exhibited by the usb device supplied */

--- linux-2.6.13/drivers/usb/serial/ftdi_sio.c
+++ linux-2.6.13/drivers/usb/serial/ftdi_sio.c
@@ -258,6 +258,7 @@
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/serial.h>
+#include <linux/circ_buf.h>
 #include "usb-serial.h"
 #include "ftdi_sio.h"
 
@@ -432,6 +433,14 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
 	{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
+	{ USB_DEVICE(WBE_VID, WBE_SMARTMOUSE_PID1) },
+	{ USB_DEVICE(WBE_VID, WBE_SMARTMOUSE_PID2) },
+	{ USB_DEVICE(WBE_VID, WBE_SMARTMOUSE_PID3) },
+	{ USB_DEVICE(WBE_VID, WBE_SMARTMOUSE_PID4) },
+	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID1) },
+	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID2) },
+	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID3) },
+	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID4) },
 	{ }						/* Terminating entry */
 };
 
@@ -456,6 +461,9 @@
 #define BUFSZ 512
 #define PKTSZ 64
 
+/* size of write buffer */
+#define SERIAL_BUF_SIZE		1024
+
 /* rx_flags */
 #define THROTTLED		0x01
 #define ACTUALLY_THROTTLED	0x02
@@ -483,6 +491,11 @@
 
 	int force_baud;		/* if non-zero, force the baud rate to this value */
 	int force_rtscts;	/* if non-zero, force RTS-CTS to always be enabled */
+
+	spinlock_t lock;	/* private lock */
+
+	struct circ_buf *buf;	/* write buffer */
+	int write_urb_in_use;	/* write urb in use indicator */
 };
 
 /* Used for TIOCMIWAIT */
@@ -500,6 +513,7 @@
 static int  ftdi_open			(struct usb_serial_port *port, struct file *filp);
 static void ftdi_close			(struct usb_serial_port *port, struct file *filp);
 static int  ftdi_write			(struct usb_serial_port *port, const unsigned char *buf, int count);
+static void ftdi_send                   (struct usb_serial_port *port);
 static int  ftdi_write_room		(struct usb_serial_port *port);
 static int  ftdi_chars_in_buffer	(struct usb_serial_port *port);
 static void ftdi_write_bulk_callback	(struct urb *urb, struct pt_regs *regs);
@@ -513,6 +527,14 @@
 static void ftdi_throttle		(struct usb_serial_port *port);
 static void ftdi_unthrottle		(struct usb_serial_port *port);
 
+/* circular buffer */
+static struct circ_buf *serial_buf_alloc(void);
+static void serial_buf_free(struct circ_buf *cb);
+static void serial_buf_clear(struct circ_buf *cb);
+static int serial_buf_data_avail(struct circ_buf *cb);
+static int serial_buf_put(struct circ_buf *cb, const char *buf, int count);
+static int serial_buf_get(struct circ_buf *cb, char *buf, int count);
+
 static unsigned short int ftdi_232am_baud_base_to_divisor (int baud, int base);
 static unsigned short int ftdi_232am_baud_to_divisor (int baud);
 static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
@@ -874,7 +896,7 @@
 	unsigned interfaces;
 
 	/* Assume it is not the original SIO device for now. */
-	priv->baud_base = 48000000 / 16;
+	priv->baud_base = 48000000 / 2;
 	priv->write_offset = 0;
 
 	version = le16_to_cpu(udev->descriptor.bcdDevice);
@@ -1074,6 +1096,7 @@
 	struct usb_serial_port *port = serial->port[0];
 	struct ftdi_private *priv;
 	struct ftdi_sio_quirk *quirk;
+	char *transfer_buffer;
 	
 	dbg("%s",__FUNCTION__);
 
@@ -1083,6 +1106,7 @@
 		return -ENOMEM;
 	}
 	memset(priv, 0, sizeof(*priv));
+	spin_lock_init(&priv->lock);
 
 	spin_lock_init(&priv->rx_lock);
         init_waitqueue_head(&priv->delta_msr_wait);
@@ -1103,14 +1127,22 @@
 	}
 
 	INIT_WORK(&priv->rx_work, ftdi_process_read, port);
+    
+	/* Try to increase the size of write buffer */
+	transfer_buffer = kmalloc(SERIAL_BUF_SIZE, GFP_KERNEL);
+
+	if (transfer_buffer) {
+                port->write_urb->transfer_buffer = transfer_buffer;
+                port->write_urb->transfer_buffer_length = SERIAL_BUF_SIZE;
+	} 
 
 	/* Free port's existing write urb and transfer buffer. */
-	if (port->write_urb) {
-		usb_free_urb (port->write_urb);
-		port->write_urb = NULL;
+	priv->buf = serial_buf_alloc();
+	if (priv->buf == NULL) {
+		kfree(port->bulk_in_buffer);
+		kfree(priv);
+		return -ENOMEM;
 	}
-	kfree(port->bulk_out_buffer);
-	port->bulk_out_buffer = NULL;
 
 	usb_set_serial_port_data(serial->port[0], priv);
 
@@ -1182,6 +1214,7 @@
 	 */
 
 	if (priv) {
+		serial_buf_free(priv->buf);
 		usb_set_serial_port_data(port, NULL);
 		kfree(priv);
 	}
@@ -1194,7 +1227,7 @@
 	struct usb_device *dev = port->serial->dev;
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
-	
+
 	int result = 0;
 	char buf[1]; /* Needed for the usb_control_msg I think */
 
@@ -1277,133 +1310,138 @@
 	/* cancel any scheduled reading */
 	cancel_delayed_work(&priv->rx_work);
 	flush_scheduled_work();
-	
+
 	/* shutdown our bulk read */
 	if (port->read_urb)
 		usb_kill_urb(port->read_urb);
-} /* ftdi_close */
 
+	/* shutdown our bulk write */
+	if (port->write_urb)
+	        usb_kill_urb(port->write_urb);
+} /* ftdi_close */
 
-  
-/* The SIO requires the first byte to have:
- *  B0 1
- *  B1 0
- *  B2..7 length of message excluding byte 0
- *
- * The new devices do not require this byte
- */
-static int ftdi_write (struct usb_serial_port *port,
-			   const unsigned char *buf, int count)
+static int ftdi_write(struct usb_serial_port *port, const unsigned char *buf, int count)
 { /* ftdi_write */
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
-	struct urb *urb;
-	unsigned char *buffer;
+	unsigned long flags;
+	
+	dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+
+	if (!count)
+		return count;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	count = serial_buf_put(priv->buf, buf, count);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	ftdi_send(port);
+
+	return count;
+} /* ftdi_write */
+
+
+static void ftdi_send(struct usb_serial_port *port)
+{
+	int count, result;
+	struct ftdi_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 	int data_offset ;       /* will be 1 for the SIO and 0 otherwise */
-	int status;
-	int transfer_size;
 
-	dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (count == 0) {
-		dbg("write request of 0 bytes");
-		return 0;
-	}
-	
-	data_offset = priv->write_offset;
-        dbg("data_offset set to %d",data_offset);
+	spin_lock_irqsave(&priv->lock, flags);
 
-	/* Determine total transfer size */
-	transfer_size = count;
-	if (data_offset > 0) {
-		/* Original sio needs control bytes too... */
-		transfer_size += (data_offset *
-				((count + (PKTSZ - 1 - data_offset)) /
-				 (PKTSZ - data_offset)));
+	if (priv->write_urb_in_use) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return;
 	}
 
-	buffer = kmalloc (transfer_size, GFP_ATOMIC);
-	if (!buffer) {
-		err("%s ran out of kernel memory for urb ...", __FUNCTION__);
-		return -ENOMEM;
-	}
+	data_offset = priv->write_offset;
+        dbg("data_offset set to %d",data_offset);
 
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
-	if (!urb) {
-		err("%s - no more free urbs", __FUNCTION__);
-		kfree (buffer);
-		return -ENOMEM;
+        if (data_offset > 0) {
+                int len = port->bulk_out_size;
+		unsigned char *first_byte = port->write_urb->transfer_buffer;
+
+                count = 0;
+
+                while (serial_buf_data_avail(priv->buf) && len > 1) {
+                       int toget = min(len - data_offset, PKTSZ - data_offset);
+                        int cnt;
+
+        	        cnt = serial_buf_get(priv->buf, first_byte + data_offset,
+		                                toget);
+                        *first_byte |= 1 | (cnt << 2);
+                        first_byte += cnt + data_offset;
+                        len -= cnt + data_offset;
+                        count += cnt + data_offset;
+                }
+        } else {
+	        count = serial_buf_get(priv->buf, port->write_urb->transfer_buffer,
+		                            port->bulk_out_size);
 	}
 
-	/* Copy data */
-	if (data_offset > 0) {
-		/* Original sio requires control byte at start of each packet. */
-		int user_pktsz = PKTSZ - data_offset;
-		int todo = count;
-		unsigned char *first_byte = buffer;
-		const unsigned char *current_position = buf;
-
-		while (todo > 0) {
-			if (user_pktsz > todo) {
-				user_pktsz = todo;
-			}
-			/* Write the control byte at the front of the packet*/
-			*first_byte = 1 | ((user_pktsz) << 2); 
-			/* Copy data for packet */
-			memcpy (first_byte + data_offset,
-				current_position, user_pktsz);
-			first_byte += user_pktsz + data_offset;
-			current_position += user_pktsz;
-			todo -= user_pktsz;
-		}
-	} else {
-		/* No control byte required. */
-		/* Copy in the data to send */
-		memcpy (buffer, buf, count);
+	if (count == 0) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer);
+	priv->write_urb_in_use = 1;
+	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* fill the buffer and send it */
-	usb_fill_bulk_urb(urb, port->serial->dev, 
-		      usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
-		      buffer, transfer_size,
-		      ftdi_write_bulk_callback, port);
+	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
 
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status) {
-		err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
-		count = status;
-		kfree (buffer);
+	port->write_urb->transfer_buffer_length = count;
+	port->write_urb->dev = port->serial->dev;
+	result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
+	if (result) {
+		dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
+		priv->write_urb_in_use = 0;
+		// TODO: reschedule pl2303_send
 	}
 
-	/* we are done with this urb, so let the host driver
-	 * really free it when it is finished with it */
-	usb_free_urb (urb);
-
-	dbg("%s write returning: %d", __FUNCTION__, count);
-	return count;
-} /* ftdi_write */
-
+	schedule_work(&port->work);
+}
 
-/* This function may get called when the device is closed */
+// /* This function may get called when the device is closed */
 
 static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-
-	/* free up the transfer buffer, as usb_free_urb() does not do this */
-	kfree (urb->transfer_buffer);
+	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+	struct ftdi_private *priv = usb_get_serial_port_data(port);
+	int result;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	
-	if (urb->status) {
-		dbg("nonzero write bulk status received: %d", urb->status);
+
+	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);
+		priv->write_urb_in_use = 0;
 		return;
+	default:
+		/* error in the urb, so we have to resubmit it */
+		dbg("%s - Overflow in write", __FUNCTION__);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+		port->write_urb->transfer_buffer_length = 1;
+		port->write_urb->dev = port->serial->dev;
+		result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
+		if (result)
+			dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result);
+		else
+			return;
 	}
 
-	schedule_work(&port->work);
-} /* ftdi_write_bulk_callback */
+	priv->write_urb_in_use = 0;
 
+	/* send any buffered data */
+	ftdi_send(port);
+}
 
 static int ftdi_write_room( struct usb_serial_port *port )
 {
@@ -2025,6 +2063,129 @@
 		schedule_work(&priv->rx_work);
 }
 
+/* Circular Buffer Functions, code from ti_usb_3410_5052 used */
+
+/*
+ * serial_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+
+static struct circ_buf *serial_buf_alloc(void)
+{
+	struct circ_buf *cb;
+
+	cb = (struct circ_buf *)kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
+	if (cb == NULL)
+		return NULL;
+
+	cb->buf = kmalloc(SERIAL_BUF_SIZE, GFP_KERNEL);
+	if (cb->buf == NULL) {
+		kfree(cb);
+		return NULL;
+	}
+
+	serial_buf_clear(cb);
+
+	return cb;
+}
+
+
+/*
+ * serial_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+
+static void serial_buf_free(struct circ_buf *cb)
+{
+	kfree(cb->buf);
+	kfree(cb);
+}
+
+
+/*
+ * serial_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+
+static void serial_buf_clear(struct circ_buf *cb)
+{
+	cb->head = cb->tail = 0;
+}
+
+
+/*
+ * serial_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+
+static int serial_buf_data_avail(struct circ_buf *cb)
+{
+	return CIRC_CNT(cb->head,cb->tail,SERIAL_BUF_SIZE);
+}
+
+/*
+ * serial_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 int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
+{
+	int c, ret = 0;
+
+	while (1) {
+		c = CIRC_SPACE_TO_END(cb->head, cb->tail, SERIAL_BUF_SIZE);
+		if (count < c)
+			c = count;
+		if (c <= 0)
+			break;
+		memcpy(cb->buf + cb->head, buf, c);
+		cb->head = (cb->head + c) & (SERIAL_BUF_SIZE-1);
+		buf += c;
+		count -= c;
+		ret += c;
+	}
+
+	return ret;
+}
+
+/*
+ * serial_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 int serial_buf_get(struct circ_buf *cb, char *buf, int count)
+{
+	int c, ret = 0;
+
+	while (1) {
+		c = CIRC_CNT_TO_END(cb->head, cb->tail, SERIAL_BUF_SIZE);
+		if (count < c)
+			c = count;
+		if (c <= 0)
+			break;
+		memcpy(buf, cb->buf + cb->tail, c);
+		cb->tail = (cb->tail + c) & (SERIAL_BUF_SIZE-1);
+		buf += c;
+		count -= c;
+		ret += c;
+	}
+
+	return ret;
+}
+
 static int __init ftdi_init (void)
 {
 	int retval;
