Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usbcore: get BOS descriptor set

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@amd.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Andiry Xu and committed by
Greg Kroah-Hartman
3148bf04 50238299

+121
+103
drivers/usb/core/config.c
··· 755 755 dev_err(ddev, "out of memory\n"); 756 756 return result; 757 757 } 758 + 759 + void usb_release_bos_descriptor(struct usb_device *dev) 760 + { 761 + if (dev->bos) { 762 + kfree(dev->bos->desc); 763 + kfree(dev->bos); 764 + dev->bos = NULL; 765 + } 766 + } 767 + 768 + /* Get BOS descriptor set */ 769 + int usb_get_bos_descriptor(struct usb_device *dev) 770 + { 771 + struct device *ddev = &dev->dev; 772 + struct usb_bos_descriptor *bos; 773 + struct usb_dev_cap_header *cap; 774 + unsigned char *buffer; 775 + int length, total_len, num, i; 776 + int ret; 777 + 778 + bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL); 779 + if (!bos) 780 + return -ENOMEM; 781 + 782 + /* Get BOS descriptor */ 783 + ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE); 784 + if (ret < USB_DT_BOS_SIZE) { 785 + dev_err(ddev, "unable to get BOS descriptor\n"); 786 + if (ret >= 0) 787 + ret = -ENOMSG; 788 + kfree(bos); 789 + return ret; 790 + } 791 + 792 + length = bos->bLength; 793 + total_len = le16_to_cpu(bos->wTotalLength); 794 + num = bos->bNumDeviceCaps; 795 + kfree(bos); 796 + if (total_len < length) 797 + return -EINVAL; 798 + 799 + dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL); 800 + if (!dev->bos) 801 + return -ENOMEM; 802 + 803 + /* Now let's get the whole BOS descriptor set */ 804 + buffer = kzalloc(total_len, GFP_KERNEL); 805 + if (!buffer) { 806 + ret = -ENOMEM; 807 + goto err; 808 + } 809 + dev->bos->desc = (struct usb_bos_descriptor *)buffer; 810 + 811 + ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len); 812 + if (ret < total_len) { 813 + dev_err(ddev, "unable to get BOS descriptor set\n"); 814 + if (ret >= 0) 815 + ret = -ENOMSG; 816 + goto err; 817 + } 818 + total_len -= length; 819 + 820 + for (i = 0; i < num; i++) { 821 + buffer += length; 822 + cap = (struct usb_dev_cap_header *)buffer; 823 + length = cap->bLength; 824 + 825 + if (total_len < length) 826 + break; 827 + total_len -= length; 828 + 829 + if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { 830 + dev_warn(ddev, "descriptor type invalid, skip\n"); 831 + continue; 832 + } 833 + 834 + switch (cap->bDevCapabilityType) { 835 + case USB_CAP_TYPE_WIRELESS_USB: 836 + /* Wireless USB cap descriptor is handled by wusb */ 837 + break; 838 + case USB_CAP_TYPE_EXT: 839 + dev->bos->ext_cap = 840 + (struct usb_ext_cap_descriptor *)buffer; 841 + break; 842 + case USB_SS_CAP_TYPE: 843 + dev->bos->ss_cap = 844 + (struct usb_ss_cap_descriptor *)buffer; 845 + break; 846 + case CONTAINER_ID_TYPE: 847 + dev->bos->ss_id = 848 + (struct usb_ss_container_id_descriptor *)buffer; 849 + break; 850 + default: 851 + break; 852 + } 853 + } 854 + 855 + return 0; 856 + 857 + err: 858 + usb_release_bos_descriptor(dev); 859 + return ret; 860 + }
+3
drivers/usb/core/hub.c
··· 3083 3083 goto fail; 3084 3084 } 3085 3085 3086 + if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) 3087 + usb_get_bos_descriptor(udev); 3088 + 3086 3089 retval = 0; 3087 3090 /* notify HCD that we have a device connected and addressed */ 3088 3091 if (hcd->driver->update_device)
+1
drivers/usb/core/usb.c
··· 225 225 hcd = bus_to_hcd(udev->bus); 226 226 227 227 usb_destroy_configuration(udev); 228 + usb_release_bos_descriptor(udev); 228 229 usb_put_hcd(hcd); 229 230 kfree(udev->product); 230 231 kfree(udev->manufacturer);
+2
drivers/usb/core/usb.h
··· 28 28 29 29 extern int usb_get_device_descriptor(struct usb_device *dev, 30 30 unsigned int size); 31 + extern int usb_get_bos_descriptor(struct usb_device *dev); 32 + extern void usb_release_bos_descriptor(struct usb_device *dev); 31 33 extern char *usb_cache_string(struct usb_device *udev, int index); 32 34 extern int usb_set_configuration(struct usb_device *dev, int configuration); 33 35 extern int usb_choose_configuration(struct usb_device *udev);
+12
include/linux/usb.h
··· 292 292 int extralen; 293 293 }; 294 294 295 + /* USB2.0 and USB3.0 device BOS descriptor set */ 296 + struct usb_host_bos { 297 + struct usb_bos_descriptor *desc; 298 + 299 + /* wireless cap descriptor is handled by wusb */ 300 + struct usb_ext_cap_descriptor *ext_cap; 301 + struct usb_ss_cap_descriptor *ss_cap; 302 + struct usb_ss_container_id_descriptor *ss_id; 303 + }; 304 + 295 305 int __usb_get_extra_descriptor(char *buffer, unsigned size, 296 306 unsigned char type, void **ptr); 297 307 #define usb_get_extra_descriptor(ifpoint, type, ptr) \ ··· 391 381 * @ep0: endpoint 0 data (default control pipe) 392 382 * @dev: generic device interface 393 383 * @descriptor: USB device descriptor 384 + * @bos: USB device BOS descriptor set 394 385 * @config: all of the device's configs 395 386 * @actconfig: the active configuration 396 387 * @ep_in: array of IN endpoints ··· 453 442 struct device dev; 454 443 455 444 struct usb_device_descriptor descriptor; 445 + struct usb_host_bos *bos; 456 446 struct usb_host_config *config; 457 447 458 448 struct usb_host_config *actconfig;