Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
[cascardo/linux.git] / drivers / usb / serial / option.c
index 8c3f55b..84c12b5 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
@@ -111,7 +112,8 @@ static int  option_send_setup(struct usb_serial_port *port);
 #define NOVATELWIRELESS_VENDOR_ID              0x1410
 
 #define ANYDATA_VENDOR_ID                      0x16d5
-#define ANYDATA_PRODUCT_ID                     0x6501
+#define ANYDATA_PRODUCT_ADU_E100A              0x6501
+#define ANYDATA_PRODUCT_ADU_500A               0x6502
 
 #define BANDRICH_VENDOR_ID                     0x1A8D
 #define BANDRICH_PRODUCT_C100_1                        0x1002
@@ -165,12 +167,12 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1410) }, /* Novatel U740 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1420) }, /* Novatel EU870 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */
-       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1430) }, /* Novatel XU870 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2100) }, /* Novatel EV620 CDMA/EV-DO */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2110) }, /* Novatel Merlin ES620 / Merlin ES720 / Ovation U720 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
-       { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
+       { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
+       { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
        { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
        { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
        { USB_DEVICE(DELL_VENDOR_ID, 0x8118) },         /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard */
@@ -239,6 +241,7 @@ struct option_port_private {
        /* Output endpoints and buffer for this port */
        struct urb *out_urbs[N_OUT_URB];
        char out_buffer[N_OUT_URB][OUT_BUFLEN];
+       unsigned long out_busy;         /* Bit vector of URBs in use */
 
        /* Settings for the port */
        int rts_state;  /* Handshaking pins (outputs) */
@@ -369,7 +372,7 @@ static int option_write(struct usb_serial_port *port,
                        todo = OUT_BUFLEN;
 
                this_urb = portdata->out_urbs[i];
-               if (this_urb->status == -EINPROGRESS) {
+               if (test_and_set_bit(i, &portdata->out_busy)) {
                        if (time_before(jiffies,
                                        portdata->tx_start_time[i] + 10 * HZ))
                                continue;
@@ -393,6 +396,7 @@ static int option_write(struct usb_serial_port *port,
                        dbg("usb_submit_urb %p (write bulk) failed "
                                "(%d, has %d)", this_urb,
                                err, this_urb->status);
+                       clear_bit(i, &portdata->out_busy);
                        continue;
                }
                portdata->tx_start_time[i] = jiffies;
@@ -412,15 +416,16 @@ static void option_indat_callback(struct urb *urb)
        struct usb_serial_port *port;
        struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
+       int status = urb->status;
 
        dbg("%s: %p", __FUNCTION__, urb);
 
        endpoint = usb_pipeendpoint(urb->pipe);
        port = (struct usb_serial_port *) urb->context;
 
-       if (urb->status) {
+       if (status) {
                dbg("%s: nonzero status: %d on endpoint %02x.",
-                   __FUNCTION__, urb->status, endpoint);
+                   __FUNCTION__, status, endpoint);
        } else {
                tty = port->tty;
                if (urb->actual_length) {
@@ -432,7 +437,7 @@ static void option_indat_callback(struct urb *urb)
                }
 
                /* Resubmit urb so we continue receiving */
-               if (port->open_count && urb->status != -ESHUTDOWN) {
+               if (port->open_count && status != -ESHUTDOWN) {
                        err = usb_submit_urb(urb, GFP_ATOMIC);
                        if (err)
                                printk(KERN_ERR "%s: resubmit read urb failed. "
@@ -445,17 +450,29 @@ static void option_indat_callback(struct urb *urb)
 static void option_outdat_callback(struct urb *urb)
 {
        struct usb_serial_port *port;
+       struct option_port_private *portdata;
+       int i;
 
        dbg("%s", __FUNCTION__);
 
        port = (struct usb_serial_port *) urb->context;
 
        usb_serial_port_softint(port);
+
+       portdata = usb_get_serial_port_data(port);
+       for (i = 0; i < N_OUT_URB; ++i) {
+               if (portdata->out_urbs[i] == urb) {
+                       smp_mb__before_clear_bit();
+                       clear_bit(i, &portdata->out_busy);
+                       break;
+               }
+       }
 }
 
 static void option_instat_callback(struct urb *urb)
 {
        int err;
+       int status = urb->status;
        struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
        struct option_port_private *portdata = usb_get_serial_port_data(port);
        struct usb_serial *serial = port->serial;
@@ -463,7 +480,7 @@ static void option_instat_callback(struct urb *urb)
        dbg("%s", __FUNCTION__);
        dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
 
-       if (urb->status == 0) {
+       if (status == 0) {
                struct usb_ctrlrequest *req_pkt =
                                (struct usb_ctrlrequest *)urb->transfer_buffer;
 
@@ -494,10 +511,10 @@ static void option_instat_callback(struct urb *urb)
                                req_pkt->bRequestType,req_pkt->bRequest);
                }
        } else
-               dbg("%s: error %d", __FUNCTION__, urb->status);
+               dbg("%s: error %d", __FUNCTION__, status);
 
        /* Resubmit urb so we continue receiving IRQ data */
-       if (urb->status != -ESHUTDOWN) {
+       if (status != -ESHUTDOWN) {
                urb->dev = serial->dev;
                err = usb_submit_urb(urb, GFP_ATOMIC);
                if (err)
@@ -517,7 +534,7 @@ static int option_write_room(struct usb_serial_port *port)
 
        for (i=0; i < N_OUT_URB; i++) {
                this_urb = portdata->out_urbs[i];
-               if (this_urb && this_urb->status != -EINPROGRESS)
+               if (this_urb && !test_bit(i, &portdata->out_busy))
                        data_len += OUT_BUFLEN;
        }
 
@@ -536,7 +553,7 @@ static int option_chars_in_buffer(struct usb_serial_port *port)
 
        for (i=0; i < N_OUT_URB; i++) {
                this_urb = portdata->out_urbs[i];
-               if (this_urb && this_urb->status == -EINPROGRESS)
+               if (this_urb && test_bit(i, &portdata->out_busy))
                        data_len += this_urb->transfer_buffer_length;
        }
        dbg("%s: %d", __FUNCTION__, data_len);