Hi Andiry, Are you getting the BOS descriptor in order to implement link power management? That was next on my todo list, and I want to make sure I'm not duplicating your efforts. :) Sarah Sharp On Wed, Jul 13, 2011 at 03:43:40PM +0800, Andiry Xu wrote: > 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/hub.c | 3 + > drivers/usb/core/message.c | 143 ++++++++++++++++++++++++++++++++++++++++++++ > drivers/usb/core/usb.c | 1 + > drivers/usb/core/usb.h | 2 + > include/linux/usb.h | 13 ++++ > 5 files changed, 162 insertions(+), 0 deletions(-) > > 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; > /* notify HCD that we have a device connected and addressed */ > if (hcd->driver->update_device) > diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c > index 5701e85..cc54e57 100644 > --- a/drivers/usb/core/message.c > +++ b/drivers/usb/core/message.c > @@ -916,6 +916,149 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) > return ret; > } > > +void usb_release_bos_descriptor(struct usb_device *dev) > +{ > + if (dev->bos) { > + kfree(dev->bos->ext_cap_desc); > + kfree(dev->bos->ss_cap_desc); > + kfree(dev->bos->ss_id_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"); > + goto err1; > + } > + > + dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL); > + if (!dev->bos) { > + ret = -ENOMEM; > + goto err1; > + } > + memcpy(&dev->bos->desc, bos, USB_DT_BOS_SIZE); > + > + length = (int)le16_to_cpu(bos->bLength); > + total_len = (int)le16_to_cpu(bos->wTotalLength); > + num = (int)le16_to_cpu(bos->bNumDeviceCaps); > + > + /* Now let's get the whole BOS descriptor set */ > + buffer = kzalloc(total_len, GFP_KERNEL); > + if (!buffer) { > + ret = -ENOMEM; > + goto err2; > + } > + > + 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"); > + goto err3; > + } > + > + header = buffer; > + > + for (i = 0; i < num; i++) { > + if (total_len < length) > + break; > + total_len -= length; > + > + header += length; > + cap = (struct usb_dev_cap_header *)header; > + length = (int)le16_to_cpu(cap->bLength); > + > + 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: > + if (dev->bos->ext_cap_desc) > + break; > + dev->bos->ext_cap_desc = > + kzalloc(sizeof(struct usb_ext_cap_descriptor), > + GFP_KERNEL); > + if (!dev->bos->ext_cap_desc) { > + ret = -ENOMEM; > + goto err4; > + } > + memcpy(dev->bos->ext_cap_desc, > + (struct usb_ext_cap_descriptor *)header, > + USB_DT_USB_EXT_CAP_SIZE); > + break; > + case USB_SS_CAP_TYPE: > + if (dev->bos->ss_cap_desc) > + break; > + dev->bos->ss_cap_desc = > + kzalloc(sizeof(struct usb_ss_cap_descriptor), > + GFP_KERNEL); > + if (!dev->bos->ss_cap_desc) { > + ret = -ENOMEM; > + goto err4; > + } > + memcpy(dev->bos->ss_cap_desc, > + (struct usb_ss_cap_descriptor *)header, > + USB_DT_USB_SS_CAP_SIZE); > + break; > + case CONTAINER_ID_TYPE: > + if (dev->bos->ss_id_desc) > + break; > + dev->bos->ss_id_desc = > + kzalloc(sizeof(struct usb_ss_container_id_descriptor), > + GFP_KERNEL); > + if (!dev->bos->ss_id_desc) { > + ret = -ENOMEM; > + goto err4; > + } > + memcpy(dev->bos->ss_id_desc, > + (struct usb_ss_container_id_descriptor *)header, > + USB_DT_USB_SS_CONTN_ID_SIZE); > + break; > + default: > + break; > + } > + } > + > + kfree(bos); > + kfree(buffer); > + > + return 0; > + > +err4: > + kfree(dev->bos->ext_cap_desc); > + kfree(dev->bos->ss_cap_desc); > + kfree(dev->bos->ss_id_desc); > +err3: > + kfree(buffer); > +err2: > + kfree(dev->bos); > + dev->bos = NULL; > +err1: > + kfree(bos); > + > + return ret; > +} > + > /** > * usb_get_status - issues a GET_STATUS call > * @dev: the device whose status is being checked > diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c > index 8706fc9..73cd900 100644 > --- a/drivers/usb/core/usb.c > +++ b/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/drivers/usb/core/usb.h b/drivers/usb/core/usb.h > index d44d4b7..0d023cd 100644 > --- a/drivers/usb/core/usb.h > +++ b/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/include/linux/usb.h b/include/linux/usb.h > index 73c7df4..5b87377 100644 > --- a/include/linux/usb.h > +++ b/include/linux/usb.h > @@ -292,6 +292,17 @@ 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_desc; > + struct usb_ss_cap_descriptor *ss_cap_desc; > + struct usb_ss_container_id_descriptor *ss_id_desc; > + > +}; > + > int __usb_get_extra_descriptor(char *buffer, unsigned size, > unsigned char type, void **ptr); > #define usb_get_extra_descriptor(ifpoint, type, ptr) \ > @@ -381,6 +392,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 +454,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; > -- > 1.7.1 > > > -- > 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 -- 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