USB: ipaq: fix oops when device is plugged in
[safe/jmp/linux-2.6] / drivers / usb / serial / ipaq.c
index c1a6484..d6231c3 100644 (file)
@@ -53,7 +53,7 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include "ipaq.h"
@@ -74,19 +74,20 @@ static int connect_retries = KP_RETRIES;
 static int initial_wait;
 
 /* Function prototypes for an ipaq */
-static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
-static void ipaq_close (struct usb_serial_port *port, struct file *filp);
-static int  ipaq_startup (struct usb_serial *serial);
-static void ipaq_shutdown (struct usb_serial *serial);
-static int ipaq_write(struct usb_serial_port *port, const unsigned char *buf,
-                      int count);
-static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *buf,
-                          int count);
+static int  ipaq_open(struct tty_struct *tty,
+                       struct usb_serial_port *port);
+static void ipaq_close(struct usb_serial_port *port);
+static int  ipaq_calc_num_ports(struct usb_serial *serial);
+static int  ipaq_startup(struct usb_serial *serial);
+static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
+                       const unsigned char *buf, int count);
+static int ipaq_write_bulk(struct usb_serial_port *port,
+                               const unsigned char *buf, int count);
 static void ipaq_write_gather(struct usb_serial_port *port);
-static void ipaq_read_bulk_callback (struct urb *urb);
+static void ipaq_read_bulk_callback(struct urb *urb);
 static void ipaq_write_bulk_callback(struct urb *urb);
-static int ipaq_write_room(struct usb_serial_port *port);
-static int ipaq_chars_in_buffer(struct usb_serial_port *port);
+static int ipaq_write_room(struct tty_struct *tty);
+static int ipaq_chars_in_buffer(struct tty_struct *tty);
 static void ipaq_destroy_lists(struct usb_serial_port *port);
 
 
