162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Released under the GPLv2 only. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/usb.h> 762306a36Sopenharmony_ci#include <linux/usb/ch9.h> 862306a36Sopenharmony_ci#include <linux/usb/hcd.h> 962306a36Sopenharmony_ci#include <linux/usb/quirks.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <asm/byteorder.h> 1462306a36Sopenharmony_ci#include "usb.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define USB_MAXALTSETTING 128 /* Hard limit */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define USB_MAXCONFIG 8 /* Arbitrary limit */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic inline const char *plural(int n) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci return (n == 1 ? "" : "s"); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int find_next_descriptor(unsigned char *buffer, int size, 2862306a36Sopenharmony_ci int dt1, int dt2, int *num_skipped) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct usb_descriptor_header *h; 3162306a36Sopenharmony_ci int n = 0; 3262306a36Sopenharmony_ci unsigned char *buffer0 = buffer; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci /* Find the next descriptor of type dt1 or dt2 */ 3562306a36Sopenharmony_ci while (size > 0) { 3662306a36Sopenharmony_ci h = (struct usb_descriptor_header *) buffer; 3762306a36Sopenharmony_ci if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2) 3862306a36Sopenharmony_ci break; 3962306a36Sopenharmony_ci buffer += h->bLength; 4062306a36Sopenharmony_ci size -= h->bLength; 4162306a36Sopenharmony_ci ++n; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* Store the number of descriptors skipped and return the 4562306a36Sopenharmony_ci * number of bytes skipped */ 4662306a36Sopenharmony_ci if (num_skipped) 4762306a36Sopenharmony_ci *num_skipped = n; 4862306a36Sopenharmony_ci return buffer - buffer0; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev, 5262306a36Sopenharmony_ci int cfgno, int inum, int asnum, struct usb_host_endpoint *ep, 5362306a36Sopenharmony_ci unsigned char *buffer, int size) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct usb_ssp_isoc_ep_comp_descriptor *desc; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * The SuperSpeedPlus Isoc endpoint companion descriptor immediately 5962306a36Sopenharmony_ci * follows the SuperSpeed Endpoint Companion descriptor 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer; 6262306a36Sopenharmony_ci if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP || 6362306a36Sopenharmony_ci size < USB_DT_SSP_ISOC_EP_COMP_SIZE) { 6462306a36Sopenharmony_ci dev_notice(ddev, "Invalid SuperSpeedPlus isoc endpoint companion" 6562306a36Sopenharmony_ci "for config %d interface %d altsetting %d ep %d.\n", 6662306a36Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 6762306a36Sopenharmony_ci return; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci memcpy(&ep->ssp_isoc_ep_comp, desc, USB_DT_SSP_ISOC_EP_COMP_SIZE); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, 7362306a36Sopenharmony_ci int inum, int asnum, struct usb_host_endpoint *ep, 7462306a36Sopenharmony_ci unsigned char *buffer, int size) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct usb_ss_ep_comp_descriptor *desc; 7762306a36Sopenharmony_ci int max_tx; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* The SuperSpeed endpoint companion descriptor is supposed to 8062306a36Sopenharmony_ci * be the first thing immediately following the endpoint descriptor. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci desc = (struct usb_ss_ep_comp_descriptor *) buffer; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP || 8562306a36Sopenharmony_ci size < USB_DT_SS_EP_COMP_SIZE) { 8662306a36Sopenharmony_ci dev_notice(ddev, "No SuperSpeed endpoint companion for config %d " 8762306a36Sopenharmony_ci " interface %d altsetting %d ep %d: " 8862306a36Sopenharmony_ci "using minimum values\n", 8962306a36Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Fill in some default values. 9262306a36Sopenharmony_ci * Leave bmAttributes as zero, which will mean no streams for 9362306a36Sopenharmony_ci * bulk, and isoc won't support multiple bursts of packets. 9462306a36Sopenharmony_ci * With bursts of only one packet, and a Mult of 1, the max 9562306a36Sopenharmony_ci * amount of data moved per endpoint service interval is one 9662306a36Sopenharmony_ci * packet. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE; 9962306a36Sopenharmony_ci ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; 10062306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(&ep->desc) || 10162306a36Sopenharmony_ci usb_endpoint_xfer_int(&ep->desc)) 10262306a36Sopenharmony_ci ep->ss_ep_comp.wBytesPerInterval = 10362306a36Sopenharmony_ci ep->desc.wMaxPacketSize; 10462306a36Sopenharmony_ci return; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci buffer += desc->bLength; 10762306a36Sopenharmony_ci size -= desc->bLength; 10862306a36Sopenharmony_ci memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Check the various values */ 11162306a36Sopenharmony_ci if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) { 11262306a36Sopenharmony_ci dev_notice(ddev, "Control endpoint with bMaxBurst = %d in " 11362306a36Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 11462306a36Sopenharmony_ci "setting to zero\n", desc->bMaxBurst, 11562306a36Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 11662306a36Sopenharmony_ci ep->ss_ep_comp.bMaxBurst = 0; 11762306a36Sopenharmony_ci } else if (desc->bMaxBurst > 15) { 11862306a36Sopenharmony_ci dev_notice(ddev, "Endpoint with bMaxBurst = %d in " 11962306a36Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 12062306a36Sopenharmony_ci "setting to 15\n", desc->bMaxBurst, 12162306a36Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 12262306a36Sopenharmony_ci ep->ss_ep_comp.bMaxBurst = 15; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if ((usb_endpoint_xfer_control(&ep->desc) || 12662306a36Sopenharmony_ci usb_endpoint_xfer_int(&ep->desc)) && 12762306a36Sopenharmony_ci desc->bmAttributes != 0) { 12862306a36Sopenharmony_ci dev_notice(ddev, "%s endpoint with bmAttributes = %d in " 12962306a36Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 13062306a36Sopenharmony_ci "setting to zero\n", 13162306a36Sopenharmony_ci usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk", 13262306a36Sopenharmony_ci desc->bmAttributes, 13362306a36Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 13462306a36Sopenharmony_ci ep->ss_ep_comp.bmAttributes = 0; 13562306a36Sopenharmony_ci } else if (usb_endpoint_xfer_bulk(&ep->desc) && 13662306a36Sopenharmony_ci desc->bmAttributes > 16) { 13762306a36Sopenharmony_ci dev_notice(ddev, "Bulk endpoint with more than 65536 streams in " 13862306a36Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 13962306a36Sopenharmony_ci "setting to max\n", 14062306a36Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 14162306a36Sopenharmony_ci ep->ss_ep_comp.bmAttributes = 16; 14262306a36Sopenharmony_ci } else if (usb_endpoint_xfer_isoc(&ep->desc) && 14362306a36Sopenharmony_ci !USB_SS_SSP_ISOC_COMP(desc->bmAttributes) && 14462306a36Sopenharmony_ci USB_SS_MULT(desc->bmAttributes) > 3) { 14562306a36Sopenharmony_ci dev_notice(ddev, "Isoc endpoint has Mult of %d in " 14662306a36Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 14762306a36Sopenharmony_ci "setting to 3\n", 14862306a36Sopenharmony_ci USB_SS_MULT(desc->bmAttributes), 14962306a36Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 15062306a36Sopenharmony_ci ep->ss_ep_comp.bmAttributes = 2; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(&ep->desc)) 15462306a36Sopenharmony_ci max_tx = (desc->bMaxBurst + 1) * 15562306a36Sopenharmony_ci (USB_SS_MULT(desc->bmAttributes)) * 15662306a36Sopenharmony_ci usb_endpoint_maxp(&ep->desc); 15762306a36Sopenharmony_ci else if (usb_endpoint_xfer_int(&ep->desc)) 15862306a36Sopenharmony_ci max_tx = usb_endpoint_maxp(&ep->desc) * 15962306a36Sopenharmony_ci (desc->bMaxBurst + 1); 16062306a36Sopenharmony_ci else 16162306a36Sopenharmony_ci max_tx = 999999; 16262306a36Sopenharmony_ci if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) { 16362306a36Sopenharmony_ci dev_notice(ddev, "%s endpoint with wBytesPerInterval of %d in " 16462306a36Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 16562306a36Sopenharmony_ci "setting to %d\n", 16662306a36Sopenharmony_ci usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int", 16762306a36Sopenharmony_ci le16_to_cpu(desc->wBytesPerInterval), 16862306a36Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress, 16962306a36Sopenharmony_ci max_tx); 17062306a36Sopenharmony_ci ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci /* Parse a possible SuperSpeedPlus isoc ep companion descriptor */ 17362306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(&ep->desc) && 17462306a36Sopenharmony_ci USB_SS_SSP_ISOC_COMP(desc->bmAttributes)) 17562306a36Sopenharmony_ci usb_parse_ssp_isoc_endpoint_companion(ddev, cfgno, inum, asnum, 17662306a36Sopenharmony_ci ep, buffer, size); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic const unsigned short low_speed_maxpacket_maxes[4] = { 18062306a36Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = 8, 18162306a36Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = 0, 18262306a36Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = 0, 18362306a36Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = 8, 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_cistatic const unsigned short full_speed_maxpacket_maxes[4] = { 18662306a36Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = 64, 18762306a36Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = 1023, 18862306a36Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = 64, 18962306a36Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = 64, 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_cistatic const unsigned short high_speed_maxpacket_maxes[4] = { 19262306a36Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = 64, 19362306a36Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = 1024, 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Bulk should be 512, but some devices use 1024: we will warn below */ 19662306a36Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = 1024, 19762306a36Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = 1024, 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_cistatic const unsigned short super_speed_maxpacket_maxes[4] = { 20062306a36Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = 512, 20162306a36Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = 1024, 20262306a36Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = 1024, 20362306a36Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = 1024, 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1, 20762306a36Sopenharmony_ci struct usb_endpoint_descriptor *e2) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci if (e1->bEndpointAddress == e2->bEndpointAddress) 21062306a36Sopenharmony_ci return true; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) { 21362306a36Sopenharmony_ci if (usb_endpoint_num(e1) == usb_endpoint_num(e2)) 21462306a36Sopenharmony_ci return true; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return false; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* 22162306a36Sopenharmony_ci * Check for duplicate endpoint addresses in other interfaces and in the 22262306a36Sopenharmony_ci * altsetting currently being parsed. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic bool config_endpoint_is_duplicate(struct usb_host_config *config, 22562306a36Sopenharmony_ci int inum, int asnum, struct usb_endpoint_descriptor *d) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct usb_endpoint_descriptor *epd; 22862306a36Sopenharmony_ci struct usb_interface_cache *intfc; 22962306a36Sopenharmony_ci struct usb_host_interface *alt; 23062306a36Sopenharmony_ci int i, j, k; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci for (i = 0; i < config->desc.bNumInterfaces; ++i) { 23362306a36Sopenharmony_ci intfc = config->intf_cache[i]; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci for (j = 0; j < intfc->num_altsetting; ++j) { 23662306a36Sopenharmony_ci alt = &intfc->altsetting[j]; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (alt->desc.bInterfaceNumber == inum && 23962306a36Sopenharmony_ci alt->desc.bAlternateSetting != asnum) 24062306a36Sopenharmony_ci continue; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci for (k = 0; k < alt->desc.bNumEndpoints; ++k) { 24362306a36Sopenharmony_ci epd = &alt->endpoint[k].desc; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (endpoint_is_duplicate(epd, d)) 24662306a36Sopenharmony_ci return true; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return false; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int usb_parse_endpoint(struct device *ddev, int cfgno, 25562306a36Sopenharmony_ci struct usb_host_config *config, int inum, int asnum, 25662306a36Sopenharmony_ci struct usb_host_interface *ifp, int num_ep, 25762306a36Sopenharmony_ci unsigned char *buffer, int size) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct usb_device *udev = to_usb_device(ddev); 26062306a36Sopenharmony_ci unsigned char *buffer0 = buffer; 26162306a36Sopenharmony_ci struct usb_endpoint_descriptor *d; 26262306a36Sopenharmony_ci struct usb_host_endpoint *endpoint; 26362306a36Sopenharmony_ci int n, i, j, retval; 26462306a36Sopenharmony_ci unsigned int maxp; 26562306a36Sopenharmony_ci const unsigned short *maxpacket_maxes; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci d = (struct usb_endpoint_descriptor *) buffer; 26862306a36Sopenharmony_ci buffer += d->bLength; 26962306a36Sopenharmony_ci size -= d->bLength; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE) 27262306a36Sopenharmony_ci n = USB_DT_ENDPOINT_AUDIO_SIZE; 27362306a36Sopenharmony_ci else if (d->bLength >= USB_DT_ENDPOINT_SIZE) 27462306a36Sopenharmony_ci n = USB_DT_ENDPOINT_SIZE; 27562306a36Sopenharmony_ci else { 27662306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has an " 27762306a36Sopenharmony_ci "invalid endpoint descriptor of length %d, skipping\n", 27862306a36Sopenharmony_ci cfgno, inum, asnum, d->bLength); 27962306a36Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK; 28362306a36Sopenharmony_ci if (i >= 16 || i == 0) { 28462306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has an " 28562306a36Sopenharmony_ci "invalid endpoint with address 0x%X, skipping\n", 28662306a36Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress); 28762306a36Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Only store as many endpoints as we have room for */ 29162306a36Sopenharmony_ci if (ifp->desc.bNumEndpoints >= num_ep) 29262306a36Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Check for duplicate endpoint addresses */ 29562306a36Sopenharmony_ci if (config_endpoint_is_duplicate(config, inum, asnum, d)) { 29662306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", 29762306a36Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress); 29862306a36Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Ignore some endpoints */ 30262306a36Sopenharmony_ci if (udev->quirks & USB_QUIRK_ENDPOINT_IGNORE) { 30362306a36Sopenharmony_ci if (usb_endpoint_is_ignored(udev, ifp, d)) { 30462306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping\n", 30562306a36Sopenharmony_ci cfgno, inum, asnum, 30662306a36Sopenharmony_ci d->bEndpointAddress); 30762306a36Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; 31262306a36Sopenharmony_ci ++ifp->desc.bNumEndpoints; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci memcpy(&endpoint->desc, d, n); 31562306a36Sopenharmony_ci INIT_LIST_HEAD(&endpoint->urb_list); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * Fix up bInterval values outside the legal range. 31962306a36Sopenharmony_ci * Use 10 or 8 ms if no proper value can be guessed. 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_ci i = 0; /* i = min, j = max, n = default */ 32262306a36Sopenharmony_ci j = 255; 32362306a36Sopenharmony_ci if (usb_endpoint_xfer_int(d)) { 32462306a36Sopenharmony_ci i = 1; 32562306a36Sopenharmony_ci switch (udev->speed) { 32662306a36Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 32762306a36Sopenharmony_ci case USB_SPEED_SUPER: 32862306a36Sopenharmony_ci case USB_SPEED_HIGH: 32962306a36Sopenharmony_ci /* 33062306a36Sopenharmony_ci * Many device manufacturers are using full-speed 33162306a36Sopenharmony_ci * bInterval values in high-speed interrupt endpoint 33262306a36Sopenharmony_ci * descriptors. Try to fix those and fall back to an 33362306a36Sopenharmony_ci * 8-ms default value otherwise. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci n = fls(d->bInterval*8); 33662306a36Sopenharmony_ci if (n == 0) 33762306a36Sopenharmony_ci n = 7; /* 8 ms = 2^(7-1) uframes */ 33862306a36Sopenharmony_ci j = 16; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* 34162306a36Sopenharmony_ci * Adjust bInterval for quirked devices. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci /* 34462306a36Sopenharmony_ci * This quirk fixes bIntervals reported in ms. 34562306a36Sopenharmony_ci */ 34662306a36Sopenharmony_ci if (udev->quirks & USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) { 34762306a36Sopenharmony_ci n = clamp(fls(d->bInterval) + 3, i, j); 34862306a36Sopenharmony_ci i = j = n; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci /* 35162306a36Sopenharmony_ci * This quirk fixes bIntervals reported in 35262306a36Sopenharmony_ci * linear microframes. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci if (udev->quirks & USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) { 35562306a36Sopenharmony_ci n = clamp(fls(d->bInterval), i, j); 35662306a36Sopenharmony_ci i = j = n; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci default: /* USB_SPEED_FULL or _LOW */ 36062306a36Sopenharmony_ci /* 36162306a36Sopenharmony_ci * For low-speed, 10 ms is the official minimum. 36262306a36Sopenharmony_ci * But some "overclocked" devices might want faster 36362306a36Sopenharmony_ci * polling so we'll allow it. 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ci n = 10; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } else if (usb_endpoint_xfer_isoc(d)) { 36962306a36Sopenharmony_ci i = 1; 37062306a36Sopenharmony_ci j = 16; 37162306a36Sopenharmony_ci switch (udev->speed) { 37262306a36Sopenharmony_ci case USB_SPEED_HIGH: 37362306a36Sopenharmony_ci n = 7; /* 8 ms = 2^(7-1) uframes */ 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci default: /* USB_SPEED_FULL */ 37662306a36Sopenharmony_ci n = 4; /* 8 ms = 2^(4-1) frames */ 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci if (d->bInterval < i || d->bInterval > j) { 38162306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d " 38262306a36Sopenharmony_ci "endpoint 0x%X has an invalid bInterval %d, " 38362306a36Sopenharmony_ci "changing to %d\n", 38462306a36Sopenharmony_ci cfgno, inum, asnum, 38562306a36Sopenharmony_ci d->bEndpointAddress, d->bInterval, n); 38662306a36Sopenharmony_ci endpoint->desc.bInterval = n; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* Some buggy low-speed devices have Bulk endpoints, which is 39062306a36Sopenharmony_ci * explicitly forbidden by the USB spec. In an attempt to make 39162306a36Sopenharmony_ci * them usable, we will try treating them as Interrupt endpoints. 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci if (udev->speed == USB_SPEED_LOW && usb_endpoint_xfer_bulk(d)) { 39462306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d " 39562306a36Sopenharmony_ci "endpoint 0x%X is Bulk; changing to Interrupt\n", 39662306a36Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress); 39762306a36Sopenharmony_ci endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT; 39862306a36Sopenharmony_ci endpoint->desc.bInterval = 1; 39962306a36Sopenharmony_ci if (usb_endpoint_maxp(&endpoint->desc) > 8) 40062306a36Sopenharmony_ci endpoint->desc.wMaxPacketSize = cpu_to_le16(8); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* 40462306a36Sopenharmony_ci * Validate the wMaxPacketSize field. 40562306a36Sopenharmony_ci * Some devices have isochronous endpoints in altsetting 0; 40662306a36Sopenharmony_ci * the USB-2 spec requires such endpoints to have wMaxPacketSize = 0 40762306a36Sopenharmony_ci * (see the end of section 5.6.3), so don't warn about them. 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize); 41062306a36Sopenharmony_ci if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) { 41162306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n", 41262306a36Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Find the highest legal maxpacket size for this endpoint */ 41662306a36Sopenharmony_ci i = 0; /* additional transactions per microframe */ 41762306a36Sopenharmony_ci switch (udev->speed) { 41862306a36Sopenharmony_ci case USB_SPEED_LOW: 41962306a36Sopenharmony_ci maxpacket_maxes = low_speed_maxpacket_maxes; 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case USB_SPEED_FULL: 42262306a36Sopenharmony_ci maxpacket_maxes = full_speed_maxpacket_maxes; 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci case USB_SPEED_HIGH: 42562306a36Sopenharmony_ci /* Multiple-transactions bits are allowed only for HS periodic endpoints */ 42662306a36Sopenharmony_ci if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) { 42762306a36Sopenharmony_ci i = maxp & USB_EP_MAXP_MULT_MASK; 42862306a36Sopenharmony_ci maxp &= ~i; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci fallthrough; 43162306a36Sopenharmony_ci default: 43262306a36Sopenharmony_ci maxpacket_maxes = high_speed_maxpacket_maxes; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case USB_SPEED_SUPER: 43562306a36Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 43662306a36Sopenharmony_ci maxpacket_maxes = super_speed_maxpacket_maxes; 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)]; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (maxp > j) { 44262306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n", 44362306a36Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress, maxp, j); 44462306a36Sopenharmony_ci maxp = j; 44562306a36Sopenharmony_ci endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* 44962306a36Sopenharmony_ci * Some buggy high speed devices have bulk endpoints using 45062306a36Sopenharmony_ci * maxpacket sizes other than 512. High speed HCDs may not 45162306a36Sopenharmony_ci * be able to handle that particular bug, so let's warn... 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) { 45462306a36Sopenharmony_ci if (maxp != 512) 45562306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d " 45662306a36Sopenharmony_ci "bulk endpoint 0x%X has invalid maxpacket %d\n", 45762306a36Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress, 45862306a36Sopenharmony_ci maxp); 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* Parse a possible SuperSpeed endpoint companion descriptor */ 46262306a36Sopenharmony_ci if (udev->speed >= USB_SPEED_SUPER) 46362306a36Sopenharmony_ci usb_parse_ss_endpoint_companion(ddev, cfgno, 46462306a36Sopenharmony_ci inum, asnum, endpoint, buffer, size); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Skip over any Class Specific or Vendor Specific descriptors; 46762306a36Sopenharmony_ci * find the next endpoint or interface descriptor */ 46862306a36Sopenharmony_ci endpoint->extra = buffer; 46962306a36Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 47062306a36Sopenharmony_ci USB_DT_INTERFACE, &n); 47162306a36Sopenharmony_ci endpoint->extralen = i; 47262306a36Sopenharmony_ci retval = buffer - buffer0 + i; 47362306a36Sopenharmony_ci if (n > 0) 47462306a36Sopenharmony_ci dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 47562306a36Sopenharmony_ci n, plural(n), "endpoint"); 47662306a36Sopenharmony_ci return retval; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciskip_to_next_endpoint_or_interface_descriptor: 47962306a36Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 48062306a36Sopenharmony_ci USB_DT_INTERFACE, NULL); 48162306a36Sopenharmony_ci return buffer - buffer0 + i; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_civoid usb_release_interface_cache(struct kref *ref) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); 48762306a36Sopenharmony_ci int j; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (j = 0; j < intfc->num_altsetting; j++) { 49062306a36Sopenharmony_ci struct usb_host_interface *alt = &intfc->altsetting[j]; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci kfree(alt->endpoint); 49362306a36Sopenharmony_ci kfree(alt->string); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci kfree(intfc); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int usb_parse_interface(struct device *ddev, int cfgno, 49962306a36Sopenharmony_ci struct usb_host_config *config, unsigned char *buffer, int size, 50062306a36Sopenharmony_ci u8 inums[], u8 nalts[]) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci unsigned char *buffer0 = buffer; 50362306a36Sopenharmony_ci struct usb_interface_descriptor *d; 50462306a36Sopenharmony_ci int inum, asnum; 50562306a36Sopenharmony_ci struct usb_interface_cache *intfc; 50662306a36Sopenharmony_ci struct usb_host_interface *alt; 50762306a36Sopenharmony_ci int i, n; 50862306a36Sopenharmony_ci int len, retval; 50962306a36Sopenharmony_ci int num_ep, num_ep_orig; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci d = (struct usb_interface_descriptor *) buffer; 51262306a36Sopenharmony_ci buffer += d->bLength; 51362306a36Sopenharmony_ci size -= d->bLength; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (d->bLength < USB_DT_INTERFACE_SIZE) 51662306a36Sopenharmony_ci goto skip_to_next_interface_descriptor; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* Which interface entry is this? */ 51962306a36Sopenharmony_ci intfc = NULL; 52062306a36Sopenharmony_ci inum = d->bInterfaceNumber; 52162306a36Sopenharmony_ci for (i = 0; i < config->desc.bNumInterfaces; ++i) { 52262306a36Sopenharmony_ci if (inums[i] == inum) { 52362306a36Sopenharmony_ci intfc = config->intf_cache[i]; 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci if (!intfc || intfc->num_altsetting >= nalts[i]) 52862306a36Sopenharmony_ci goto skip_to_next_interface_descriptor; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Check for duplicate altsetting entries */ 53162306a36Sopenharmony_ci asnum = d->bAlternateSetting; 53262306a36Sopenharmony_ci for ((i = 0, alt = &intfc->altsetting[0]); 53362306a36Sopenharmony_ci i < intfc->num_altsetting; 53462306a36Sopenharmony_ci (++i, ++alt)) { 53562306a36Sopenharmony_ci if (alt->desc.bAlternateSetting == asnum) { 53662306a36Sopenharmony_ci dev_notice(ddev, "Duplicate descriptor for config %d " 53762306a36Sopenharmony_ci "interface %d altsetting %d, skipping\n", 53862306a36Sopenharmony_ci cfgno, inum, asnum); 53962306a36Sopenharmony_ci goto skip_to_next_interface_descriptor; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci ++intfc->num_altsetting; 54462306a36Sopenharmony_ci memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* Skip over any Class Specific or Vendor Specific descriptors; 54762306a36Sopenharmony_ci * find the first endpoint or interface descriptor */ 54862306a36Sopenharmony_ci alt->extra = buffer; 54962306a36Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 55062306a36Sopenharmony_ci USB_DT_INTERFACE, &n); 55162306a36Sopenharmony_ci alt->extralen = i; 55262306a36Sopenharmony_ci if (n > 0) 55362306a36Sopenharmony_ci dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 55462306a36Sopenharmony_ci n, plural(n), "interface"); 55562306a36Sopenharmony_ci buffer += i; 55662306a36Sopenharmony_ci size -= i; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* Allocate space for the right(?) number of endpoints */ 55962306a36Sopenharmony_ci num_ep = num_ep_orig = alt->desc.bNumEndpoints; 56062306a36Sopenharmony_ci alt->desc.bNumEndpoints = 0; /* Use as a counter */ 56162306a36Sopenharmony_ci if (num_ep > USB_MAXENDPOINTS) { 56262306a36Sopenharmony_ci dev_notice(ddev, "too many endpoints for config %d interface %d " 56362306a36Sopenharmony_ci "altsetting %d: %d, using maximum allowed: %d\n", 56462306a36Sopenharmony_ci cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS); 56562306a36Sopenharmony_ci num_ep = USB_MAXENDPOINTS; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (num_ep > 0) { 56962306a36Sopenharmony_ci /* Can't allocate 0 bytes */ 57062306a36Sopenharmony_ci len = sizeof(struct usb_host_endpoint) * num_ep; 57162306a36Sopenharmony_ci alt->endpoint = kzalloc(len, GFP_KERNEL); 57262306a36Sopenharmony_ci if (!alt->endpoint) 57362306a36Sopenharmony_ci return -ENOMEM; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* Parse all the endpoint descriptors */ 57762306a36Sopenharmony_ci n = 0; 57862306a36Sopenharmony_ci while (size > 0) { 57962306a36Sopenharmony_ci if (((struct usb_descriptor_header *) buffer)->bDescriptorType 58062306a36Sopenharmony_ci == USB_DT_INTERFACE) 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum, 58362306a36Sopenharmony_ci alt, num_ep, buffer, size); 58462306a36Sopenharmony_ci if (retval < 0) 58562306a36Sopenharmony_ci return retval; 58662306a36Sopenharmony_ci ++n; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci buffer += retval; 58962306a36Sopenharmony_ci size -= retval; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (n != num_ep_orig) 59362306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has %d " 59462306a36Sopenharmony_ci "endpoint descriptor%s, different from the interface " 59562306a36Sopenharmony_ci "descriptor's value: %d\n", 59662306a36Sopenharmony_ci cfgno, inum, asnum, n, plural(n), num_ep_orig); 59762306a36Sopenharmony_ci return buffer - buffer0; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ciskip_to_next_interface_descriptor: 60062306a36Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, 60162306a36Sopenharmony_ci USB_DT_INTERFACE, NULL); 60262306a36Sopenharmony_ci return buffer - buffer0 + i; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic int usb_parse_configuration(struct usb_device *dev, int cfgidx, 60662306a36Sopenharmony_ci struct usb_host_config *config, unsigned char *buffer, int size) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci struct device *ddev = &dev->dev; 60962306a36Sopenharmony_ci unsigned char *buffer0 = buffer; 61062306a36Sopenharmony_ci int cfgno; 61162306a36Sopenharmony_ci int nintf, nintf_orig; 61262306a36Sopenharmony_ci int i, j, n; 61362306a36Sopenharmony_ci struct usb_interface_cache *intfc; 61462306a36Sopenharmony_ci unsigned char *buffer2; 61562306a36Sopenharmony_ci int size2; 61662306a36Sopenharmony_ci struct usb_descriptor_header *header; 61762306a36Sopenharmony_ci int retval; 61862306a36Sopenharmony_ci u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES]; 61962306a36Sopenharmony_ci unsigned iad_num = 0; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); 62262306a36Sopenharmony_ci nintf = nintf_orig = config->desc.bNumInterfaces; 62362306a36Sopenharmony_ci config->desc.bNumInterfaces = 0; // Adjusted later 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (config->desc.bDescriptorType != USB_DT_CONFIG || 62662306a36Sopenharmony_ci config->desc.bLength < USB_DT_CONFIG_SIZE || 62762306a36Sopenharmony_ci config->desc.bLength > size) { 62862306a36Sopenharmony_ci dev_notice(ddev, "invalid descriptor for config index %d: " 62962306a36Sopenharmony_ci "type = 0x%X, length = %d\n", cfgidx, 63062306a36Sopenharmony_ci config->desc.bDescriptorType, config->desc.bLength); 63162306a36Sopenharmony_ci return -EINVAL; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci cfgno = config->desc.bConfigurationValue; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci buffer += config->desc.bLength; 63662306a36Sopenharmony_ci size -= config->desc.bLength; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (nintf > USB_MAXINTERFACES) { 63962306a36Sopenharmony_ci dev_notice(ddev, "config %d has too many interfaces: %d, " 64062306a36Sopenharmony_ci "using maximum allowed: %d\n", 64162306a36Sopenharmony_ci cfgno, nintf, USB_MAXINTERFACES); 64262306a36Sopenharmony_ci nintf = USB_MAXINTERFACES; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* Go through the descriptors, checking their length and counting the 64662306a36Sopenharmony_ci * number of altsettings for each interface */ 64762306a36Sopenharmony_ci n = 0; 64862306a36Sopenharmony_ci for ((buffer2 = buffer, size2 = size); 64962306a36Sopenharmony_ci size2 > 0; 65062306a36Sopenharmony_ci (buffer2 += header->bLength, size2 -= header->bLength)) { 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (size2 < sizeof(struct usb_descriptor_header)) { 65362306a36Sopenharmony_ci dev_notice(ddev, "config %d descriptor has %d excess " 65462306a36Sopenharmony_ci "byte%s, ignoring\n", 65562306a36Sopenharmony_ci cfgno, size2, plural(size2)); 65662306a36Sopenharmony_ci break; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci header = (struct usb_descriptor_header *) buffer2; 66062306a36Sopenharmony_ci if ((header->bLength > size2) || (header->bLength < 2)) { 66162306a36Sopenharmony_ci dev_notice(ddev, "config %d has an invalid descriptor " 66262306a36Sopenharmony_ci "of length %d, skipping remainder of the config\n", 66362306a36Sopenharmony_ci cfgno, header->bLength); 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (header->bDescriptorType == USB_DT_INTERFACE) { 66862306a36Sopenharmony_ci struct usb_interface_descriptor *d; 66962306a36Sopenharmony_ci int inum; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci d = (struct usb_interface_descriptor *) header; 67262306a36Sopenharmony_ci if (d->bLength < USB_DT_INTERFACE_SIZE) { 67362306a36Sopenharmony_ci dev_notice(ddev, "config %d has an invalid " 67462306a36Sopenharmony_ci "interface descriptor of length %d, " 67562306a36Sopenharmony_ci "skipping\n", cfgno, d->bLength); 67662306a36Sopenharmony_ci continue; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci inum = d->bInterfaceNumber; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) && 68262306a36Sopenharmony_ci n >= nintf_orig) { 68362306a36Sopenharmony_ci dev_notice(ddev, "config %d has more interface " 68462306a36Sopenharmony_ci "descriptors, than it declares in " 68562306a36Sopenharmony_ci "bNumInterfaces, ignoring interface " 68662306a36Sopenharmony_ci "number: %d\n", cfgno, inum); 68762306a36Sopenharmony_ci continue; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (inum >= nintf_orig) 69162306a36Sopenharmony_ci dev_notice(ddev, "config %d has an invalid " 69262306a36Sopenharmony_ci "interface number: %d but max is %d\n", 69362306a36Sopenharmony_ci cfgno, inum, nintf_orig - 1); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Have we already encountered this interface? 69662306a36Sopenharmony_ci * Count its altsettings */ 69762306a36Sopenharmony_ci for (i = 0; i < n; ++i) { 69862306a36Sopenharmony_ci if (inums[i] == inum) 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci if (i < n) { 70262306a36Sopenharmony_ci if (nalts[i] < 255) 70362306a36Sopenharmony_ci ++nalts[i]; 70462306a36Sopenharmony_ci } else if (n < USB_MAXINTERFACES) { 70562306a36Sopenharmony_ci inums[n] = inum; 70662306a36Sopenharmony_ci nalts[n] = 1; 70762306a36Sopenharmony_ci ++n; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci } else if (header->bDescriptorType == 71162306a36Sopenharmony_ci USB_DT_INTERFACE_ASSOCIATION) { 71262306a36Sopenharmony_ci struct usb_interface_assoc_descriptor *d; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci d = (struct usb_interface_assoc_descriptor *)header; 71562306a36Sopenharmony_ci if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) { 71662306a36Sopenharmony_ci dev_notice(ddev, 71762306a36Sopenharmony_ci "config %d has an invalid interface association descriptor of length %d, skipping\n", 71862306a36Sopenharmony_ci cfgno, d->bLength); 71962306a36Sopenharmony_ci continue; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (iad_num == USB_MAXIADS) { 72362306a36Sopenharmony_ci dev_notice(ddev, "found more Interface " 72462306a36Sopenharmony_ci "Association Descriptors " 72562306a36Sopenharmony_ci "than allocated for in " 72662306a36Sopenharmony_ci "configuration %d\n", cfgno); 72762306a36Sopenharmony_ci } else { 72862306a36Sopenharmony_ci config->intf_assoc[iad_num] = d; 72962306a36Sopenharmony_ci iad_num++; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci } else if (header->bDescriptorType == USB_DT_DEVICE || 73362306a36Sopenharmony_ci header->bDescriptorType == USB_DT_CONFIG) 73462306a36Sopenharmony_ci dev_notice(ddev, "config %d contains an unexpected " 73562306a36Sopenharmony_ci "descriptor of type 0x%X, skipping\n", 73662306a36Sopenharmony_ci cfgno, header->bDescriptorType); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci } /* for ((buffer2 = buffer, size2 = size); ...) */ 73962306a36Sopenharmony_ci size = buffer2 - buffer; 74062306a36Sopenharmony_ci config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (n != nintf) 74362306a36Sopenharmony_ci dev_notice(ddev, "config %d has %d interface%s, different from " 74462306a36Sopenharmony_ci "the descriptor's value: %d\n", 74562306a36Sopenharmony_ci cfgno, n, plural(n), nintf_orig); 74662306a36Sopenharmony_ci else if (n == 0) 74762306a36Sopenharmony_ci dev_notice(ddev, "config %d has no interfaces?\n", cfgno); 74862306a36Sopenharmony_ci config->desc.bNumInterfaces = nintf = n; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* Check for missing interface numbers */ 75162306a36Sopenharmony_ci for (i = 0; i < nintf; ++i) { 75262306a36Sopenharmony_ci for (j = 0; j < nintf; ++j) { 75362306a36Sopenharmony_ci if (inums[j] == i) 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci if (j >= nintf) 75762306a36Sopenharmony_ci dev_notice(ddev, "config %d has no interface number " 75862306a36Sopenharmony_ci "%d\n", cfgno, i); 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* Allocate the usb_interface_caches and altsetting arrays */ 76262306a36Sopenharmony_ci for (i = 0; i < nintf; ++i) { 76362306a36Sopenharmony_ci j = nalts[i]; 76462306a36Sopenharmony_ci if (j > USB_MAXALTSETTING) { 76562306a36Sopenharmony_ci dev_notice(ddev, "too many alternate settings for " 76662306a36Sopenharmony_ci "config %d interface %d: %d, " 76762306a36Sopenharmony_ci "using maximum allowed: %d\n", 76862306a36Sopenharmony_ci cfgno, inums[i], j, USB_MAXALTSETTING); 76962306a36Sopenharmony_ci nalts[i] = j = USB_MAXALTSETTING; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci intfc = kzalloc(struct_size(intfc, altsetting, j), GFP_KERNEL); 77362306a36Sopenharmony_ci config->intf_cache[i] = intfc; 77462306a36Sopenharmony_ci if (!intfc) 77562306a36Sopenharmony_ci return -ENOMEM; 77662306a36Sopenharmony_ci kref_init(&intfc->ref); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* FIXME: parse the BOS descriptor */ 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* Skip over any Class Specific or Vendor Specific descriptors; 78262306a36Sopenharmony_ci * find the first interface descriptor */ 78362306a36Sopenharmony_ci config->extra = buffer; 78462306a36Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, 78562306a36Sopenharmony_ci USB_DT_INTERFACE, &n); 78662306a36Sopenharmony_ci config->extralen = i; 78762306a36Sopenharmony_ci if (n > 0) 78862306a36Sopenharmony_ci dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 78962306a36Sopenharmony_ci n, plural(n), "configuration"); 79062306a36Sopenharmony_ci buffer += i; 79162306a36Sopenharmony_ci size -= i; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* Parse all the interface/altsetting descriptors */ 79462306a36Sopenharmony_ci while (size > 0) { 79562306a36Sopenharmony_ci retval = usb_parse_interface(ddev, cfgno, config, 79662306a36Sopenharmony_ci buffer, size, inums, nalts); 79762306a36Sopenharmony_ci if (retval < 0) 79862306a36Sopenharmony_ci return retval; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci buffer += retval; 80162306a36Sopenharmony_ci size -= retval; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* Check for missing altsettings */ 80562306a36Sopenharmony_ci for (i = 0; i < nintf; ++i) { 80662306a36Sopenharmony_ci intfc = config->intf_cache[i]; 80762306a36Sopenharmony_ci for (j = 0; j < intfc->num_altsetting; ++j) { 80862306a36Sopenharmony_ci for (n = 0; n < intfc->num_altsetting; ++n) { 80962306a36Sopenharmony_ci if (intfc->altsetting[n].desc. 81062306a36Sopenharmony_ci bAlternateSetting == j) 81162306a36Sopenharmony_ci break; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci if (n >= intfc->num_altsetting) 81462306a36Sopenharmony_ci dev_notice(ddev, "config %d interface %d has no " 81562306a36Sopenharmony_ci "altsetting %d\n", cfgno, inums[i], j); 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/* hub-only!! ... and only exported for reset/reinit path. 82362306a36Sopenharmony_ci * otherwise used internally on disconnect/destroy path 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_civoid usb_destroy_configuration(struct usb_device *dev) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci int c, i; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (!dev->config) 83062306a36Sopenharmony_ci return; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (dev->rawdescriptors) { 83362306a36Sopenharmony_ci for (i = 0; i < dev->descriptor.bNumConfigurations; i++) 83462306a36Sopenharmony_ci kfree(dev->rawdescriptors[i]); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci kfree(dev->rawdescriptors); 83762306a36Sopenharmony_ci dev->rawdescriptors = NULL; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { 84162306a36Sopenharmony_ci struct usb_host_config *cf = &dev->config[c]; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci kfree(cf->string); 84462306a36Sopenharmony_ci for (i = 0; i < cf->desc.bNumInterfaces; i++) { 84562306a36Sopenharmony_ci if (cf->intf_cache[i]) 84662306a36Sopenharmony_ci kref_put(&cf->intf_cache[i]->ref, 84762306a36Sopenharmony_ci usb_release_interface_cache); 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci kfree(dev->config); 85162306a36Sopenharmony_ci dev->config = NULL; 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci/* 85662306a36Sopenharmony_ci * Get the USB config descriptors, cache and parse'em 85762306a36Sopenharmony_ci * 85862306a36Sopenharmony_ci * hub-only!! ... and only in reset path, or usb_new_device() 85962306a36Sopenharmony_ci * (used by real hubs and virtual root hubs) 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_ciint usb_get_configuration(struct usb_device *dev) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct device *ddev = &dev->dev; 86462306a36Sopenharmony_ci int ncfg = dev->descriptor.bNumConfigurations; 86562306a36Sopenharmony_ci unsigned int cfgno, length; 86662306a36Sopenharmony_ci unsigned char *bigbuffer; 86762306a36Sopenharmony_ci struct usb_config_descriptor *desc; 86862306a36Sopenharmony_ci int result; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (ncfg > USB_MAXCONFIG) { 87162306a36Sopenharmony_ci dev_notice(ddev, "too many configurations: %d, " 87262306a36Sopenharmony_ci "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); 87362306a36Sopenharmony_ci dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (ncfg < 1) { 87762306a36Sopenharmony_ci dev_err(ddev, "no configurations\n"); 87862306a36Sopenharmony_ci return -EINVAL; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci length = ncfg * sizeof(struct usb_host_config); 88262306a36Sopenharmony_ci dev->config = kzalloc(length, GFP_KERNEL); 88362306a36Sopenharmony_ci if (!dev->config) 88462306a36Sopenharmony_ci return -ENOMEM; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci length = ncfg * sizeof(char *); 88762306a36Sopenharmony_ci dev->rawdescriptors = kzalloc(length, GFP_KERNEL); 88862306a36Sopenharmony_ci if (!dev->rawdescriptors) 88962306a36Sopenharmony_ci return -ENOMEM; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); 89262306a36Sopenharmony_ci if (!desc) 89362306a36Sopenharmony_ci return -ENOMEM; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci for (cfgno = 0; cfgno < ncfg; cfgno++) { 89662306a36Sopenharmony_ci /* We grab just the first descriptor so we know how long 89762306a36Sopenharmony_ci * the whole configuration is */ 89862306a36Sopenharmony_ci result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, 89962306a36Sopenharmony_ci desc, USB_DT_CONFIG_SIZE); 90062306a36Sopenharmony_ci if (result < 0) { 90162306a36Sopenharmony_ci dev_err(ddev, "unable to read config index %d " 90262306a36Sopenharmony_ci "descriptor/%s: %d\n", cfgno, "start", result); 90362306a36Sopenharmony_ci if (result != -EPIPE) 90462306a36Sopenharmony_ci goto err; 90562306a36Sopenharmony_ci dev_notice(ddev, "chopping to %d config(s)\n", cfgno); 90662306a36Sopenharmony_ci dev->descriptor.bNumConfigurations = cfgno; 90762306a36Sopenharmony_ci break; 90862306a36Sopenharmony_ci } else if (result < 4) { 90962306a36Sopenharmony_ci dev_err(ddev, "config index %d descriptor too short " 91062306a36Sopenharmony_ci "(expected %i, got %i)\n", cfgno, 91162306a36Sopenharmony_ci USB_DT_CONFIG_SIZE, result); 91262306a36Sopenharmony_ci result = -EINVAL; 91362306a36Sopenharmony_ci goto err; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci length = max((int) le16_to_cpu(desc->wTotalLength), 91662306a36Sopenharmony_ci USB_DT_CONFIG_SIZE); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci /* Now that we know the length, get the whole thing */ 91962306a36Sopenharmony_ci bigbuffer = kmalloc(length, GFP_KERNEL); 92062306a36Sopenharmony_ci if (!bigbuffer) { 92162306a36Sopenharmony_ci result = -ENOMEM; 92262306a36Sopenharmony_ci goto err; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (dev->quirks & USB_QUIRK_DELAY_INIT) 92662306a36Sopenharmony_ci msleep(200); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, 92962306a36Sopenharmony_ci bigbuffer, length); 93062306a36Sopenharmony_ci if (result < 0) { 93162306a36Sopenharmony_ci dev_err(ddev, "unable to read config index %d " 93262306a36Sopenharmony_ci "descriptor/%s\n", cfgno, "all"); 93362306a36Sopenharmony_ci kfree(bigbuffer); 93462306a36Sopenharmony_ci goto err; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci if (result < length) { 93762306a36Sopenharmony_ci dev_notice(ddev, "config index %d descriptor too short " 93862306a36Sopenharmony_ci "(expected %i, got %i)\n", cfgno, length, result); 93962306a36Sopenharmony_ci length = result; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci dev->rawdescriptors[cfgno] = bigbuffer; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci result = usb_parse_configuration(dev, cfgno, 94562306a36Sopenharmony_ci &dev->config[cfgno], bigbuffer, length); 94662306a36Sopenharmony_ci if (result < 0) { 94762306a36Sopenharmony_ci ++cfgno; 94862306a36Sopenharmony_ci goto err; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cierr: 95362306a36Sopenharmony_ci kfree(desc); 95462306a36Sopenharmony_ci dev->descriptor.bNumConfigurations = cfgno; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return result; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_civoid usb_release_bos_descriptor(struct usb_device *dev) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci if (dev->bos) { 96262306a36Sopenharmony_ci kfree(dev->bos->desc); 96362306a36Sopenharmony_ci kfree(dev->bos); 96462306a36Sopenharmony_ci dev->bos = NULL; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistatic const __u8 bos_desc_len[256] = { 96962306a36Sopenharmony_ci [USB_CAP_TYPE_WIRELESS_USB] = USB_DT_USB_WIRELESS_CAP_SIZE, 97062306a36Sopenharmony_ci [USB_CAP_TYPE_EXT] = USB_DT_USB_EXT_CAP_SIZE, 97162306a36Sopenharmony_ci [USB_SS_CAP_TYPE] = USB_DT_USB_SS_CAP_SIZE, 97262306a36Sopenharmony_ci [USB_SSP_CAP_TYPE] = USB_DT_USB_SSP_CAP_SIZE(1), 97362306a36Sopenharmony_ci [CONTAINER_ID_TYPE] = USB_DT_USB_SS_CONTN_ID_SIZE, 97462306a36Sopenharmony_ci [USB_PTM_CAP_TYPE] = USB_DT_USB_PTM_ID_SIZE, 97562306a36Sopenharmony_ci}; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci/* Get BOS descriptor set */ 97862306a36Sopenharmony_ciint usb_get_bos_descriptor(struct usb_device *dev) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci struct device *ddev = &dev->dev; 98162306a36Sopenharmony_ci struct usb_bos_descriptor *bos; 98262306a36Sopenharmony_ci struct usb_dev_cap_header *cap; 98362306a36Sopenharmony_ci struct usb_ssp_cap_descriptor *ssp_cap; 98462306a36Sopenharmony_ci unsigned char *buffer, *buffer0; 98562306a36Sopenharmony_ci int length, total_len, num, i, ssac; 98662306a36Sopenharmony_ci __u8 cap_type; 98762306a36Sopenharmony_ci int ret; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci bos = kzalloc(sizeof(*bos), GFP_KERNEL); 99062306a36Sopenharmony_ci if (!bos) 99162306a36Sopenharmony_ci return -ENOMEM; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* Get BOS descriptor */ 99462306a36Sopenharmony_ci ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE); 99562306a36Sopenharmony_ci if (ret < USB_DT_BOS_SIZE || bos->bLength < USB_DT_BOS_SIZE) { 99662306a36Sopenharmony_ci dev_notice(ddev, "unable to get BOS descriptor or descriptor too short\n"); 99762306a36Sopenharmony_ci if (ret >= 0) 99862306a36Sopenharmony_ci ret = -ENOMSG; 99962306a36Sopenharmony_ci kfree(bos); 100062306a36Sopenharmony_ci return ret; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci length = bos->bLength; 100462306a36Sopenharmony_ci total_len = le16_to_cpu(bos->wTotalLength); 100562306a36Sopenharmony_ci num = bos->bNumDeviceCaps; 100662306a36Sopenharmony_ci kfree(bos); 100762306a36Sopenharmony_ci if (total_len < length) 100862306a36Sopenharmony_ci return -EINVAL; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci dev->bos = kzalloc(sizeof(*dev->bos), GFP_KERNEL); 101162306a36Sopenharmony_ci if (!dev->bos) 101262306a36Sopenharmony_ci return -ENOMEM; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci /* Now let's get the whole BOS descriptor set */ 101562306a36Sopenharmony_ci buffer = kzalloc(total_len, GFP_KERNEL); 101662306a36Sopenharmony_ci if (!buffer) { 101762306a36Sopenharmony_ci ret = -ENOMEM; 101862306a36Sopenharmony_ci goto err; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci dev->bos->desc = (struct usb_bos_descriptor *)buffer; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len); 102362306a36Sopenharmony_ci if (ret < total_len) { 102462306a36Sopenharmony_ci dev_notice(ddev, "unable to get BOS descriptor set\n"); 102562306a36Sopenharmony_ci if (ret >= 0) 102662306a36Sopenharmony_ci ret = -ENOMSG; 102762306a36Sopenharmony_ci goto err; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci buffer0 = buffer; 103162306a36Sopenharmony_ci total_len -= length; 103262306a36Sopenharmony_ci buffer += length; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci for (i = 0; i < num; i++) { 103562306a36Sopenharmony_ci cap = (struct usb_dev_cap_header *)buffer; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (total_len < sizeof(*cap) || total_len < cap->bLength) { 103862306a36Sopenharmony_ci dev->bos->desc->bNumDeviceCaps = i; 103962306a36Sopenharmony_ci break; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci cap_type = cap->bDevCapabilityType; 104262306a36Sopenharmony_ci length = cap->bLength; 104362306a36Sopenharmony_ci if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) { 104462306a36Sopenharmony_ci dev->bos->desc->bNumDeviceCaps = i; 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { 104962306a36Sopenharmony_ci dev_notice(ddev, "descriptor type invalid, skip\n"); 105062306a36Sopenharmony_ci goto skip_to_next_descriptor; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci switch (cap_type) { 105462306a36Sopenharmony_ci case USB_CAP_TYPE_EXT: 105562306a36Sopenharmony_ci dev->bos->ext_cap = 105662306a36Sopenharmony_ci (struct usb_ext_cap_descriptor *)buffer; 105762306a36Sopenharmony_ci break; 105862306a36Sopenharmony_ci case USB_SS_CAP_TYPE: 105962306a36Sopenharmony_ci dev->bos->ss_cap = 106062306a36Sopenharmony_ci (struct usb_ss_cap_descriptor *)buffer; 106162306a36Sopenharmony_ci break; 106262306a36Sopenharmony_ci case USB_SSP_CAP_TYPE: 106362306a36Sopenharmony_ci ssp_cap = (struct usb_ssp_cap_descriptor *)buffer; 106462306a36Sopenharmony_ci ssac = (le32_to_cpu(ssp_cap->bmAttributes) & 106562306a36Sopenharmony_ci USB_SSP_SUBLINK_SPEED_ATTRIBS); 106662306a36Sopenharmony_ci if (length >= USB_DT_USB_SSP_CAP_SIZE(ssac)) 106762306a36Sopenharmony_ci dev->bos->ssp_cap = ssp_cap; 106862306a36Sopenharmony_ci break; 106962306a36Sopenharmony_ci case CONTAINER_ID_TYPE: 107062306a36Sopenharmony_ci dev->bos->ss_id = 107162306a36Sopenharmony_ci (struct usb_ss_container_id_descriptor *)buffer; 107262306a36Sopenharmony_ci break; 107362306a36Sopenharmony_ci case USB_PTM_CAP_TYPE: 107462306a36Sopenharmony_ci dev->bos->ptm_cap = 107562306a36Sopenharmony_ci (struct usb_ptm_cap_descriptor *)buffer; 107662306a36Sopenharmony_ci break; 107762306a36Sopenharmony_ci default: 107862306a36Sopenharmony_ci break; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ciskip_to_next_descriptor: 108262306a36Sopenharmony_ci total_len -= length; 108362306a36Sopenharmony_ci buffer += length; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci dev->bos->desc->wTotalLength = cpu_to_le16(buffer - buffer0); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci return 0; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cierr: 109062306a36Sopenharmony_ci usb_release_bos_descriptor(dev); 109162306a36Sopenharmony_ci return ret; 109262306a36Sopenharmony_ci} 1093