Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Oct 2009 22:05:33 +0000 (15:05 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Oct 2009 22:05:33 +0000 (15:05 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6:
  USB: gadget: Fix EEM driver comments and VID/PID
  usb-storage: Workaround devices with bogus sense size
  USB: ehci: Fix IST boundary checking interval math.
  USB: option: Support for AIRPLUS MCD650 Datacard
  USB: whci-hcd: always do an update after processing a halted qTD
  USB: whci-hcd: handle early deletion of endpoints
  USB: wusb: don't use the stack to read security descriptor
  USB: rename Documentation/ABI/.../sysfs-class-usb_host

Documentation/ABI/testing/sysfs-class-uwb_rc-wusbhc [moved from Documentation/ABI/testing/sysfs-class-usb_host with 88% similarity]
drivers/usb/gadget/ether.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/whci/asl.c
drivers/usb/host/whci/pzl.c
drivers/usb/serial/option.c
drivers/usb/storage/transport.c
drivers/usb/wusbcore/security.c

@@ -1,4 +1,4 @@
-What:           /sys/class/usb_host/usb_hostN/wusb_chid
+What:           /sys/class/uwb_rc/uwbN/wusbhc/wusb_chid
 Date:           July 2008
 KernelVersion:  2.6.27
 Contact:        David Vrabel <david.vrabel@csr.com>
@@ -9,7 +9,7 @@ Description:
 
                 Set an all zero CHID to stop the host controller.
 
-What:           /sys/class/usb_host/usb_hostN/wusb_trust_timeout
+What:           /sys/class/uwb_rc/uwbN/wusbhc/wusb_trust_timeout
 Date:           July 2008
 KernelVersion:  2.6.27
 Contact:        David Vrabel <david.vrabel@csr.com>
index f37de28..167cb2a 100644 (file)
  * simpler, Microsoft pushes their own approach: RNDIS.  The published
  * RNDIS specs are ambiguous and appear to be incomplete, and are also
  * needlessly complex.  They borrow more from CDC ACM than CDC ECM.
- *
- * While CDC ECM, CDC Subset, and RNDIS are designed to extend the ethernet
- * interface to the target, CDC EEM was designed to use ethernet over the USB
- * link between the host and target.  CDC EEM is implemented as an alternative
- * to those other protocols when that communication model is more appropriate
  */
 
 #define DRIVER_DESC            "Ethernet Gadget"
@@ -157,8 +152,8 @@ static inline bool has_rndis(void)
 #define RNDIS_PRODUCT_NUM      0xa4a2  /* Ethernet/RNDIS Gadget */
 
 /* For EEM gadgets */
-#define EEM_VENDOR_NUM 0x0525  /* INVALID - NEEDS TO BE ALLOCATED */
-#define EEM_PRODUCT_NUM        0xa4a1  /* INVALID - NEEDS TO BE ALLOCATED */
+#define EEM_VENDOR_NUM         0x1d6b  /* Linux Foundation */
+#define EEM_PRODUCT_NUM                0x0102  /* EEM Gadget */
 
 /*-------------------------------------------------------------------------*/
 
index 3efa59b..b25cdea 100644 (file)
@@ -1400,6 +1400,10 @@ iso_stream_schedule (
                goto fail;
        }
 
+       period = urb->interval;
+       if (!stream->highspeed)
+               period <<= 3;
+
        now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 
        /* when's the last uframe this urb could start? */
@@ -1417,8 +1421,8 @@ iso_stream_schedule (
 
                /* Fell behind (by up to twice the slop amount)? */
                if (start >= max - 2 * 8 * SCHEDULE_SLOP)
-                       start += stream->interval * DIV_ROUND_UP(
-                                       max - start, stream->interval) - mod;
+                       start += period * DIV_ROUND_UP(
+                                       max - start, period) - mod;
 
                /* Tried to schedule too far into the future? */
                if (unlikely((start + sched->span) >= max)) {
@@ -1441,10 +1445,6 @@ iso_stream_schedule (
 
        /* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
 
-       period = urb->interval;
-       if (!stream->highspeed)
-               period <<= 3;
-
        /* find a uframe slot with enough bandwidth */
        for (; start < (stream->next_uframe + period); start++) {
                int             enough_space;
index c632437..562eba1 100644 (file)
@@ -115,6 +115,10 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
                if (status & QTD_STS_HALTED) {
                        /* Ug, an error. */
                        process_halted_qtd(whc, qset, td);
+                       /* A halted qTD always triggers an update
+                          because the qset was either removed or
+                          reactivated. */
+                       update |= WHC_UPDATE_UPDATED;
                        goto done;
                }
 
@@ -305,6 +309,7 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
        struct whc_urb *wurb = urb->hcpriv;
        struct whc_qset *qset = wurb->qset;
        struct whc_std *std, *t;
+       bool has_qtd = false;
        int ret;
        unsigned long flags;
 
@@ -315,17 +320,21 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
                goto out;
 
        list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb == urb)
+               if (std->urb == urb) {
+                       if (std->qtd)
+                               has_qtd = true;
                        qset_free_std(whc, std);
-               else
+               else
                        std->qtd = NULL; /* so this std is re-added when the qset is */
        }
 
-       asl_qset_remove(whc, qset);
-       wurb->status = status;
-       wurb->is_async = true;
-       queue_work(whc->workqueue, &wurb->dequeue_work);
-
+       if (has_qtd) {
+               asl_qset_remove(whc, qset);
+               wurb->status = status;
+               wurb->is_async = true;
+               queue_work(whc->workqueue, &wurb->dequeue_work);
+       } else
+               qset_remove_urb(whc, qset, urb, status);
 out:
        spin_unlock_irqrestore(&whc->lock, flags);
 
index a9e05ba..0db3fb2 100644 (file)
@@ -121,6 +121,10 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
                if (status & QTD_STS_HALTED) {
                        /* Ug, an error. */
                        process_halted_qtd(whc, qset, td);
+                       /* A halted qTD always triggers an update
+                          because the qset was either removed or
+                          reactivated. */
+                       update |= WHC_UPDATE_UPDATED;
                        goto done;
                }
 
@@ -333,6 +337,7 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
        struct whc_urb *wurb = urb->hcpriv;
        struct whc_qset *qset = wurb->qset;
        struct whc_std *std, *t;
+       bool has_qtd = false;
        int ret;
        unsigned long flags;
 
@@ -343,17 +348,22 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
                goto out;
 
        list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb == urb)
+               if (std->urb == urb) {
+                       if (std->qtd)
+                               has_qtd = true;
                        qset_free_std(whc, std);
-               else
+               else
                        std->qtd = NULL; /* so this std is re-added when the qset is */
        }
 
-       pzl_qset_remove(whc, qset);
-       wurb->status = status;
-       wurb->is_async = false;
-       queue_work(whc->workqueue, &wurb->dequeue_work);
-
+       if (has_qtd) {
+               pzl_qset_remove(whc, qset);
+               update_pzl_hw_view(whc);
+               wurb->status = status;
+               wurb->is_async = false;
+               queue_work(whc->workqueue, &wurb->dequeue_work);
+       } else
+               qset_remove_urb(whc, qset, urb, status);
 out:
        spin_unlock_irqrestore(&whc->lock, flags);
 
index 43c2270..65d96b2 100644 (file)
@@ -328,6 +328,9 @@ static int  option_resume(struct usb_serial *serial);
 #define ALCATEL_VENDOR_ID                      0x1bbb
 #define ALCATEL_PRODUCT_X060S                  0x0000
 
+/* Airplus products */
+#define AIRPLUS_VENDOR_ID                      0x1011
+#define AIRPLUS_PRODUCT_MCD650                 0x3198
 
 static struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -589,6 +592,7 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
        { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
+       { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index 3a4fb02..589f6b4 100644 (file)
@@ -696,7 +696,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
                /* device supports and needs bigger sense buffer */
                if (us->fflags & US_FL_SANE_SENSE)
                        sense_size = ~0;
-
+Retry_Sense:
                US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
 
                scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size);
@@ -720,6 +720,21 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
                        srb->result = DID_ABORT << 16;
                        goto Handle_Errors;
                }
+
+               /* Some devices claim to support larger sense but fail when
+                * trying to request it. When a transport failure happens
+                * using US_FS_SANE_SENSE, we always retry with a standard
+                * (small) sense request. This fixes some USB GSM modems
+                */
+               if (temp_result == USB_STOR_TRANSPORT_FAILED &&
+                   (us->fflags & US_FL_SANE_SENSE) &&
+                   sense_size != US_SENSE_SIZE) {
+                       US_DEBUGP("-- auto-sense failure, retry small sense\n");
+                       sense_size = US_SENSE_SIZE;
+                       goto Retry_Sense;
+               }
+
+               /* Other failures */
                if (temp_result != USB_STOR_TRANSPORT_GOOD) {
                        US_DEBUGP("-- auto-sense failure\n");
 
index b2f149f..4516c36 100644 (file)
@@ -200,35 +200,40 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
 {
        int result, bytes, secd_size;
        struct device *dev = &usb_dev->dev;
-       struct usb_security_descriptor secd;
+       struct usb_security_descriptor *secd;
        const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
-       void *secd_buf;
        const void *itr, *top;
        char buf[64];
 
+       secd = kmalloc(sizeof(struct usb_security_descriptor), GFP_KERNEL);
+       if (secd == NULL) {
+               result = -ENOMEM;
+               goto out;
+       }
+
        result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
-                                   0, &secd, sizeof(secd));
+                                   0, secd, sizeof(struct usb_security_descriptor));
        if (result < sizeof(secd)) {
                dev_err(dev, "Can't read security descriptor or "
                        "not enough data: %d\n", result);
-               goto error_secd;
+               goto out;
        }
-       secd_size = le16_to_cpu(secd.wTotalLength);
-       secd_buf = kmalloc(secd_size, GFP_KERNEL);
-       if (secd_buf == NULL) {
+       secd_size = le16_to_cpu(secd->wTotalLength);
+       secd = krealloc(secd, secd_size, GFP_KERNEL);
+       if (secd == NULL) {
                dev_err(dev, "Can't allocate space for security descriptors\n");
-               goto error_secd_alloc;
+               goto out;
        }
        result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
-                                   0, secd_buf, secd_size);
+                                   0, secd, secd_size);
        if (result < secd_size) {
                dev_err(dev, "Can't read security descriptor or "
                        "not enough data: %d\n", result);
-               goto error_secd_all;
+               goto out;
        }
        bytes = 0;
-       itr = secd_buf + sizeof(secd);
-       top = secd_buf + result;
+       itr = &secd[1];
+       top = (void *)secd + result;
        while (itr < top) {
                etd = itr;
                if (top - itr < sizeof(*etd)) {
@@ -259,24 +264,16 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
                dev_err(dev, "WUSB device doesn't support CCM1 encryption, "
                        "can't use!\n");
                result = -EINVAL;
-               goto error_no_ccm1;
+               goto out;
        }
        wusb_dev->ccm1_etd = *ccm1_etd;
        dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n",
                buf, wusb_et_name(ccm1_etd->bEncryptionType),
                ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex);
        result = 0;
-       kfree(secd_buf);
 out:
+       kfree(secd);
        return result;
-
-
-error_no_ccm1:
-error_secd_all:
-       kfree(secd_buf);
-error_secd_alloc:
-error_secd:
-       goto out;
 }
 
 void wusb_dev_sec_rm(struct wusb_dev *wusb_dev)