* Andiry Xu | 2011-07-14 16:27:06 [+0800]: >This commit gets BOS(Binary Device Object Store) descriptor set for Super >Speed devices and High Speed devices which support BOS descriptor. > >BOS descriptor is used to report additional USB device-level capabilities >that are not reported via the Device descriptor. By getting BOS descriptor >set, driver can check device's device-level capability such as LPM >capability. > >Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx> >--- > drivers/usb/core/config.c | 102 +++++++++++++++++++++++++++++++++++++++++++++ > drivers/usb/core/hub.c | 3 + > drivers/usb/core/usb.c | 1 + > drivers/usb/core/usb.h | 2 + > include/linux/usb.h | 12 +++++ > 5 files changed, 120 insertions(+), 0 deletions(-) > >diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c >index c962608..da7ccbf 100644 >--- a/drivers/usb/core/config.c >+++ b/drivers/usb/core/config.c >@@ -754,3 +754,105 @@ 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, *header; >+ 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 = (int)le16_to_cpu(bos->bLength); the by in blength stands for byte so no need for le16 here. >+ total_len = (int)le16_to_cpu(bos->wTotalLength); this is fine but the cast is ugly. >+ num = (int)le16_to_cpu(bos->bNumDeviceCaps); also a byte >+ kfree(bos); >+ >+ 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; >+ } >+ header = buffer; >+ >+ for (i = 0; i < num; i++) { >+ if (total_len < length) isn't this an error case? The descriptor looks kinda broken or do we try to make the best out of it? >+ break; >+ total_len -= length; >+ >+ header += length; >+ cap = (struct usb_dev_cap_header *)header; >+ length = (int)le16_to_cpu(cap->bLength); byte >+ >+ if (le16_to_cpu(cap->bDescriptorType) >+ != USB_DT_DEVICE_CAPABILITY) { also a byte >+ dev_warn(ddev, "descriptor type invalid, skip\n"); mind dumping the type that has been identified as invalid? >+ continue; >+ } >+ >+ switch (le16_to_cpu(cap->bDevCapabilityType)) { another byte >+ 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 *)header; >+ break; >+ case USB_SS_CAP_TYPE: >+ dev->bos->ss_cap = >+ (struct usb_ss_cap_descriptor *)header; >+ break; >+ case CONTAINER_ID_TYPE: >+ dev->bos->ss_id = >+ (struct usb_ss_container_id_descriptor *)header; >+ break; >+ default: >+ break; >+ } >+ } >+ >+ return 0; >+ >+err: >+ usb_release_bos_descriptor(dev); >+ return ret; >+} >diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c >index 90ae175..4ca6bb2 100644 >--- a/drivers/usb/core/hub.c >+++ b/drivers/usb/core/hub.c >@@ -3041,6 +3041,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, > goto fail; > } > >+ if (udev->wusb == 0 && udev->descriptor.bcdUSB >= 0x0210) >+ retval = usb_get_bos_descriptor(udev); >+ > retval = 0; so retval is overwritten > /* notify HCD that we have a device connected and addressed */ > if (hcd->driver->update_device) Sebastian -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html