fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / usb / serial / option.c
index b722175..0fed43a 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  Option Card (PCMCIA to) USB to Serial Driver
+  USB Driver for GSM modems
 
   Copyright (C) 2005  Matthias Urlichs <smurf@smurf.noris.de>
 
@@ -9,21 +9,29 @@
 
   Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 
-  History:
+  History: see the git log.
 
-  2005-05-19  v0.1   Initial version, based on incomplete docs
-                     and analysis of misbehavior of the standard driver
-  2005-05-20  v0.2   Extended the input buffer to avoid losing
-                     random 64-byte chunks of data
-  2005-05-21  v0.3   implemented chars_in_buffer()
-                     turned on low_latency
-                     simplified the code somewhat
+  Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
+
+  This driver exists because the "normal" serial driver doesn't work too well
+  with GSM modems. Issues:
+  - data loss -- one single Receive URB is not nearly enough
+  - nonstandard flow (Option devices) control
+  - controlling the baud rate doesn't make sense
+
+  This driver is named "option" because the most common device it's
+  used for is a PC-Card (with an internal OHCI-USB interface, behind
+  which the GSM interface sits), made by Option Inc.
+
+  Some of the "one port" devices actually exhibit multiple USB instances
+  on the USB bus. This is not a bug, these ports are used for different
+  device features.
 */
-#define DRIVER_VERSION "v0.3"
+
+#define DRIVER_VERSION "v0.7.1"
 #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
-#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver"
+#define DRIVER_DESC "USB Driver for GSM modems"
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
 #include <linux/errno.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
 
 /* Function prototypes */
-static int  option_open (struct usb_serial_port *port, struct file *filp);
-static void option_close (struct usb_serial_port *port, struct file *filp);
-static int  option_startup (struct usb_serial *serial);
-static void option_shutdown (struct usb_serial *serial);
-static void option_rx_throttle (struct usb_serial_port *port);
-static void option_rx_unthrottle (struct usb_serial_port *port);
-static int  option_write_room (struct usb_serial_port *port);
-
-static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
-
-
-static int  option_write (struct usb_serial_port *port,
-                          const unsigned char *buf, int count);
-
-static int  option_chars_in_buffer (struct usb_serial_port *port);
-static int  option_ioctl (struct usb_serial_port *port, struct file *file,
-                          unsigned int cmd, unsigned long arg);
-static void option_set_termios (struct usb_serial_port *port,
-                                struct termios *old);
-static void option_break_ctl (struct usb_serial_port *port, int break_state);
-static int  option_tiocmget (struct usb_serial_port *port, struct file *file);
-static int  option_tiocmset (struct usb_serial_port *port, struct file *file,
-                             unsigned int set, unsigned int clear);
-static int  option_send_setup (struct usb_serial_port *port);
+static int  option_open(struct usb_serial_port *port, struct file *filp);
+static void option_close(struct usb_serial_port *port, struct file *filp);
+static int  option_startup(struct usb_serial *serial);
+static void option_shutdown(struct usb_serial *serial);
+static void option_rx_throttle(struct usb_serial_port *port);
+static void option_rx_unthrottle(struct usb_serial_port *port);
+static int  option_write_room(struct usb_serial_port *port);
+
+static void option_instat_callback(struct urb *urb);
+
+static int option_write(struct usb_serial_port *port,
+                       const unsigned char *buf, int count);
+
+static int  option_chars_in_buffer(struct usb_serial_port *port);
+static int  option_ioctl(struct usb_serial_port *port, struct file *file,
+                       unsigned int cmd, unsigned long arg);
+static void option_set_termios(struct usb_serial_port *port,
+                               struct ktermios *old);
+static void option_break_ctl(struct usb_serial_port *port, int break_state);
+static int  option_tiocmget(struct usb_serial_port *port, struct file *file);
+static int  option_tiocmset(struct usb_serial_port *port, struct file *file,
+                               unsigned int set, unsigned int clear);
+static int  option_send_setup(struct usb_serial_port *port);
 
 /* Vendor and product IDs */
