Hi all,
Now that we have proper reference counting logic in the USB core code, I
rewrote how the visor driver handles urbs. Instead of having a urb pool
which gets recycled, we create a new urb for every transfer, and then
let the host controller clean up the urb when it is finished.
This shrinks the visor driver by a lot, and makes the logic a lot
simpler.
The 2.5.6-pre1 driver is this big:
text data bss dec hex filename
9256 576 160 9992 2708 visor.o
With this patch and the previous usb-serial locking patch:
text data bss dec hex filename
8326 576 12 8914 22d2 visor.o
In testing I could not measure any speed differences with this patch,
and without it. I would not recommend this approach for drivers that
really care about speed (we are doing to kmalloc() calls for every
write), but the visor driver does not have to worry about things like
this (the limiting factor is the device itself, not the transfer
speeds.)
Comments?
thanks,
greg k-h
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c Wed Feb 27 11:03:53 2002
+++ b/drivers/usb/serial/visor.c Wed Feb 27 11:03:53 2002
@@ -12,6 +12,12 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (02/27/2002) gkh
+ * Reworked the urb handling logic. We have no more pool, but dynamically
+ * allocate the urb and the transfer buffer on the fly. In testing this
+ * does not incure any measurable overhead. This also relies on the fact
+ * that we have proper reference counting logic for urbs.
+ *
* (02/21/2002) SilaS
* Added initial support for the Palm m515 devices.
*
@@ -137,7 +143,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.9"
+#define DRIVER_VERSION "v2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>"
#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Cli� driver"
@@ -238,12 +244,8 @@
};
-#define NUM_URBS 24
-#define URB_TRANSFER_BUFFER_SIZE 768
-static struct urb *write_urb_pool[NUM_URBS];
-static spinlock_t write_urb_pool_lock;
-static int bytes_in;
-static int bytes_out;
+static int bytes_in;
+static int bytes_out;
/******************************************************************************
@@ -337,120 +339,82 @@
{
struct usb_serial *serial = port->serial;
struct urb *urb;
- const unsigned char *current_position = buf;
- unsigned long flags;
+ unsigned char *buffer;
int status;
- int i;
- int bytes_sent = 0;
- int transfer_size;
dbg(__FUNCTION__ " - port %d", port->number);
- while (count > 0) {
- /* try to find a free urb in our list of them */
- urb = NULL;
- spin_lock_irqsave (&write_urb_pool_lock, flags);
- for (i = 0; i < NUM_URBS; ++i) {
- if (write_urb_pool[i]->status != -EINPROGRESS) {
- urb = write_urb_pool[i];
- break;
- }
- }
- spin_unlock_irqrestore (&write_urb_pool_lock, flags);
- if (urb == NULL) {
- dbg (__FUNCTION__ " - no more free urbs");
- goto exit;
- }
- if (urb->transfer_buffer == NULL) {
- urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
- if (urb->transfer_buffer == NULL) {
- err(__FUNCTION__" no more kernel memory...");
- goto exit;
- }
- }
-
- transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
- if (from_user) {
- if (copy_from_user (urb->transfer_buffer, current_position,
transfer_size)) {
- bytes_sent = -EFAULT;
- break;
- }
- } else {
- memcpy (urb->transfer_buffer, current_position, transfer_size);
- }
+ buffer = kmalloc (count, GFP_KERNEL);
+ if (!buffer) {
+ err ("out of memory");
+ return -ENOMEM;
+ }
- usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size,
urb->transfer_buffer);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ err ("no more free urbs");
+ kfree (buffer);
+ return -ENOMEM;
+ }
- /* build up our urb */
- usb_fill_bulk_urb (urb, serial->dev,
- usb_sndbulkpipe (serial->dev,
- port->bulk_out_endpointAddress),
- urb->transfer_buffer, transfer_size,
- visor_write_bulk_callback, port);
- urb->transfer_flags |= USB_QUEUE_BULK;
-
- /* send it down the pipe */
- status = usb_submit_urb(urb, GFP_KERNEL);
- if (status) {
- err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with
status = %d", status);
- bytes_sent = status;
- break;
+ if (from_user) {
+ if (copy_from_user (buffer, buf, count)) {
+ kfree (buffer);
+ usb_free_urb (urb);
+ return -EFAULT;
}
+ } else {
+ memcpy (buffer, buf, count);
+ }
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, count, buffer);
+
+ usb_fill_bulk_urb (urb, serial->dev,
+ usb_sndbulkpipe (serial->dev,
+ port->bulk_out_endpointAddress),
+ buffer, count,
+ visor_write_bulk_callback, port);
+ urb->transfer_flags |= USB_QUEUE_BULK;
- current_position += transfer_size;
- bytes_sent += transfer_size;
- count -= transfer_size;
- bytes_out += transfer_size;
+ /* send it down the pipe */
+ status = usb_submit_urb(urb, GFP_KERNEL);
+ if (status) {
+ err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status =
+%d", status);
+ count = status;
}
-exit:
- return bytes_sent;
+ /* 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 int visor_write_room (struct usb_serial_port *port)
{
- unsigned long flags;
- int i;
- int room = 0;
-
dbg(__FUNCTION__ " - port %d", port->number);
-
- spin_lock_irqsave (&write_urb_pool_lock, flags);
- for (i = 0; i < NUM_URBS; ++i) {
- if (write_urb_pool[i]->status != -EINPROGRESS) {
- room += URB_TRANSFER_BUFFER_SIZE;
- }
- }
-
- spin_unlock_irqrestore (&write_urb_pool_lock, flags);
-
- dbg(__FUNCTION__ " - returns %d", room);
- return (room);
+ /*
+ * We really can take anything the user throws at us
+ * but let's pick a nice big number to tell the tty
+ * layer that we have lots of free space
+ */
+ return 2048;
}
static int visor_chars_in_buffer (struct usb_serial_port *port)
{
- unsigned long flags;
- int i;
- int chars = 0;
-
dbg(__FUNCTION__ " - port %d", port->number);
-
- spin_lock_irqsave (&write_urb_pool_lock, flags);
-
- for (i = 0; i < NUM_URBS; ++i) {
- if (write_urb_pool[i]->status == -EINPROGRESS) {
- chars += URB_TRANSFER_BUFFER_SIZE;
- }
- }
-
- spin_unlock_irqrestore (&write_urb_pool_lock, flags);
- dbg (__FUNCTION__ " - returns %d", chars);
- return (chars);
+ /*
+ * We can't really account for how much data we
+ * have sent out, but hasn't made it through to the
+ * device, so just tell the tty layer that everything
+ * is flushed.
+ */
+ return 0;
}
@@ -468,9 +432,12 @@
return;
}
+ /* free up the transfer buffer, as usb_free_urb() does not do this */
+ kfree (urb->transfer_buffer);
+
queue_task(&port->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
-
+
return;
}
@@ -766,30 +733,8 @@
static int __init visor_init (void)
{
- struct urb *urb;
- int i;
-
usb_serial_register (&handspring_device);
usb_serial_register (&clie_3_5_device);
-
- /* create our write urb pool and transfer buffers */
- spin_lock_init (&write_urb_pool_lock);
- for (i = 0; i < NUM_URBS; ++i) {
- urb = usb_alloc_urb(0, GFP_KERNEL);
- write_urb_pool[i] = urb;
- if (urb == NULL) {
- err("No more urbs???");
- continue;
- }
-
- urb->transfer_buffer = NULL;
- urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
- if (!urb->transfer_buffer) {
- err (__FUNCTION__ " - out of memory for urb buffers.");
- continue;
- }
- }
-
info(DRIVER_DESC " " DRIVER_VERSION);
return 0;
@@ -798,27 +743,8 @@
static void __exit visor_exit (void)
{
- int i;
- unsigned long flags;
-
usb_serial_deregister (&handspring_device);
usb_serial_deregister (&clie_3_5_device);
-
- spin_lock_irqsave (&write_urb_pool_lock, flags);
-
- for (i = 0; i < NUM_URBS; ++i) {
- if (write_urb_pool[i]) {
- /* FIXME - uncomment the following usb_unlink_urb call when
- * the host controllers get fixed to set urb->dev = NULL after
- * the urb is finished. Otherwise this call oopses. */
- /* usb_unlink_urb(write_urb_pool[i]); */
- if (write_urb_pool[i]->transfer_buffer)
- kfree(write_urb_pool[i]->transfer_buffer);
- usb_free_urb (write_urb_pool[i]);
- }
- }
-
- spin_unlock_irqrestore (&write_urb_pool_lock, flags);
}
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel