From ec8e99e86d1efdfb6f3422a9c8fc0341c4aae01c Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Fri, 23 Sep 2011 14:19:47 -0700 Subject: [PATCH] --- yaml --- r: 265018 b: refs/heads/master c: 3148bf041d169a083aa31bd69bedd5bfb7ffe215 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/usb/core/config.c | 103 ++++++++++++++++++++++++++++++++ trunk/drivers/usb/core/hub.c | 3 + trunk/drivers/usb/core/usb.c | 1 + trunk/drivers/usb/core/usb.h | 2 + trunk/include/linux/usb.h | 12 ++++ 6 files changed, 122 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 746f8f72a1ce..9d794b9c5dd6 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 5023829969f56b78a16da94f34c605bbbb344018 +refs/heads/master: 3148bf041d169a083aa31bd69bedd5bfb7ffe215 diff --git a/trunk/drivers/usb/core/config.c b/trunk/drivers/usb/core/config.c index 9d5e07af55be..f4bdd0ce8d56 100644 --- a/trunk/drivers/usb/core/config.c +++ b/trunk/drivers/usb/core/config.c @@ -755,3 +755,106 @@ int usb_get_configuration(struct usb_device *dev) 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; +} diff --git a/trunk/drivers/usb/core/hub.c b/trunk/drivers/usb/core/hub.c index 1c155123c32f..7a2514322bfd 100644 --- a/trunk/drivers/usb/core/hub.c +++ b/trunk/drivers/usb/core/hub.c @@ -3083,6 +3083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } + if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) + usb_get_bos_descriptor(udev); + retval = 0; /* notify HCD that we have a device connected and addressed */ if (hcd->driver->update_device) diff --git a/trunk/drivers/usb/core/usb.c b/trunk/drivers/usb/core/usb.c index 8706fc97e60f..73cd90012ec5 100644 --- a/trunk/drivers/usb/core/usb.c +++ b/trunk/drivers/usb/core/usb.c @@ -225,6 +225,7 @@ static void usb_release_dev(struct device *dev) hcd = bus_to_hcd(udev->bus); usb_destroy_configuration(udev); + usb_release_bos_descriptor(udev); usb_put_hcd(hcd); kfree(udev->product); kfree(udev->manufacturer); diff --git a/trunk/drivers/usb/core/usb.h b/trunk/drivers/usb/core/usb.h index d44d4b7bbf17..0d023cd2c149 100644 --- a/trunk/drivers/usb/core/usb.h +++ b/trunk/drivers/usb/core/usb.h @@ -28,6 +28,8 @@ extern int usb_remove_device(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); +extern int usb_get_bos_descriptor(struct usb_device *dev); +extern void usb_release_bos_descriptor(struct usb_device *dev); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_choose_configuration(struct usb_device *udev); diff --git a/trunk/include/linux/usb.h b/trunk/include/linux/usb.h index c19f9100c307..90ab9dc1f080 100644 --- a/trunk/include/linux/usb.h +++ b/trunk/include/linux/usb.h @@ -292,6 +292,16 @@ struct usb_host_config { int extralen; }; +/* USB2.0 and USB3.0 device BOS descriptor set */ +struct usb_host_bos { + struct usb_bos_descriptor *desc; + + /* wireless cap descriptor is handled by wusb */ + struct usb_ext_cap_descriptor *ext_cap; + struct usb_ss_cap_descriptor *ss_cap; + struct usb_ss_container_id_descriptor *ss_id; +}; + int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr); #define usb_get_extra_descriptor(ifpoint, type, ptr) \ @@ -381,6 +391,7 @@ struct usb_tt; * @ep0: endpoint 0 data (default control pipe) * @dev: generic device interface * @descriptor: USB device descriptor + * @bos: USB device BOS descriptor set * @config: all of the device's configs * @actconfig: the active configuration * @ep_in: array of IN endpoints @@ -442,6 +453,7 @@ struct usb_device { struct device dev; struct usb_device_descriptor descriptor; + struct usb_host_bos *bos; struct usb_host_config *config; struct usb_host_config *actconfig;