diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-05-31 13:58:52 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-05-31 13:58:52 -0700 |
commit | 79831534f914a3465ebed3770938094b3b18bb8e (patch) | |
tree | b173f7c746e4bb675f78178a7ab7398ddb25aa8e /usb | |
parent | cd9f6ed81e278f7a5b8984132fde66b61e0bb856 (diff) | |
download | patches-79831534f914a3465ebed3770938094b3b18bb8e.tar.gz |
refresh and add airprime driver update
Diffstat (limited to 'usb')
-rw-r--r-- | usb/airprime_major_update.patch | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/usb/airprime_major_update.patch b/usb/airprime_major_update.patch new file mode 100644 index 0000000000000..ff9e17ffbae5f --- /dev/null +++ b/usb/airprime_major_update.patch @@ -0,0 +1,259 @@ +From foo@baz Tue Apr 9 12:12:43 2002 +Date: Wed, 31 May 2006 20:16:19 +0200 +To: Greg KH <greg@kroah.com> +From: Greg Kroah-Hartman <gregkh@suse.de> +Subject: USB: big airprime driver update + +This should make the airprime driver work much faster and hopefully +achieve wire speeds. It increases the buffer size of the urbs and puts +lots of them in flight at the same time. + +Thanks to Ken Brush <kbrush@gmail.com> for help in testing this. + +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/usb/serial/airprime.c | 206 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 205 insertions(+), 1 deletion(-) + +--- gregkh-2.6.orig/drivers/usb/serial/airprime.c ++++ gregkh-2.6/drivers/usb/serial/airprime.c +@@ -1,7 +1,7 @@ + /* + * AirPrime CDMA Wireless Serial USB driver + * +- * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de> ++ * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version +@@ -11,6 +11,7 @@ + #include <linux/kernel.h> + #include <linux/init.h> + #include <linux/tty.h> ++#include <linux/tty_flip.h> + #include <linux/module.h> + #include <linux/usb.h> + #include "usb-serial.h" +@@ -23,6 +24,201 @@ static struct usb_device_id id_table [] + }; + MODULE_DEVICE_TABLE(usb, id_table); + ++#define URB_TRANSFER_BUFFER_SIZE 4096 ++#define NUM_READ_URBS 4 ++#define NUM_WRITE_URBS 4 ++ ++/* if overridden by the user, then use their value for the size of the ++ * read and write urbs */ ++static int buffer_size = URB_TRANSFER_BUFFER_SIZE; ++static int debug; ++ ++struct airprime_private { ++ spinlock_t lock; ++ int outstanding_urbs; ++ int throttled; ++}; ++ ++static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs) ++{ ++ struct usb_serial_port *port = urb->context; ++ unsigned char *data = urb->transfer_buffer; ++ struct tty_struct *tty; ++ int result; ++ ++ dbg("%s - port %d", __FUNCTION__, port->number); ++ ++ if (urb->status) { ++ dbg("%s - nonzero read bulk status received: %d", ++ __FUNCTION__, urb->status); ++ /* something happened, so free up the memory for this urb (the ++ * urb will go away automatically when we return due to the ++ * reference count drop. */ ++ kfree(urb->transfer_buffer); ++ return; ++ } ++ ++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); ++ ++ tty = port->tty; ++ if (tty && urb->actual_length) { ++ tty_buffer_request_room(tty, urb->actual_length); ++ tty_insert_flip_string(tty, data, urb->actual_length); ++ tty_flip_buffer_push(tty); ++ } ++ ++ result = usb_submit_urb(urb, GFP_ATOMIC); ++ if (result) ++ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", ++ __FUNCTION__, result); ++ return; ++} ++ ++static void airprime_write_bulk_callback(struct urb *urb, struct pt_regs *regs) ++{ ++ struct usb_serial_port *port = urb->context; ++ struct airprime_private *priv = usb_get_serial_port_data(port); ++ unsigned long flags; ++ ++ /* free up the transfer buffer, as usb_free_urb() does not do this */ ++ kfree (urb->transfer_buffer); ++ ++ dbg("%s - port %d", __FUNCTION__, port->number); ++ ++ if (urb->status) ++ dbg("%s - nonzero write bulk status received: %d", ++ __FUNCTION__, urb->status); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ --priv->outstanding_urbs; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ usb_serial_port_softint(port); ++} ++ ++static int airprime_open(struct usb_serial_port *port, struct file *filp) ++{ ++ struct airprime_private *priv = usb_get_serial_port_data(port); ++ struct usb_serial *serial = port->serial; ++ struct urb *urb; ++ char *buffer; ++ int i; ++ int result = 0; ++ ++ dbg("%s - port %d", __FUNCTION__, port->number); ++ ++ /* initialize our private data structure if it isn't already created */ ++ if (!priv) { ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ spin_lock_init(&priv->lock); ++ usb_set_serial_port_data(port, priv); ++ } ++ ++ /* TODO handle error conditions better, right now we leak memory */ ++ for (i = 0; i < NUM_READ_URBS; ++i) { ++ buffer = kmalloc(buffer_size, GFP_KERNEL); ++ if (!buffer) { ++ dev_err(&port->dev, "%s - out of memory.\n", ++ __FUNCTION__); ++ return -ENOMEM; ++ } ++ urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!urb) { ++ dev_err(&port->dev, "%s - no more urbs?\n", ++ __FUNCTION__); ++ return -ENOMEM; ++ } ++ usb_fill_bulk_urb(urb, serial->dev, ++ usb_rcvbulkpipe(serial->dev, ++ port->bulk_out_endpointAddress), ++ buffer, buffer_size, ++ airprime_read_bulk_callback, port); ++ result = usb_submit_urb(urb, GFP_KERNEL); ++ if (result) { ++ dev_err(&port->dev, ++ "%s - failed submitting read urb, error %d\n", ++ __FUNCTION__, result); ++ return result; ++ } ++ /* fun with reference counting, when this urb is finished, the ++ * host driver will free it up automatically */ ++ usb_free_urb (urb); ++ } ++ ++ return result; ++} ++ ++static void airprime_close(struct usb_serial_port *port, struct file * filp) ++{ ++ /* free up private structure? */ ++} ++ ++static int airprime_write(struct usb_serial_port *port, ++ const unsigned char *buf, int count) ++{ ++ struct airprime_private *priv = usb_get_serial_port_data(port); ++ struct usb_serial *serial = port->serial; ++ struct urb *urb; ++ unsigned char *buffer; ++ unsigned long flags; ++ int status; ++ ++ dbg("%s - port %d", __FUNCTION__, port->number); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (priv->outstanding_urbs > NUM_WRITE_URBS) { ++ spin_unlock_irqrestore(&priv->lock, flags); ++ dbg("%s - write limit hit\n", __FUNCTION__); ++ return 0; ++ } ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ buffer = kmalloc(count, GFP_ATOMIC); ++ if (!buffer) { ++ dev_err(&port->dev, "out of memory\n"); ++ return -ENOMEM; ++ } ++ ++ urb = usb_alloc_urb(0, GFP_ATOMIC); ++ if (!urb) { ++ dev_err(&port->dev, "no more free urbs\n"); ++ kfree (buffer); ++ return -ENOMEM; ++ } ++ ++ memcpy (buffer, buf, count); ++ ++ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer); ++ ++ usb_fill_bulk_urb(urb, serial->dev, ++ usb_sndbulkpipe(serial->dev, ++ port->bulk_out_endpointAddress), ++ buffer, count, ++ airprime_write_bulk_callback, port); ++ ++ /* send it down the pipe */ ++ status = usb_submit_urb(urb, GFP_ATOMIC); ++ if (status) { ++ dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", ++ __FUNCTION__, status); ++ count = status; ++ kfree (buffer); ++ } else { ++ spin_lock_irqsave(&priv->lock, flags); ++ ++priv->outstanding_urbs; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ ++ /* we are done with this urb, so let the host driver ++ * really free it when it is finished with it */ ++ usb_free_urb (urb); ++ ++ return count; ++} ++ ++ + static struct usb_driver airprime_driver = { + .name = "airprime", + .probe = usb_serial_probe, +@@ -41,6 +237,9 @@ static struct usb_serial_driver airprime + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, ++ .open = airprime_open, ++ .close = airprime_close, ++ .write = airprime_write, + }; + + static int __init airprime_init(void) +@@ -65,3 +264,8 @@ static void __exit airprime_exit(void) + module_init(airprime_init); + module_exit(airprime_exit); + MODULE_LICENSE("GPL"); ++ ++module_param(debug, bool, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(debug, "Debug enabled or not"); ++module_param(buffer_size, int, 0); ++MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers"); |