@@ -256,6 +257,7 @@ static struct usb_device_id ipaq_id_table [] = {
        { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
        { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
        { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+       { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
        { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
        { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
        { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -305,7 +307,7 @@ static struct usb_device_id ipaq_id_table [] = {
        { USB_DEVICE(0x0930, 0x0705) }, /* TOSHIBA Pocket PC e310 */
        { USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */
        { USB_DEVICE(0x0930, 0x0707) }, /* TOSHIBA Pocket PC e330 Series */
-       { USB_DEVICE(0x0930, 0x0708) }, /* TOSHIBA Pocket PC e350 Series */
+       { USB_DEVICE(0x0930, 0x0708) }, /* TOSHIBA Pocket PC e350 Series */
        { USB_DEVICE(0x0930, 0x0709) }, /* TOSHIBA Pocket PC e750 Series */
        { USB_DEVICE(0x0930, 0x070A) }, /* TOSHIBA Pocket PC e400 Series */
        { USB_DEVICE(0x0930, 0x070B) }, /* TOSHIBA Pocket PC e800 Series */
@@ -487,7 +489,7 @@ static struct usb_device_id ipaq_id_table [] = {
        { USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */
        { USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */
        { USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */
-       { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */
+       { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */
        { USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */
        { USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */
        { USB_DEVICE(0x0FB8, 0x3001) }, /* Wistron USB Sync */
@@ -549,7 +551,7 @@ static struct usb_device_id ipaq_id_table [] = {
        { }                             /* Terminating entry */
 };
 
-MODULE_DEVICE_TABLE (usb, ipaq_id_table);
+MODULE_DEVICE_TABLE(usb, ipaq_id_table);
 
 static struct usb_driver ipaq_driver = {
        .name =         "ipaq",
@@ -569,14 +571,10 @@ static struct usb_serial_driver ipaq_device = {
        .description =          "PocketPC PDA",
        .usb_driver =           &ipaq_driver,
        .id_table =             ipaq_id_table,
-       .num_interrupt_in =     NUM_DONT_CARE,
-       .num_bulk_in =          1,
-       .num_bulk_out =         1,
-       .num_ports =            1,
        .open =                 ipaq_open,
        .close =                ipaq_close,
        .attach =               ipaq_startup,
-       .shutdown =             ipaq_shutdown,
+       .calc_num_ports =       ipaq_calc_num_ports,
        .write =                ipaq_write,
        .write_room =           ipaq_write_room,
        .chars_in_buffer =      ipaq_chars_in_buffer,
@@ -588,7 +586,8 @@ static spinlock_t   write_list_lock;
 static int             bytes_in;
 static int             bytes_out;
 
-static int ipaq_open(struct usb_serial_port *port, struct file *filp)
+static int ipaq_open(struct tty_struct *tty,
+                       struct usb_serial_port *port)
 {
        struct usb_serial       *serial = port->serial;
        struct ipaq_private     *priv;
@@ -596,13 +595,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
        int                     i, result = 0;
        int                     retries = connect_retries;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        bytes_in = 0;
        bytes_out = 0;
        priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
        if (priv == NULL) {
-               err("%s - Out of memory", __FUNCTION__);
+               dev_err(&port->dev, "%s - Out of memory\n", __func__);
                return -ENOMEM;
        }
        usb_set_serial_port_data(port, priv);
@@ -614,9 +613,9 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
 
        for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
                pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
-               if (pkt == NULL) {
+               if (pkt == NULL)
                        goto enomem;
-               }
+
                pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
                if (pkt->data == NULL) {
                        kfree(pkt);
@@ -630,27 +629,21 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
        }
 
        /*
-        * Force low latency on. This will immediately push data to the line
-        * discipline instead of queueing.
-        */
-
-       port->tty->low_latency = 1;
-       port->tty->raw = 1;
-       port->tty->real_raw = 1;
-
-       /*
         * Lose the small buffers usbserial provides. Make larger ones.
         */
 
        kfree(port->bulk_in_buffer);
        kfree(port->bulk_out_buffer);
+       /* make sure the generic serial code knows */
+       port->bulk_out_buffer = NULL;
+
        port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
-       if (port->bulk_in_buffer == NULL) {
-               port->bulk_out_buffer = NULL; /* prevent double free */
+       if (port->bulk_in_buffer == NULL)
                goto enomem;
-       }
+
        port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
        if (port->bulk_out_buffer == NULL) {
+               /* the buffer is useless, free it */
                kfree(port->bulk_in_buffer);
                port->bulk_in_buffer = NULL;
                goto enomem;
@@ -658,8 +651,9 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
        port->read_urb->transfer_buffer = port->bulk_in_buffer;
        port->write_urb->transfer_buffer = port->bulk_out_buffer;
        port->read_urb->transfer_buffer_length = URBDATA_SIZE;
-       port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
-       
+       port->bulk_out_size = port->write_urb->transfer_buffer_length
+                                                       = URBDATA_SIZE;
+
        msleep(1000*initial_wait);
 
        /*
@@ -681,20 +675,22 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
        }
 
        if (!retries && result) {
-               err("%s - failed doing control urb, error %d", __FUNCTION__,
-                   result);
+               dev_err(&port->dev, "%s - failed doing control urb, error %d\n",                        __func__, result);
                goto error;
        }
 
        /* Start reading from the device */
        usb_fill_bulk_urb(port->read_urb, serial->dev,
-                     usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-                     port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-                     ipaq_read_bulk_callback, port);
+               usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+               port->read_urb->transfer_buffer,
+               port->read_urb->transfer_buffer_length,
+               ipaq_read_bulk_callback, port);
 
        result = usb_submit_urb(port->read_urb, GFP_KERNEL);
        if (result) {
-               err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+               dev_err(&port->dev,
+                       "%s - failed submitting read urb, error %d\n",
+                       __func__, result);
                goto error;
        }
 
@@ -702,7 +698,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
 
 enomem:
        result = -ENOMEM;
-       err("%s - Out of memory", __FUNCTION__);
+       dev_err(&port->dev, "%s - Out of memory\n", __func__);
 error:
        ipaq_destroy_lists(port);
        kfree(priv);
@@ -710,12 +706,12 @@ error:
 }
 
 
-static void ipaq_close(struct usb_serial_port *port, struct file *filp)
+static void ipaq_close(struct usb_serial_port *port)
 {
        struct ipaq_private     *priv = usb_get_serial_port_data(port);
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
-                        
+       dbg("%s - port %d", __func__, port->number);
+
        /*
         * shut down bulk read and write
         */
@@ -725,61 +721,66 @@ static void ipaq_close(struct usb_serial_port *port, struct file *filp)
        kfree(priv);
        usb_set_serial_port_data(port, NULL);
 
-       /* Uncomment the following line if you want to see some statistics in your syslog */
+       /* 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); */
 }
 
 static void ipaq_read_bulk_callback(struct urb *urb)
 {
-       struct usb_serial_port  *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial_port  *port = urb->context;
        struct tty_struct       *tty;
        unsigned char           *data = urb->transfer_buffer;
        int                     result;
        int status = urb->status;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        if (status) {
                dbg("%s - nonzero read bulk status received: %d",
-                   __FUNCTION__, status);
+                   __func__, status);
                return;
        }
 
-       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+       usb_serial_debug_data(debug, &port->dev, __func__,
+                                               urb->actual_length, data);
 
-       tty = port->tty;
+       tty = tty_port_tty_get(&port->port);
        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);
                bytes_in += urb->actual_length;
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
-       usb_fill_bulk_urb(port->read_urb, port->serial->dev, 
-                     usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
-                     port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-                     ipaq_read_bulk_callback, port);
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+           usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
+           port->read_urb->transfer_buffer,
+           port->read_urb->transfer_buffer_length,
+           ipaq_read_bulk_callback, port);
        result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
        if (result)
-               err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+               dev_err(&port->dev,
+                       "%s - failed resubmitting read urb, error %d\n",
+                       __func__, result);
        return;
 }
 
-static int ipaq_write(struct usb_serial_port *port, const unsigned char *buf,
-                      int count)
+static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
+                       const unsigned char *buf, int count)
 {
        const unsigned char     *current_position = buf;
        int                     bytes_sent = 0;
        int                     transfer_size;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        while (count > 0) {
                transfer_size = min(count, PACKET_SIZE);
-               if (ipaq_write_bulk(port, current_position, transfer_size)) {
+               if (ipaq_write_bulk(port, current_position, transfer_size))
                        break;
-               }
                current_position += transfer_size;
                bytes_sent += transfer_size;
                count -= transfer_size;
@@ -787,10 +788,10 @@ static int ipaq_write(struct usb_serial_port *port, const unsigned char *buf,
        }
 
        return bytes_sent;
-} 
+}
 
-static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *buf,
-                          int count)
+static int ipaq_write_bulk(struct usb_serial_port *port,
+                                       const unsigned char *buf, int count)
 {
        struct ipaq_private     *priv = usb_get_serial_port_data(port);
        struct ipaq_packet      *pkt = NULL;
@@ -798,7 +799,7 @@ static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *bu
        unsigned long           flags;
 
        if (priv->free_len <= 0) {
-               dbg("%s - we're stuffed", __FUNCTION__);
+               dbg("%s - we're stuffed", __func__);
                return -EAGAIN;
        }
 
@@ -810,12 +811,12 @@ static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *bu
        }
        spin_unlock_irqrestore(&write_list_lock, flags);
        if (pkt == NULL) {
-               dbg("%s - we're stuffed", __FUNCTION__);
+               dbg("%s - we're stuffed", __func__);
                return -EAGAIN;
        }
 
        memcpy(pkt->data, buf, count);
-       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, pkt->data);
+       usb_serial_debug_data(debug, &port->dev, __func__, count, pkt->data);
 
        pkt->len = count;
        pkt->written = 0;
@@ -827,9 +828,10 @@ static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *bu
                ipaq_write_gather(port);
                spin_unlock_irqrestore(&write_list_lock, flags);
                result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-               if (result) {
-                       err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
-               }
+               if (result)
+                       dev_err(&port->dev,
+                               "%s - failed submitting write urb, error %d\n",
+                               __func__, result);
        } else {
                spin_unlock_irqrestore(&write_list_lock, flags);
        }
@@ -856,32 +858,31 @@ static void ipaq_write_gather(struct usb_serial_port *port)
                        list_move(&pkt->list, &priv->freelist);
                        priv->free_len += PACKET_SIZE;
                }
-               if (room == 0) {
+               if (room == 0)
                        break;
-               }
        }
 
        count = URBDATA_SIZE - room;
-       usb_fill_bulk_urb(port->write_urb, serial->dev, 
-                     usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
-                     port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback,
-                     port);
+       usb_fill_bulk_urb(port->write_urb, serial->dev,
+               usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+               port->write_urb->transfer_buffer, count,
+               ipaq_write_bulk_callback, port);
        return;
 }
 
 static void ipaq_write_bulk_callback(struct urb *urb)
 {
-       struct usb_serial_port  *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial_port  *port = urb->context;
        struct ipaq_private     *priv = usb_get_serial_port_data(port);
        unsigned long           flags;
        int                     result;
        int status = urb->status;
 
-       dbg("%s - port %d", __FUNCTION__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        if (status) {
                dbg("%s - nonzero write bulk status received: %d",
-                   __FUNCTION__, status);
+                   __func__, status);
                return;
        }
 
@@ -890,9 +891,10 @@ static void ipaq_write_bulk_callback(struct urb *urb)
                ipaq_write_gather(port);
                spin_unlock_irqrestore(&write_list_lock, flags);
                result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-               if (result) {
-                       err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
-               }
+               if (result)
+                       dev_err(&port->dev,
+                               "%s - failed submitting write urb, error %d\n",
+                               __func__, result);
        } else {
                priv->active = 0;
                spin_unlock_irqrestore(&write_list_lock, flags);
@@ -901,19 +903,21 @@ static void ipaq_write_bulk_callback(struct urb *urb)
        usb_serial_port_softint(port);
 }
 
-static int ipaq_write_room(struct usb_serial_port *port)
+static int ipaq_write_room(struct tty_struct *tty)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct ipaq_private     *priv = usb_get_serial_port_data(port);
 
-       dbg("%s - freelen %d", __FUNCTION__, priv->free_len);
+       dbg("%s - freelen %d", __func__, priv->free_len);
        return priv->free_len;
 }
 
-static int ipaq_chars_in_buffer(struct usb_serial_port *port)
+static int ipaq_chars_in_buffer(struct tty_struct *tty)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct ipaq_private     *priv = usb_get_serial_port_data(port);
 
-       dbg("%s - queuelen %d", __FUNCTION__, priv->queue_len);
+       dbg("%s - queuelen %d", __func__, priv->queue_len);
        return priv->queue_len;
 }
 
@@ -933,20 +937,59 @@ static void ipaq_destroy_lists(struct usb_serial_port *port)
 }
 
 
+static int ipaq_calc_num_ports(struct usb_serial *serial)
+{
+       /*
+        * some devices have 3 endpoints, the 3rd of which
+        * must be ignored as it would make the core
+        * create a second port which oopses when used
+        */
+       int ipaq_num_ports = 1;
+
+       dbg("%s - numberofendpoints: %d", __FUNCTION__,
+               (int)serial->interface->cur_altsetting->desc.bNumEndpoints);
+
+       /*
+        * a few devices have 4 endpoints, seemingly Yakuma devices,
+        * and we need the second pair, so let them have 2 ports
+        *
+        * TODO: can we drop port 1 ?
+        */
+       if (serial->interface->cur_altsetting->desc.bNumEndpoints > 3) {
+               ipaq_num_ports = 2;
+       }
+
+       return ipaq_num_ports;
+}
+
+
 static int ipaq_startup(struct usb_serial *serial)
 {
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __func__);
+
+       /* Some of the devices in ipaq_id_table[] are composite, and we
+        * shouldn't bind to all the interfaces.  This test will rule out
+        * some obviously invalid possibilities.
+        */
+       if (serial->num_bulk_in < serial->num_ports ||
+                       serial->num_bulk_out < serial->num_ports)
+               return -ENODEV;
+
        if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
-               err("active config #%d != 1 ??",
+               /*
+                * FIXME: HP iPaq rx3715, possibly others, have 1 config that
+                * is labeled as 2
+                */
+
+               dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
                        serial->dev->actconfig->desc.bConfigurationValue);
                return -ENODEV;
        }
-       return usb_reset_configuration (serial->dev);
-}
 
-static void ipaq_shutdown(struct usb_serial *serial)
-{
-       dbg("%s", __FUNCTION__);
+       dbg("%s - iPAQ module configured for %d ports",
+               __FUNCTION__, serial->num_ports);
+
+       return usb_reset_configuration(serial->dev);
 }
 
 static int __init ipaq_init(void)
@@ -954,9 +997,8 @@ static int __init ipaq_init(void)
        int retval;
        spin_lock_init(&write_list_lock);
        retval = usb_serial_register(&ipaq_device);
-       if (retval) 
+       if (retval)
                goto failed_usb_serial_register;
-       info(DRIVER_DESC " " DRIVER_VERSION);
        if (vendor) {
                ipaq_id_table[0].idVendor = vendor;
                ipaq_id_table[0].idProduct = product;
@@ -964,7 +1006,9 @@ static int __init ipaq_init(void)
        retval = usb_register(&ipaq_driver);
        if (retval)
                goto failed_usb_register;
-                 
+
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+              DRIVER_DESC "\n");
        return 0;
 failed_usb_register:
        usb_serial_deregister(&ipaq_device);
@@ -983,8 +1027,8 @@ static void __exit ipaq_exit(void)
 module_init(ipaq_init);
 module_exit(ipaq_exit);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
@@ -997,7 +1041,9 @@ module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified USB idProduct");
 
 module_param(connect_retries, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(connect_retries, "Maximum number of connect retries (one second each)");
+MODULE_PARM_DESC(connect_retries,
+               "Maximum number of connect retries (one second each)");
 
 module_param(initial_wait, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(initial_wait, "Time to wait before attempting a connection (in seconds)");
+MODULE_PARM_DESC(initial_wait,
+               "Time to wait before attempting a connection (in seconds)");