# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.430 -> 1.431 # drivers/usb/serial/visor.h 1.7 -> 1.8 # drivers/usb/serial/visor.c 1.24 -> 1.25 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/02/27 greg@kroah.com 1.431 # usb visor driver: # - reworked urb handling, getting rid of lots of code now that we have # proper urb reference counting. # - removed port locks as the usb-serial core now does this. # - added support for the Palm m515 thanks to SilaS # -------------------------------------------- # diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c --- a/drivers/usb/serial/visor.c Wed Feb 27 15:44:55 2002 +++ b/drivers/usb/serial/visor.c Wed Feb 27 15:44:55 2002 @@ -12,6 +12,15 @@ * * 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. + * * (02/14/2002) gkh * Added support for the Clie S-360 device. * @@ -134,7 +143,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.9" +#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman " #define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clié driver" @@ -158,6 +167,7 @@ static __devinitdata struct usb_device_id combined_id_table [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, @@ -174,6 +184,7 @@ { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, @@ -233,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; /****************************************************************************** @@ -259,8 +266,6 @@ return -ENODEV; } - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -284,8 +289,6 @@ err(__FUNCTION__ " - failed submitting read urb, error %d", result); } - up (&port->sem); - return result; } @@ -304,8 +307,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -329,8 +330,6 @@ } port->open_count = 0; } - up (&port->sem); - /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ } @@ -340,120 +339,84 @@ { 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); - current_position += transfer_size; - bytes_sent += transfer_size; - count -= transfer_size; - bytes_out += transfer_size; + 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; + + /* 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; + } else { + bytes_out += count; } -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; } @@ -471,9 +434,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; } @@ -534,16 +500,8 @@ static void visor_throttle (struct usb_serial_port *port) { - dbg(__FUNCTION__ " - port %d", port->number); - - down (&port->sem); - usb_unlink_urb (port->read_urb); - - up (&port->sem); - - return; } @@ -553,16 +511,10 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); - - up (&port->sem); - - return; } @@ -783,30 +735,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; @@ -815,27 +745,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); } diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h --- a/drivers/usb/serial/visor.h Wed Feb 27 15:44:55 2002 +++ b/drivers/usb/serial/visor.h Wed Feb 27 15:44:55 2002 @@ -23,6 +23,7 @@ #define PALM_VENDOR_ID 0x0830 #define PALM_M500_ID 0x0001 #define PALM_M505_ID 0x0002 +#define PALM_M515_ID 0x0003 #define PALM_M125_ID 0x0040 #define SONY_VENDOR_ID 0x054C