-#define OPTION_VENDOR_ID               0x0AF0
-
-#define        OPTION_PRODUCT_OLD              0x5000
-#define        OPTION_PRODUCT_WLAN             0x6000
+#define OPTION_VENDOR_ID                0x0AF0
+#define HUAWEI_VENDOR_ID                0x12D1
+#define AUDIOVOX_VENDOR_ID              0x0F3D
+#define NOVATELWIRELESS_VENDOR_ID       0x1410
+#define ANYDATA_VENDOR_ID               0x16d5
+
+#define OPTION_PRODUCT_OLD              0x5000
+#define OPTION_PRODUCT_FUSION           0x6000
+#define OPTION_PRODUCT_FUSION2          0x6300
+#define OPTION_PRODUCT_COBRA            0x6500
+#define OPTION_PRODUCT_COBRA2           0x6600
+#define OPTION_PRODUCT_GTMAX36          0x6701
+#define HUAWEI_PRODUCT_E600             0x1001
+#define HUAWEI_PRODUCT_E220             0x1003
+#define AUDIOVOX_PRODUCT_AIRCARD        0x0112
+#define NOVATELWIRELESS_PRODUCT_U740    0x1400
+#define ANYDATA_PRODUCT_ID              0x6501
 
 static struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_WLAN) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
