USB: pl2303: fix DTR/RTS being raised on baud rate change
[linux-flexiantxendom0.git] / drivers / usb / serial / pl2303.c
index a63ea99..5532ea5 100644 (file)
@@ -40,17 +40,7 @@ static int debug;
 
 #define PL2303_CLOSING_WAIT    (30*HZ)
 
-#define PL2303_BUF_SIZE                1024
-#define PL2303_TMP_BUF_SIZE    1024
-
-struct pl2303_buf {
-       unsigned int    buf_size;
-       char            *buf_buf;
-       char            *buf_get;
-       char            *buf_put;
-};
-
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
@@ -59,6 +49,8 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
+       { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
+       { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
        { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
@@ -95,7 +87,11 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
        { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
        { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
+       { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
+       { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
+       { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
+       { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
 
@@ -154,173 +150,12 @@ enum pl2303_type {
 
 struct pl2303_private {
        spinlock_t lock;
-       struct pl2303_buf *buf;
-       int write_urb_in_use;
        wait_queue_head_t delta_msr_wait;
        u8 line_control;
        u8 line_status;
        enum pl2303_type type;
 };
 
-/*
- * pl2303_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
-{
-       struct pl2303_buf *pb;
-
-       if (size == 0)
-               return NULL;
-
-       pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
-       if (pb == NULL)
-               return NULL;
-
-       pb->buf_buf = kmalloc(size, GFP_KERNEL);
-       if (pb->buf_buf == NULL) {
-               kfree(pb);
-               return NULL;
-       }
-
-       pb->buf_size = size;
-       pb->buf_get = pb->buf_put = pb->buf_buf;
-
-       return pb;
-}
-
-/*
- * pl2303_buf_free
- *
- * Free the buffer and all associated memory.
- */
-static void pl2303_buf_free(struct pl2303_buf *pb)
-{
-       if (pb) {
-               kfree(pb->buf_buf);
-               kfree(pb);
-       }
-}
-
-/*
- * pl2303_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-static void pl2303_buf_clear(struct pl2303_buf *pb)
-{
-       if (pb != NULL)
-               pb->buf_get = pb->buf_put;
-               /* equivalent to a get of all data available */
-}
-
-/*
- * pl2303_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
-{
-       if (pb == NULL)
-               return 0;
-
-       return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
-}
-
-/*
- * pl2303_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
-{
-       if (pb == NULL)
-               return 0;
-
-       return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
-}
-
-/*
- * pl2303_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 pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
-                                  unsigned int count)
-{
-       unsigned int len;
-
-       if (pb == NULL)
-               return 0;
-
-       len  = pl2303_buf_space_avail(pb);
-       if (count > len)
-               count = len;
-
-       if (count == 0)
-               return 0;
-
-       len = pb->buf_buf + pb->buf_size - pb->buf_put;
-       if (count > len) {
-               memcpy(pb->buf_put, buf, len);
-               memcpy(pb->buf_buf, buf+len, count - len);
-               pb->buf_put = pb->buf_buf + count - len;
-       } else {
-               memcpy(pb->buf_put, buf, count);
-               if (count < len)
-                       pb->buf_put += count;
-               else /* count == len */
-                       pb->buf_put = pb->buf_buf;
-       }
-
-       return count;
-}
-
-/*
- * pl2303_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 pl2303_buf_get(struct pl2303_buf *pb, char *buf,
-                                  unsigned int count)
-{
-       unsigned int len;
-
-       if (pb == NULL)
-               return 0;
-
-       len = pl2303_buf_data_avail(pb);
-       if (count > len)
-               count = len;
-
-       if (count == 0)
-               return 0;
-
-       len = pb->buf_buf + pb->buf_size - pb->buf_get;
-       if (count > len) {
-               memcpy(buf, pb->buf_get, len);
-               memcpy(buf+len, pb->buf_buf, count - len);
-               pb->buf_get = pb->buf_buf + count - len;
-       } else {
-               memcpy(buf, pb->buf_get, count);
-               if (count < len)
-                       pb->buf_get += count;
-               else /* count == len */
-                       pb->buf_get = pb->buf_buf;
-       }
-
-       return count;
-}
-
 static int pl2303_vendor_read(__u16 value, __u16 index,
                struct usb_serial *serial, unsigned char *buf)
 {
@@ -369,11 +204,6 @@ static int pl2303_startup(struct usb_serial *serial)
                if (!priv)
                        goto cleanup;
                spin_lock_init(&priv->lock);
-               priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
-               if (priv->buf == NULL) {
-                       kfree(priv);
-                       goto cleanup;
-               }
                init_waitqueue_head(&priv->delta_msr_wait);
                priv->type = type;
                usb_set_serial_port_data(serial->port[i], priv);
@@ -401,7 +231,6 @@ cleanup:
        kfree(buf);
        for (--i; i >= 0; --i) {
                priv = usb_get_serial_port_data(serial->port[i]);
-               pl2303_buf_free(priv->buf);
                kfree(priv);
                usb_set_serial_port_data(serial->port[i], NULL);
        }
@@ -419,103 +248,6 @@ static int set_control_lines(struct usb_device *dev, u8 value)
        return retval;
 }
 
-static void pl2303_send(struct usb_serial_port *port)
-{
-       int count, result;
-       struct pl2303_private *priv = usb_get_serial_port_data(port);
-       unsigned long flags;
-
-       dbg("%s - port %d", __func__, port->number);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       if (priv->write_urb_in_use) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return;
-       }
-
-       count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
-                              port->bulk_out_size);
-
-       if (count == 0) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return;
-       }
-
-       priv->write_urb_in_use = 1;
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       usb_serial_debug_data(debug, &port->dev, __func__, count,
-                             port->write_urb->transfer_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", __func__, result);
-               priv->write_urb_in_use = 0;
-               /* TODO: reschedule pl2303_send */
-       }
-
-       usb_serial_port_softint(port);
-}
-
-static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
-                               const unsigned char *buf, int count)
-{
-       struct pl2303_private *priv = usb_get_serial_port_data(port);
-       unsigned long flags;
-
-       dbg("%s - port %d, %d bytes", __func__, port->number, count);
-
-       if (!count)
-               return count;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       count = pl2303_buf_put(priv->buf, buf, count);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       pl2303_send(port);
-
-       return count;
-}
-
-static int pl2303_write_room(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct pl2303_private *priv = usb_get_serial_port_data(port);
-       int room = 0;
-       unsigned long flags;
-
-       dbg("%s - port %d", __func__, port->number);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       room = pl2303_buf_space_avail(priv->buf);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       dbg("%s - returns %d", __func__, room);
-       return room;
-}
-
-static int pl2303_chars_in_buffer(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct pl2303_private *priv = usb_get_serial_port_data(port);
-       int chars = 0;
-       unsigned long flags;
-
-       dbg("%s - port %d", __func__, port->number);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       chars = pl2303_buf_data_avail(priv->buf);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       dbg("%s - returns %d", __func__, chars);
-       return chars;
-}
-
 static void pl2303_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -527,6 +259,12 @@ static void pl2303_set_termios(struct tty_struct *tty,
        int baud;
        int i;
        u8 control;
+       const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
+                                4800, 7200, 9600, 14400, 19200, 28800, 38400,
+                                57600, 115200, 230400, 460800, 614400,
+                                921600, 1228800, 2457600, 3000000, 6000000 };
+       int baud_floor, baud_ceil;
+       int k;
 
        dbg("%s -  port %d", __func__, port->number);
 
@@ -572,21 +310,74 @@ static void pl2303_set_termios(struct tty_struct *tty,
                dbg("%s - data bits = %d", __func__, buf[6]);
        }
 
+       /* For reference buf[0]:buf[3] baud rate value */
+       /* NOTE: Only the values defined in baud_sup are supported !
+        *       => if unsupported values are set, the PL2303 seems to use
+        *          9600 baud (at least my PL2303X always does)
+        */
        baud = tty_get_baud_rate(tty);
-       dbg("%s - baud = %d", __func__, baud);
+       dbg("%s - baud requested = %d", __func__, baud);
        if (baud) {
-               buf[0] = baud & 0xff;
-               buf[1] = (baud >> 8) & 0xff;
-               buf[2] = (baud >> 16) & 0xff;
-               buf[3] = (baud >> 24) & 0xff;
+               /* Set baudrate to nearest supported value */
+               for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
+                       if (baud_sup[k] / baud) {
+                               baud_ceil = baud_sup[k];
+                               if (k==0) {
+                                       baud = baud_ceil;
+                               } else {
+                                       baud_floor = baud_sup[k-1];
+                                       if ((baud_ceil % baud)
+                                           > (baud % baud_floor))
+                                               baud = baud_floor;
+                                       else
+                                               baud = baud_ceil;
+                               }
+                               break;
+                       }
+               }
+               if (baud > 1228800) {
+                       /* type_0, type_1 only support up to 1228800 baud */
+                       if (priv->type != HX)
+                               baud = 1228800;
+                       else if (baud > 6000000)
+                               baud = 6000000;
+               }
+               dbg("%s - baud set = %d", __func__, baud);
+               if (baud <= 115200) {
+                       buf[0] = baud & 0xff;
+                       buf[1] = (baud >> 8) & 0xff;
+                       buf[2] = (baud >> 16) & 0xff;
+                       buf[3] = (baud >> 24) & 0xff;
+               } else {
+                       /* apparently the formula for higher speeds is:
+                        * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
+                        */
+                       unsigned tmp = 12*1000*1000*32 / baud;
+                       buf[3] = 0x80;
+                       buf[2] = 0;
+                       buf[1] = (tmp >= 256);
+                       while (tmp >= 256) {
+                               tmp >>= 2;
+                               buf[1] <<= 1;
+                       }
+                       buf[0] = tmp;
+               }
        }
 
        /* For reference buf[4]=0 is 1 stop bits */
        /* For reference buf[4]=1 is 1.5 stop bits */
        /* For reference buf[4]=2 is 2 stop bits */
        if (cflag & CSTOPB) {
-               buf[4] = 2;
-               dbg("%s - stop bits = 2", __func__);
+               /* NOTE: Comply with "real" UARTs / RS232:
+                *       use 1.5 instead of 2 stop bits with 5 data bits
+                */
+               if ((cflag & CSIZE) == CS5) {
+                       buf[4] = 1;
+                       dbg("%s - stop bits = 1.5", __func__);
+               } else {
+                       buf[4] = 2;
+                       dbg("%s - stop bits = 2", __func__);
+               }
        } else {
                buf[4] = 0;
                dbg("%s - stop bits = 1", __func__);
@@ -599,11 +390,21 @@ static void pl2303_set_termios(struct tty_struct *tty,
                /* For reference buf[5]=3 is mark parity */
                /* For reference buf[5]=4 is space parity */
                if (cflag & PARODD) {
-                       buf[5] = 1;
-                       dbg("%s - parity = odd", __func__);
+                       if (cflag & CMSPAR) {
+                               buf[5] = 3;
+                               dbg("%s - parity = mark", __func__);
+                       } else {
+                               buf[5] = 1;
+                               dbg("%s - parity = odd", __func__);
+                       }
                } else {
-                       buf[5] = 2;
-                       dbg("%s - parity = even", __func__);
+                       if (cflag & CMSPAR) {
+                               buf[5] = 4;
+                               dbg("%s - parity = space", __func__);
+                       } else {
+                               buf[5] = 2;
+                               dbg("%s - parity = even", __func__);
+                       }
                }
        } else {
                buf[5] = 0;
@@ -620,7 +421,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
        control = priv->line_control;
        if ((cflag & CBAUD) == B0)
                priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
-       else
+       else if ((old_termios->c_cflag & CBAUD) == B0)
                priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
        if (control != priv->line_control) {
                control = priv->line_control;
@@ -647,7 +448,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
                pl2303_vendor_write(0x0, 0x0, serial);
        }
 
-       /* FIXME: Need to read back resulting baud rate */
+       /* Save resulting baud rate */
        if (baud)
                tty_encode_baud_rate(tty, baud, baud);
 
@@ -673,22 +474,10 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
 
 static void pl2303_close(struct usb_serial_port *port)
 {
-       struct pl2303_private *priv = usb_get_serial_port_data(port);
-       unsigned long flags;
-
        dbg("%s - port %d", __func__, port->number);
 
-       spin_lock_irqsave(&priv->lock, flags);
-       /* clear out any remaining data in the buffer */
-       pl2303_buf_clear(priv->buf);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* shutdown our urbs */
-       dbg("%s - shutting down urbs", __func__);
-       usb_kill_urb(port->write_urb);
-       usb_kill_urb(port->read_urb);
+       usb_serial_generic_close(port);
        usb_kill_urb(port->interrupt_in_urb);
-
 }
 
 static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -714,17 +503,13 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
                pl2303_set_termios(tty, port, &tmp_termios);
 
        dbg("%s - submitting read urb", __func__);
-       port->read_urb->dev = serial->dev;
-       result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+       result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
        if (result) {
-               dev_err(&port->dev, "%s - failed submitting read urb,"
-                       " error %d\n", __func__, result);
                pl2303_close(port);
                return -EPROTO;
        }
 
        dbg("%s - submitting interrupt urb", __func__);
-       port->interrupt_in_urb->dev = serial->dev;
        result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
        if (result) {
                dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -736,7 +521,7 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
        return 0;
 }
 
-static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
+static int pl2303_tiocmset(struct tty_struct *tty,
                           unsigned int set, unsigned int clear)
 {
        struct usb_serial_port *port = tty->driver_data;
@@ -762,7 +547,7 @@ static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
        return set_control_lines(port->serial->dev, control);
 }
 
-static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
+static int pl2303_tiocmget(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -837,13 +622,26 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
        return 0;
 }
 
-static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
+static int pl2303_ioctl(struct tty_struct *tty,
                        unsigned int cmd, unsigned long arg)
 {
+       struct serial_struct ser;
        struct usb_serial_port *port = tty->driver_data;
        dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
 
        switch (cmd) {
+       case TIOCGSERIAL:
+               memset(&ser, 0, sizeof ser);
+               ser.type = PORT_16654;
+               ser.line = port->serial->minor;
+               ser.port = port->number;
+               ser.baud_base = 460800;
+
+               if (copy_to_user((void __user *)arg, &ser, sizeof ser))
+                       return -EFAULT;
+
+               return 0;
+
        case TIOCMIWAIT:
                dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
                return wait_modem_info(port, arg);
@@ -886,10 +684,7 @@ static void pl2303_release(struct usb_serial *serial)
 
        for (i = 0; i < serial->num_ports; ++i) {
                priv = usb_get_serial_port_data(serial->port[i]);
-               if (priv) {
-                       pl2303_buf_free(priv->buf);
-                       kfree(priv);
-               }
+               kfree(priv);
        }
 }
 
@@ -899,9 +694,11 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
 {
 
        struct pl2303_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
        unsigned long flags;
        u8 status_idx = UART_STATE;
        u8 length = UART_STATE + 1;
+       u8 prev_line_status;
        u16 idv, idp;
 
        idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
@@ -923,11 +720,20 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
 
        /* Save off the uart status for others to look at */
        spin_lock_irqsave(&priv->lock, flags);
+       prev_line_status = priv->line_status;
        priv->line_status = data[status_idx];
        spin_unlock_irqrestore(&priv->lock, flags);
        if (priv->line_status & UART_BREAK_ERROR)
                usb_serial_handle_break(port);
        wake_up_interruptible(&priv->delta_msr_wait);
+
+       tty = tty_port_tty_get(&port->port);
+       if (!tty)
+               return;
+       if ((priv->line_status ^ prev_line_status) & UART_DCD)
+               usb_serial_handle_dcd_change(port, tty,
+                               priv->line_status & UART_DCD);
+       tty_kref_put(tty);
 }
 
 static void pl2303_read_int_callback(struct urb *urb)
@@ -970,13 +776,31 @@ exit:
                        __func__, retval);
 }
 
-static void pl2303_push_data(struct tty_struct *tty,
-               struct usb_serial_port *port, struct urb *urb,
-               u8 line_status)
+static void pl2303_process_read_urb(struct urb *urb)
 {
+       struct usb_serial_port *port = urb->context;
+       struct pl2303_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
-       /* get tty_flag from status */
        char tty_flag = TTY_NORMAL;
+       unsigned long flags;
+       u8 line_status;
+       int i;
+
+       /* update line status */
+       spin_lock_irqsave(&priv->lock, flags);
+       line_status = priv->line_status;
+       priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+       spin_unlock_irqrestore(&priv->lock, flags);
+       wake_up_interruptible(&priv->delta_msr_wait);
+
+       if (!urb->actual_length)
+               return;
+
+       tty = tty_port_tty_get(&port->port);
+       if (!tty)
+               return;
+
        /* break takes precedence over parity, */
        /* which takes precedence over framing errors */
        if (line_status & UART_BREAK_ERROR)
@@ -987,121 +811,21 @@ static void pl2303_push_data(struct tty_struct *tty,
                tty_flag = TTY_FRAME;
        dbg("%s - tty_flag = %d", __func__, tty_flag);
 
-       tty_buffer_request_room(tty, urb->actual_length + 1);
        /* overrun is special, not associated with a char */
        if (line_status & UART_OVERRUN_ERROR)
                tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-       if (port->console && port->sysrq) {
-               int i;
+
+       if (port->port.console && port->sysrq) {
                for (i = 0; i < urb->actual_length; ++i)
-                       if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
+                       if (!usb_serial_handle_sysrq_char(port, data[i]))
                                tty_insert_flip_char(tty, data[i], tty_flag);
-       } else
-               tty_insert_flip_string(tty, data, urb->actual_length);
-       tty_flip_buffer_push(tty);
-}
-
-static void pl2303_read_bulk_callback(struct urb *urb)
-{
-       struct usb_serial_port *port =  urb->context;
-       struct pl2303_private *priv = usb_get_serial_port_data(port);
-       struct tty_struct *tty;
-       unsigned long flags;
-       int result;
-       int status = urb->status;
-       u8 line_status;
-
-       dbg("%s - port %d", __func__, port->number);
-
-       if (status) {
-               dbg("%s - urb status = %d", __func__, status);
-               if (!port->port.count) {
-                       dbg("%s - port is closed, exiting.", __func__);
-                       return;
-               }
-               if (status == -EPROTO) {
-                       /* PL2303 mysteriously fails with -EPROTO reschedule
-                        * the read */
-                       dbg("%s - caught -EPROTO, resubmitting the urb",
-                           __func__);
-                       urb->dev = port->serial->dev;
-                       result = usb_submit_urb(urb, GFP_ATOMIC);
-                       if (result)
-                               dev_err(&urb->dev->dev, "%s - failed"
-                                       " resubmitting read urb, error %d\n",
-                                       __func__, result);
-                       return;
-               }
-               dbg("%s - unable to handle the error, exiting.", __func__);
-               return;
+       } else {
+               tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+                                                       urb->actual_length);
        }
 
-       usb_serial_debug_data(debug, &port->dev, __func__,
-                             urb->actual_length, urb->transfer_buffer);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       line_status = priv->line_status;
-       priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
-       spin_unlock_irqrestore(&priv->lock, flags);
-       wake_up_interruptible(&priv->delta_msr_wait);
-
-       tty = tty_port_tty_get(&port->port);
-       if (tty && urb->actual_length) {
-               pl2303_push_data(tty, port, urb, line_status);
-       }
+       tty_flip_buffer_push(tty);
        tty_kref_put(tty);
-       /* Schedule the next read _if_ we are still open */
-       if (port->port.count) {
-               urb->dev = port->serial->dev;
-               result = usb_submit_urb(urb, GFP_ATOMIC);
-               if (result)
-                       dev_err(&urb->dev->dev, "%s - failed resubmitting"
-                               " read urb, error %d\n", __func__, result);
-       }
-
-       return;
-}
-
-static void pl2303_write_bulk_callback(struct urb *urb)
-{
-       struct usb_serial_port *port =  urb->context;
-       struct pl2303_private *priv = usb_get_serial_port_data(port);
-       int result;
-       int status = urb->status;
-
-       dbg("%s - port %d", __func__, port->number);
-
-       switch (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", __func__,
-                   status);
-               priv->write_urb_in_use = 0;
-               return;
-       default:
-               /* error in the urb, so we have to resubmit it */
-               dbg("%s - Overflow in write", __func__);
-               dbg("%s - nonzero write bulk status received: %d", __func__,
-                   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", __func__, result);
-               else
-                       return;
-       }
-
-       priv->write_urb_in_use = 0;
-
-       /* send any buffered data */
-       pl2303_send(port);
 }
 
 /* All of the device info needed for the PL2303 SIO serial converter */
@@ -1113,21 +837,19 @@ static struct usb_serial_driver pl2303_device = {
        .id_table =             id_table,
        .usb_driver =           &pl2303_driver,
        .num_ports =            1,
+       .bulk_in_size =         256,
+       .bulk_out_size =        256,
        .open =                 pl2303_open,
        .close =                pl2303_close,
        .dtr_rts =              pl2303_dtr_rts,
        .carrier_raised =       pl2303_carrier_raised,
-       .write =                pl2303_write,
        .ioctl =                pl2303_ioctl,
        .break_ctl =            pl2303_break_ctl,
        .set_termios =          pl2303_set_termios,
        .tiocmget =             pl2303_tiocmget,
        .tiocmset =             pl2303_tiocmset,
-       .read_bulk_callback =   pl2303_read_bulk_callback,
+       .process_read_urb =     pl2303_process_read_urb,
        .read_int_callback =    pl2303_read_int_callback,
-       .write_bulk_callback =  pl2303_write_bulk_callback,
-       .write_room =           pl2303_write_room,
-       .chars_in_buffer =      pl2303_chars_in_buffer,
        .attach =               pl2303_startup,
        .release =              pl2303_release,
 };