USB: Add reset-resume quirk for two Plantronics usb headphones.
[pandora-kernel.git] / drivers / usb / core / config.c
index 26678ca..478d71b 100644 (file)
@@ -114,7 +114,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
                                cfgno, inum, asnum, ep->desc.bEndpointAddress);
                ep->ss_ep_comp.bmAttributes = 16;
        } else if (usb_endpoint_xfer_isoc(&ep->desc) &&
-                       desc->bmAttributes > 2) {
+                  USB_SS_MULT(desc->bmAttributes) > 3) {
                dev_warn(ddev, "Isoc endpoint has Mult of %d in "
                                "config %d interface %d altsetting %d ep %d: "
                                "setting to 3\n", desc->bmAttributes + 1,
@@ -123,10 +123,11 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
        }
 
        if (usb_endpoint_xfer_isoc(&ep->desc))
-               max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
-                       le16_to_cpu(ep->desc.wMaxPacketSize);
+               max_tx = (desc->bMaxBurst + 1) *
+                       (USB_SS_MULT(desc->bmAttributes)) *
+                       usb_endpoint_maxp(&ep->desc);
        else if (usb_endpoint_xfer_int(&ep->desc))
-               max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) *
+               max_tx = usb_endpoint_maxp(&ep->desc) *
                        (desc->bMaxBurst + 1);
        else
                max_tx = 999999;
@@ -201,6 +202,17 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                        if (n == 0)
                                n = 9;  /* 32 ms = 2^(9-1) uframes */
                        j = 16;
+
+                       /*
+                        * Adjust bInterval for quirked devices.
+                        * This quirk fixes bIntervals reported in
+                        * linear microframes.
+                        */
+                       if (to_usb_device(ddev)->quirks &
+                               USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) {
+                               n = clamp(fls(d->bInterval), i, j);
+                               i = j = n;
+                       }
                        break;
                default:                /* USB_SPEED_FULL or _LOW */
                        /* For low-speed, 10 ms is the official minimum.
@@ -241,7 +253,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                    cfgno, inum, asnum, d->bEndpointAddress);
                endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
                endpoint->desc.bInterval = 1;
-               if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
+               if (usb_endpoint_maxp(&endpoint->desc) > 8)
                        endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
        }
 
@@ -254,7 +266,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                        && usb_endpoint_xfer_bulk(d)) {
                unsigned maxp;
 
-               maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
+               maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
                if (maxp != 512)
                        dev_warn(ddev, "config %d interface %d altsetting %d "
                                "bulk endpoint 0x%X has invalid maxpacket %d\n",
@@ -424,7 +436,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
 
        memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
        if (config->desc.bDescriptorType != USB_DT_CONFIG ||
-           config->desc.bLength < USB_DT_CONFIG_SIZE) {
+           config->desc.bLength < USB_DT_CONFIG_SIZE ||
+           config->desc.bLength > size) {
                dev_err(ddev, "invalid descriptor for config index %d: "
                    "type = 0x%X, length = %d\n", cfgidx,
                    config->desc.bDescriptorType, config->desc.bLength);
@@ -721,6 +734,10 @@ int usb_get_configuration(struct usb_device *dev)
                        result = -ENOMEM;
                        goto err;
                }
+
+               if (dev->quirks & USB_QUIRK_DELAY_INIT)
+                       msleep(100);
+
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
                    bigbuffer, length);
                if (result < 0) {
@@ -755,3 +772,106 @@ err2:
                dev_err(ddev, "out of memory\n");
        return result;
 }
+
+void usb_release_bos_descriptor(struct usb_device *dev)
+{
+       if (dev->bos) {
+               kfree(dev->bos->desc);
+               kfree(dev->bos);
+               dev->bos = NULL;
+       }
+}
+
+/* Get BOS descriptor set */
+int usb_get_bos_descriptor(struct usb_device *dev)
+{
+       struct device *ddev = &dev->dev;
+       struct usb_bos_descriptor *bos;
+       struct usb_dev_cap_header *cap;
+       unsigned char *buffer;
+       int length, total_len, num, i;
+       int ret;
+
+       bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
+       if (!bos)
+               return -ENOMEM;
+
+       /* Get BOS descriptor */
+       ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
+       if (ret < USB_DT_BOS_SIZE) {
+               dev_err(ddev, "unable to get BOS descriptor\n");
+               if (ret >= 0)
+                       ret = -ENOMSG;
+               kfree(bos);
+               return ret;
+       }
+
+       length = bos->bLength;
+       total_len = le16_to_cpu(bos->wTotalLength);
+       num = bos->bNumDeviceCaps;
+       kfree(bos);
+       if (total_len < length)
+               return -EINVAL;
+
+       dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL);
+       if (!dev->bos)
+               return -ENOMEM;
+
+       /* Now let's get the whole BOS descriptor set */
+       buffer = kzalloc(total_len, GFP_KERNEL);
+       if (!buffer) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       dev->bos->desc = (struct usb_bos_descriptor *)buffer;
+
+       ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len);
+       if (ret < total_len) {
+               dev_err(ddev, "unable to get BOS descriptor set\n");
+               if (ret >= 0)
+                       ret = -ENOMSG;
+               goto err;
+       }
+       total_len -= length;
+
+       for (i = 0; i < num; i++) {
+               buffer += length;
+               cap = (struct usb_dev_cap_header *)buffer;
+               length = cap->bLength;
+
+               if (total_len < length)
+                       break;
+               total_len -= length;
+
+               if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
+                       dev_warn(ddev, "descriptor type invalid, skip\n");
+                       continue;
+               }
+
+               switch (cap->bDevCapabilityType) {
+               case USB_CAP_TYPE_WIRELESS_USB:
+                       /* Wireless USB cap descriptor is handled by wusb */
+                       break;
+               case USB_CAP_TYPE_EXT:
+                       dev->bos->ext_cap =
+                               (struct usb_ext_cap_descriptor *)buffer;
+                       break;
+               case USB_SS_CAP_TYPE:
+                       dev->bos->ss_cap =
+                               (struct usb_ss_cap_descriptor *)buffer;
+                       break;
+               case CONTAINER_ID_TYPE:
+                       dev->bos->ss_id =
+                               (struct usb_ss_container_id_descriptor *)buffer;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+
+err:
+       usb_release_bos_descriptor(dev);
+       return ret;
+}