+       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
+       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
+       { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
+       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
+       { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
+       { } /* Terminating entry */
+};
+
+static struct usb_device_id option_ids1[] = {
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
+       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
+       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
+       { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
+       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
+       { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
        { } /* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE(usb, option_ids);
 
 static struct usb_driver option_driver = {
-       .owner      = THIS_MODULE,
        .name       = "option",
        .probe      = usb_serial_probe,
        .disconnect = usb_serial_disconnect,
        .id_table   = option_ids,
+       .no_dynamic_id =        1,
 };
 
-/* The card has three separate interfaces, wich the serial driver
+/* The card has three separate interfaces, which the serial driver
  * recognizes separately, thus num_port=1.
  */
-static struct usb_serial_device_type option_3port_device = {
-       .owner                  = THIS_MODULE,
-       .name                   = "Option 3-port card",
-       .short_name             = "option",
-       .id_table               = option_ids,
-       .num_interrupt_in       = NUM_DONT_CARE,
-       .num_bulk_in            = NUM_DONT_CARE,
-       .num_bulk_out           = NUM_DONT_CARE,
-       .num_ports              = 1, /* 3 */
-       .open                   = option_open,
-       .close                  = option_close,
-       .write                  = option_write,
-       .write_room             = option_write_room,
-       .chars_in_buffer        = option_chars_in_buffer,
-       .throttle               = option_rx_throttle,
-       .unthrottle             = option_rx_unthrottle,
-       .ioctl                  = option_ioctl,
-       .set_termios            = option_set_termios,
-       .break_ctl              = option_break_ctl,
-       .tiocmget               = option_tiocmget,
-       .tiocmset               = option_tiocmset,
-       .attach                 = option_startup,
-       .shutdown               = option_shutdown,
-       .read_int_callback      = option_instat_callback,
+
+static struct usb_serial_driver option_1port_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "option1",
+       },
+       .description       = "GSM modem (1-port)",
+       .id_table          = option_ids1,
+       .num_interrupt_in  = NUM_DONT_CARE,
+       .num_bulk_in       = NUM_DONT_CARE,
+       .num_bulk_out      = NUM_DONT_CARE,
+       .num_ports         = 1,
+       .open              = option_open,
+       .close             = option_close,
+       .write             = option_write,
+       .write_room        = option_write_room,
+       .chars_in_buffer   = option_chars_in_buffer,
+       .throttle          = option_rx_throttle,
+       .unthrottle        = option_rx_unthrottle,
+       .ioctl             = option_ioctl,
+       .set_termios       = option_set_termios,
+       .break_ctl         = option_break_ctl,
+       .tiocmget          = option_tiocmget,
+       .tiocmset          = option_tiocmset,
+       .attach            = option_startup,
+       .shutdown          = option_shutdown,
+       .read_int_callback = option_instat_callback,
 };
 
+#ifdef CONFIG_USB_DEBUG
 static int debug;
+#else
+#define debug 0
+#endif
 
 /* per port private data */
 
-#define N_IN_URB       4
-#define N_OUT_URB      1
-#define IN_BUFLEN      1024
-#define OUT_BUFLEN     1024
+#define N_IN_URB 4
+#define N_OUT_URB 1
+#define IN_BUFLEN 4096
+#define OUT_BUFLEN 128
 
 struct option_port_private {
        /* Input endpoints and buffer for this port */
-       struct urb      *in_urbs[N_IN_URB];
-       char            in_buffer[N_IN_URB][IN_BUFLEN];
+       struct urb *in_urbs[N_IN_URB];
+       char in_buffer[N_IN_URB][IN_BUFLEN];
        /* Output endpoints and buffer for this port */
-       struct urb      *out_urbs[N_OUT_URB];
-       char            out_buffer[N_OUT_URB][OUT_BUFLEN];
+       struct urb *out_urbs[N_OUT_URB];
+       char out_buffer[N_OUT_URB][OUT_BUFLEN];
 
        /* Settings for the port */
-       int             rts_state;      /* Handshaking pins (outputs) */
-       int             dtr_state;
-       int             cts_state;      /* Handshaking pins (inputs) */
-       int             dsr_state;
-       int             dcd_state;
-       int             ri_state;
-       // int          break_on;
-
-       unsigned long   tx_start_time[N_OUT_URB];
+       int rts_state;  /* Handshaking pins (outputs) */
+       int dtr_state;
+       int cts_state;  /* Handshaking pins (inputs) */
+       int dsr_state;
+       int dcd_state;
+       int ri_state;
+
+       unsigned long tx_start_time[N_OUT_URB];
 };
 
-
 /* Functions used by new usb-serial code. */
-static int __init
-option_init (void)
+static int __init option_init(void)
 {
        int retval;
-       retval = usb_serial_register(&option_3port_device);
+       retval = usb_serial_register(&option_1port_device);
        if (retval)
-               goto failed_3port_device_register;
+               goto failed_1port_device_register;
        retval = usb_register(&option_driver);
        if (retval)
                goto failed_driver_register;
@@ -157,57 +205,48 @@ option_init (void)
        return 0;
 
 failed_driver_register:
-       usb_serial_deregister (&option_3port_device);
-failed_3port_device_register:
+       usb_serial_deregister (&option_1port_device);
+failed_1port_device_register:
        return retval;
 }
 
-static void __exit
-option_exit (void)
+static void __exit option_exit(void)
 {
        usb_deregister (&option_driver);
-       usb_serial_deregister (&option_3port_device);
+       usb_serial_deregister (&option_1port_device);
 }
 
 module_init(option_init);
 module_exit(option_exit);
 
-static void
-option_rx_throttle (struct usb_serial_port *port)
+static void option_rx_throttle(struct usb_serial_port *port)
 {
        dbg("%s", __FUNCTION__);
 }
 
-
-static void
-option_rx_unthrottle (struct usb_serial_port *port)
+static void option_rx_unthrottle(struct usb_serial_port *port)
 {
        dbg("%s", __FUNCTION__);
 }
 
-
-static void
-option_break_ctl (struct usb_serial_port *port, int break_state)
+static void option_break_ctl(struct usb_serial_port *port, int break_state)
 {
        /* Unfortunately, I don't know how to send a break */
-       dbg("%s", __FUNCTION__);
+       dbg("%s", __FUNCTION__);
 }
 
-
-static void
-option_set_termios (struct usb_serial_port *port,
-                                    struct termios *old_termios)
+static void option_set_termios(struct usb_serial_port *port,
+                       struct ktermios *old_termios)
 {
        dbg("%s", __FUNCTION__);
 
        option_send_setup(port);
 }
 
-static int
-option_tiocmget(struct usb_serial_port *port, struct file *file)
+static int option_tiocmget(struct usb_serial_port *port, struct file *file)
 {
-       unsigned int                    value;
-       struct option_port_private      *portdata;
+       unsigned int value;
+       struct option_port_private *portdata;
 
        portdata = usb_get_serial_port_data(port);
 
@@ -221,11 +260,10 @@ option_tiocmget(struct usb_serial_port *port, struct file *file)
        return value;
 }
 
-static int
-option_tiocmset (struct usb_serial_port *port, struct file *file,
-                 unsigned int set, unsigned int clear)
+static int option_tiocmset(struct usb_serial_port *port, struct file *file,
+                       unsigned int set, unsigned int clear)
 {
-       struct option_port_private      *portdata;
+       struct option_port_private *portdata;
 
        portdata = usb_get_serial_port_data(port);
 
@@ -241,80 +279,58 @@ option_tiocmset (struct usb_serial_port *port, struct file *file,
        return option_send_setup(port);
 }
 
-static int
-option_ioctl (struct usb_serial_port *port, struct file *file,
-              unsigned int cmd, unsigned long arg)
+static int option_ioctl(struct usb_serial_port *port, struct file *file,
+                       unsigned int cmd, unsigned long arg)
 {
        return -ENOIOCTLCMD;
 }
 
 /* Write */
-static int
-option_write(struct usb_serial_port *port,
-                        const unsigned char *buf, int count)
+static int option_write(struct usb_serial_port *port,
+                       const unsigned char *buf, int count)
 {
-       struct option_port_private      *portdata;
-       int                             i;
-       int                             left, todo;
-       struct urb                      *this_urb = NULL; /* spurious */
-       int                             err;
+       struct option_port_private *portdata;
+       int i;
+       int left, todo;
+       struct urb *this_urb = NULL; /* spurious */
+       int err;
 
        portdata = usb_get_serial_port_data(port);
 
        dbg("%s: write (%d chars)", __FUNCTION__, count);
 
-#if 0
-       spin_lock(&port->lock);
-       if (port->write_urb_busy) {
-               spin_unlock(&port->lock);
-               dbg("%s: already writing", __FUNCTION__);
-               return 0;
-       }
-       port->write_urb_busy = 1;
-       spin_unlock(&port->lock);
-#endif
-
        i = 0;
        left = count;
-       while (left>0) {
+       for (i=0; left > 0 && i < N_OUT_URB; i++) {
                todo = left;
                if (todo > OUT_BUFLEN)
                        todo = OUT_BUFLEN;
 
-               for (;i < N_OUT_URB; i++) {
-                       /* Check we have a valid urb/endpoint before we use it... */
-                       this_urb = portdata->out_urbs[i];
-                       if (this_urb->status != -EINPROGRESS)
-                               break;
-                       if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
-                               continue;
-                       if (time_before(jiffies, portdata->tx_start_time[i] + 10 * HZ))
+               this_urb = portdata->out_urbs[i];
+               if (this_urb->status == -EINPROGRESS) {
+                       if (time_before(jiffies,
+                                       portdata->tx_start_time[i] + 10 * HZ))
                                continue;
-                       this_urb->transfer_flags |= URB_ASYNC_UNLINK;
                        usb_unlink_urb(this_urb);
+                       continue;
                }
+               if (this_urb->status != 0)
+                       dbg("usb_write %p failed (err=%d)",
+                               this_urb, this_urb->status);
 
-               if (i == N_OUT_URB) {
-                       /* no bulk out free! */
-                       dbg("%s: no output urb -- left %d", __FUNCTION__,count-left);
-#if 0
-                       port->write_urb_busy = 0;
-#endif
-                       return count-left;
-               }
-
-               dbg("%s: endpoint %d buf %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), i);
+               dbg("%s: endpoint %d buf %d", __FUNCTION__,
+                       usb_pipeendpoint(this_urb->pipe), i);
 
+               /* send the data */
                memcpy (this_urb->transfer_buffer, buf, todo);
-
-               /* send the data out the bulk port */
                this_urb->transfer_buffer_length = todo;
 
-               this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
                this_urb->dev = port->serial->dev;
                err = usb_submit_urb(this_urb, GFP_ATOMIC);
                if (err) {
-                       dbg("usb_submit_urb %p (write bulk) failed (%d,, has %d)", this_urb, err, this_urb->status);
+                       dbg("usb_submit_urb %p (write bulk) failed "
+                               "(%d, has %d)", this_urb,
+                               err, this_urb->status);
                        continue;
                }
                portdata->tx_start_time[i] = jiffies;
@@ -323,17 +339,13 @@ option_write(struct usb_serial_port *port,
        }
 
        count -= left;
-#if 0
-       port->write_urb_busy = 0;
-#endif
        dbg("%s: wrote (did %d)", __FUNCTION__, count);
        return count;
 }
 
-static void
-option_indat_callback (struct urb *urb, struct pt_regs *regs)
+static void option_indat_callback(struct urb *urb)
 {
-       int     i, err;
+       int err;
        int endpoint;
        struct usb_serial_port *port;
        struct tty_struct *tty;
@@ -350,11 +362,8 @@ option_indat_callback (struct urb *urb, struct pt_regs *regs)
        } else {
                tty = port->tty;
                if (urb->actual_length) {
-                       for (i = 0; i < urb->actual_length ; ++i) {
-                               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                                       tty_flip_buffer_push(tty);
-                               tty_insert_flip_char(tty, data[i], 0);
-                       }
+                       tty_buffer_request_room(tty, urb->actual_length);
+                       tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
                } else {
                        dbg("%s: empty read urb received", __FUNCTION__);
@@ -364,14 +373,14 @@ option_indat_callback (struct urb *urb, struct pt_regs *regs)
                if (port->open_count && urb->status != -ESHUTDOWN) {
                        err = usb_submit_urb(urb, GFP_ATOMIC);
                        if (err)
-                               printk(KERN_ERR "%s: resubmit read urb failed. (%d)", __FUNCTION__, err);
+                               printk(KERN_ERR "%s: resubmit read urb failed. "
+                                       "(%d)", __FUNCTION__, err);
                }
        }
        return;
 }
 
-static void
-option_outdat_callback (struct urb *urb, struct pt_regs *regs)
+static void option_outdat_callback(struct urb *urb)
 {
        struct usb_serial_port *port;
 
@@ -379,12 +388,10 @@ option_outdat_callback (struct urb *urb, struct pt_regs *regs)
 
        port = (struct usb_serial_port *) urb->context;
 
-       if (port->open_count)
-               schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
-static void
-option_instat_callback (struct urb *urb, struct pt_regs *regs)
+static void option_instat_callback(struct urb *urb)
 {
        int err;
        struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
@@ -402,10 +409,12 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
                        dbg("%s: NULL req_pkt\n", __FUNCTION__);
                        return;
                }
-               if ((req_pkt->bRequestType == 0xA1) && (req_pkt->bRequest == 0x20)) {
+               if ((req_pkt->bRequestType == 0xA1) &&
+                               (req_pkt->bRequest == 0x20)) {
                        int old_dcd_state;
                        unsigned char signals = *((unsigned char *)
-                                       urb->transfer_buffer + sizeof(struct usb_ctrlrequest));
+                                       urb->transfer_buffer +
+                                       sizeof(struct usb_ctrlrequest));
 
                        dbg("%s: signal x%x", __FUNCTION__, signals);
 
@@ -415,12 +424,13 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
                        portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
                        portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-                       if (port->tty && !C_CLOCAL(port->tty)
-                                       && old_dcd_state && !portdata->dcd_state) {
+                       if (port->tty && !C_CLOCAL(port->tty) &&
+                                       old_dcd_state && !portdata->dcd_state)
                                tty_hangup(port->tty);
-                       }
-               } else
-                       dbg("%s: type %x req %x", __FUNCTION__, req_pkt->bRequestType,req_pkt->bRequest);
+               } else {
+                       dbg("%s: type %x req %x", __FUNCTION__,
+                               req_pkt->bRequestType,req_pkt->bRequest);
+               }
        } else
                dbg("%s: error %d", __FUNCTION__, urb->status);
 
@@ -429,13 +439,12 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
                urb->dev = serial->dev;
                err = usb_submit_urb(urb, GFP_ATOMIC);
                if (err)
-                       dbg("%s: resubmit intr urb failed. (%d)", __FUNCTION__, err);
+                       dbg("%s: resubmit intr urb failed. (%d)",
+                               __FUNCTION__, err);
        }
 }
 
-
-static int
-option_write_room (struct usb_serial_port *port)
+static int option_write_room(struct usb_serial_port *port)
 {
        struct option_port_private *portdata;
        int i;
@@ -444,18 +453,17 @@ option_write_room (struct usb_serial_port *port)
 
        portdata = usb_get_serial_port_data(port);
 
-       for (i=0; i < N_OUT_URB; i++)
+       for (i=0; i < N_OUT_URB; i++) {
                this_urb = portdata->out_urbs[i];
                if (this_urb && this_urb->status != -EINPROGRESS)
                        data_len += OUT_BUFLEN;
+       }
 
        dbg("%s: %d", __FUNCTION__, data_len);
        return data_len;
 }
 
-
-static int
-option_chars_in_buffer (struct usb_serial_port *port)
+static int option_chars_in_buffer(struct usb_serial_port *port)
 {
        struct option_port_private *portdata;
        int i;
@@ -464,23 +472,21 @@ option_chars_in_buffer (struct usb_serial_port *port)
 
        portdata = usb_get_serial_port_data(port);
 
-       for (i=0; i < N_OUT_URB; i++)
+       for (i=0; i < N_OUT_URB; i++) {
                this_urb = portdata->out_urbs[i];
                if (this_urb && this_urb->status == -EINPROGRESS)
                        data_len += this_urb->transfer_buffer_length;
-
+       }
        dbg("%s: %d", __FUNCTION__, data_len);
        return data_len;
 }
 
-
-static int
-option_open (struct usb_serial_port *port, struct file *filp)
+static int option_open(struct usb_serial_port *port, struct file *filp)
 {
-       struct option_port_private      *portdata;
-       struct usb_serial               *serial = port->serial;
-       int                             i, err;
-       struct urb                      *urb;
+       struct option_port_private *portdata;
+       struct usb_serial *serial = port->serial;
+       int i, err;
+       struct urb *urb;
 
        portdata = usb_get_serial_port_data(port);
 
@@ -496,17 +502,21 @@ option_open (struct usb_serial_port *port, struct file *filp)
                if (! urb)
                        continue;
                if (urb->dev != serial->dev) {
-                       dbg("%s: dev %p != %p", __FUNCTION__, urb->dev, serial->dev);
+                       dbg("%s: dev %p != %p", __FUNCTION__,
+                               urb->dev, serial->dev);
                        continue;
                }
 
-               /* make sure endpoint data toggle is synchronized with the device */
-
+               /*
+                * make sure endpoint data toggle is synchronized with the
+                * device
+                */
                usb_clear_halt(urb->dev, urb->pipe);
 
                err = usb_submit_urb(urb, GFP_KERNEL);
                if (err) {
-                       dbg("%s: submit urb %d failed (%d) %d", __FUNCTION__, i, err,
+                       dbg("%s: submit urb %d failed (%d) %d",
+                               __FUNCTION__, i, err,
                                urb->transfer_buffer_length);
                }
        }
@@ -517,7 +527,8 @@ option_open (struct usb_serial_port *port, struct file *filp)
                if (! urb)
                        continue;
                urb->dev = serial->dev;
-               /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
+               /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                               usb_pipeout(urb->pipe), 0); */
        }
 
        port->tty->low_latency = 1;
@@ -527,21 +538,17 @@ option_open (struct usb_serial_port *port, struct file *filp)
        return (0);
 }
 
-static inline void
-stop_urb(struct urb *urb)
+static inline void stop_urb(struct urb *urb)
 {
-       if (urb && urb->status == -EINPROGRESS) {
-               urb->transfer_flags &= ~URB_ASYNC_UNLINK;
+       if (urb && urb->status == -EINPROGRESS)
                usb_kill_urb(urb);
-       }
 }
 
-static void
-option_close(struct usb_serial_port *port, struct file *filp)
+static void option_close(struct usb_serial_port *port, struct file *filp)
 {
-       int                     i;
-       struct usb_serial       *serial = port->serial;
-       struct option_port_private      *portdata;
+       int i;
+       struct usb_serial *serial = port->serial;
+       struct option_port_private *portdata;
 
        dbg("%s", __FUNCTION__);
        portdata = usb_get_serial_port_data(port);
@@ -561,12 +568,10 @@ option_close(struct usb_serial_port *port, struct file *filp)
        port->tty = NULL;
 }
 
-
 /* Helper functions used by option_setup_urbs */
-static struct urb *
-option_setup_urb (struct usb_serial *serial, int endpoint,
-                  int dir, void *ctx, char *buf, int len,
-                  void (*callback)(struct urb *, struct pt_regs *regs))
+static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
+               int dir, void *ctx, char *buf, int len,
+               void (*callback)(struct urb *))
 {
        struct urb *urb;
 
@@ -588,42 +593,44 @@ option_setup_urb (struct usb_serial *serial, int endpoint,
 }
 
 /* Setup urbs */
-static void
-option_setup_urbs(struct usb_serial *serial)
+static void option_setup_urbs(struct usb_serial *serial)
 {
-       int                             j;
-       struct usb_serial_port          *port;
-       struct option_port_private      *portdata;
+       int i,j;
+       struct usb_serial_port *port;
+       struct option_port_private *portdata;
 
        dbg("%s", __FUNCTION__);
 
-       port = serial->port[0];
-       portdata = usb_get_serial_port_data(port);
+       for (i = 0; i < serial->num_ports; i++) {
+               port = serial->port[i];
+               portdata = usb_get_serial_port_data(port);
 
        /* Do indat endpoints first */
-       for (j = 0; j <= N_IN_URB; ++j) {
-               portdata->in_urbs[j] = option_setup_urb (serial,
-                  port->bulk_in_endpointAddress, USB_DIR_IN, port,
-                  portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
-       }
+               for (j = 0; j < N_IN_URB; ++j) {
+                       portdata->in_urbs[j] = option_setup_urb (serial,
+                       port->bulk_in_endpointAddress, USB_DIR_IN, port,
+                       portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
+               }
 
-       /* outdat endpoints */
-       for (j = 0; j <= N_OUT_URB; ++j) {
-               portdata->out_urbs[j] = option_setup_urb (serial,
-                  port->bulk_out_endpointAddress, USB_DIR_OUT, port,
-                  portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
+               /* outdat endpoints */
+               for (j = 0; j < N_OUT_URB; ++j) {
+                       portdata->out_urbs[j] = option_setup_urb (serial,
+                       port->bulk_out_endpointAddress, USB_DIR_OUT, port,
+                       portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
+               }
        }
 }
 
-
-static int
-option_send_setup(struct usb_serial_port *port)
+static int option_send_setup(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
        struct option_port_private *portdata;
 
        dbg("%s", __FUNCTION__);
 
+       if (port->number != 0)
+               return 0;
+
        portdata = usb_get_serial_port_data(port);
 
        if (port->tty) {
@@ -633,32 +640,31 @@ option_send_setup(struct usb_serial_port *port)
                if (portdata->rts_state)
                        val |= 0x02;
 
-               return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-                                       0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+               return usb_control_msg(serial->dev,
+                               usb_rcvctrlpipe(serial->dev, 0),
+                               0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
        }
 
        return 0;
 }
 
-
-static int
-option_startup (struct usb_serial *serial)
+static int option_startup(struct usb_serial *serial)
 {
-       int                             i, err;
-       struct usb_serial_port          *port;
-       struct option_port_private      *portdata;
+       int i, err;
+       struct usb_serial_port *port;
+       struct option_port_private *portdata;
 
        dbg("%s", __FUNCTION__);
 
        /* Now setup per port private data */
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
-               portdata = kmalloc(sizeof(struct option_port_private), GFP_KERNEL);
+               portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
                if (!portdata) {
-                       dbg("%s: kmalloc for option_port_private (%d) failed!.", __FUNCTION__, i);
+                       dbg("%s: kmalloc for option_port_private (%d) failed!.",
+                                       __FUNCTION__, i);
                        return (1);
                }
-               memset(portdata, 0, sizeof(struct option_port_private));
 
                usb_set_serial_port_data(port, portdata);
 
@@ -666,7 +672,8 @@ option_startup (struct usb_serial *serial)
                        continue;
                err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
                if (err)
-                       dbg("%s: submit irq_in urb failed %d", __FUNCTION__, err);
+                       dbg("%s: submit irq_in urb failed %d",
+                               __FUNCTION__, err);
        }
 
        option_setup_urbs(serial);
@@ -674,12 +681,11 @@ option_startup (struct usb_serial *serial)
        return (0);
 }
 
-static void
-option_shutdown (struct usb_serial *serial)
+static void option_shutdown(struct usb_serial *serial)
 {
-       int                             i, j;
-       struct usb_serial_port          *port;
-       struct option_port_private      *portdata;
+       int i, j;
+       struct usb_serial_port *port;
+       struct option_port_private *portdata;
 
        dbg("%s", __FUNCTION__);
 
@@ -724,6 +730,8 @@ MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
+#ifdef CONFIG_USB_DEBUG
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug messages");
+#endif