diff options
author | Johan Hovold <jhovold@gmail.com> | 2010-05-05 23:58:13 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 13:21:42 -0700 |
commit | c23e5fc1f7dba228558b4a46e68f7af89515b13c (patch) | |
tree | add71b10dc2275c98d3439fe3756829c2ec0afc9 /drivers/usb/serial/ftdi_sio.c | |
parent | 27c7acf22047fbe4ec4cc36b7c2610dba227697c (diff) | |
download | op-kernel-dev-c23e5fc1f7dba228558b4a46e68f7af89515b13c.zip op-kernel-dev-c23e5fc1f7dba228558b4a46e68f7af89515b13c.tar.gz |
USB: serial: remove multi-urb write from generic driver
Remove multi-urb write from the generic driver and simplify the
prepare_write_buffer prototype:
int (*prepare_write_buffer)(struct usb_serial_port *port,
void *dest, size_t size);
The default implementation simply fills dest with data from port write
fifo but drivers can override it if they need to process the outgoing
data (e.g. add headers).
Turn ftdi_sio into a generic fifo-based driver, which lowers CPU usage
significantly for small writes while retaining maximum throughput.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 59 |
1 files changed, 21 insertions, 38 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f515f32..14f7a34 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -781,7 +781,7 @@ static void ftdi_close(struct usb_serial_port *port); static void ftdi_dtr_rts(struct usb_serial_port *port, int on); static void ftdi_process_read_urb(struct urb *urb); static int ftdi_prepare_write_buffer(struct usb_serial_port *port, - void **dest, size_t size, const void *buf, size_t count); + void *dest, size_t size); static void ftdi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int ftdi_tiocmget(struct tty_struct *tty, struct file *file); @@ -808,8 +808,7 @@ static struct usb_serial_driver ftdi_sio_device = { .id_table = id_table_combined, .num_ports = 1, .bulk_in_size = 512, - /* Must modify prepare_write_buffer if multi_urb_write is changed. */ - .multi_urb_write = 1, + .bulk_out_size = 256, .probe = ftdi_sio_probe, .port_probe = ftdi_sio_port_probe, .port_remove = ftdi_sio_port_remove, @@ -1531,15 +1530,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) quirk->port_probe(priv); priv->port = port; - - /* Free port's existing write urb and transfer buffer. */ - if (port->write_urb) { - usb_free_urb(port->write_urb); - port->write_urb = NULL; - } - kfree(port->bulk_out_buffer); - port->bulk_out_buffer = NULL; - usb_set_serial_port_data(port, priv); ftdi_determine_type(port); @@ -1734,8 +1724,7 @@ static void ftdi_close(struct usb_serial_port *port) dbg("%s", __func__); - /* shutdown our bulk read */ - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); kref_put(&priv->kref, ftdi_sio_priv_release); } @@ -1747,40 +1736,34 @@ static void ftdi_close(struct usb_serial_port *port) * The new devices do not require this byte */ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, - void **dest, size_t size, const void *src, size_t count) + void *dest, size_t size) { struct ftdi_private *priv; - unsigned char *buffer; - int len; + int count; + unsigned long flags; priv = usb_get_serial_port_data(port); - len = count; - if (priv->chip_type == SIO && count != 0) - len += ((count - 1) / (priv->max_packet_size - 1)) + 1; - - buffer = kmalloc(len, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, "%s - could not allocate buffer\n", - __func__); - return -ENOMEM; - } - if (priv->chip_type == SIO) { - int i, msg_len; - - for (i = 0; i < len; i += priv->max_packet_size) { - msg_len = min_t(int, len - i, priv->max_packet_size) - 1; - buffer[i] = (msg_len << 2) + 1; - memcpy(&buffer[i + 1], src, msg_len); - src += msg_len; + unsigned char *buffer = dest; + int i, len, c; + + count = 0; + spin_lock_irqsave(&port->lock, flags); + for (i = 0; i < size - 1; i += priv->max_packet_size) { + len = min_t(int, size - i, priv->max_packet_size) - 1; + buffer[i] = (len << 2) + 1; + c = kfifo_out(&port->write_fifo, &buffer[i + 1], len); + if (!c) + break; + count += c + 1; } + spin_unlock_irqrestore(&port->lock, flags); } else { - memcpy(buffer, src, count); + count = kfifo_out_locked(&port->write_fifo, dest, size, + &port->lock); } - *dest = buffer; - return count; } |