*
* 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.
*
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.9"
+#define DRIVER_VERSION "v2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony CliƩ driver"
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) },
{ 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) },
};
-#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;
/******************************************************************************
return -ENODEV;
}
- down (&port->sem);
-
++port->open_count;
if (port->open_count == 1) {
err(__FUNCTION__ " - failed submitting read urb, error %d", result);
}
- up (&port->sem);
-
return result;
}
if (!serial)
return;
- down (&port->sem);
-
--port->open_count;
if (port->open_count <= 0) {
}
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); */
}
{
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);
-
- /* 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;
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ err ("no more free urbs");
+ kfree (buffer);
+ return -ENOMEM;
+ }
+
+ 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;
}
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;
}
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;
}
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;
}
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;
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);
}