Merge branches 'for-linus' and 'for-linus-3.2' of git://git.kernel.org/pub/scm/linux...
[pandora-kernel.git] / drivers / usb / core / config.c
index 26678ca..f4bdd0c 100644 (file)
@@ -124,9 +124,9 @@ 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);
+                       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;
@@ -241,7 +241,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 +254,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",
@@ -755,3 +755,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;
+}