18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Released under the GPLv2 only. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/usb.h> 78c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h> 88c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h> 98c2ecf20Sopenharmony_ci#include <linux/usb/quirks.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 148c2ecf20Sopenharmony_ci#include "usb.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define USB_MAXALTSETTING 128 /* Hard limit */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define USB_MAXCONFIG 8 /* Arbitrary limit */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic inline const char *plural(int n) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci return (n == 1 ? "" : "s"); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int find_next_descriptor(unsigned char *buffer, int size, 288c2ecf20Sopenharmony_ci int dt1, int dt2, int *num_skipped) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct usb_descriptor_header *h; 318c2ecf20Sopenharmony_ci int n = 0; 328c2ecf20Sopenharmony_ci unsigned char *buffer0 = buffer; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* Find the next descriptor of type dt1 or dt2 */ 358c2ecf20Sopenharmony_ci while (size > 0) { 368c2ecf20Sopenharmony_ci h = (struct usb_descriptor_header *) buffer; 378c2ecf20Sopenharmony_ci if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2) 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci buffer += h->bLength; 408c2ecf20Sopenharmony_ci size -= h->bLength; 418c2ecf20Sopenharmony_ci ++n; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* Store the number of descriptors skipped and return the 458c2ecf20Sopenharmony_ci * number of bytes skipped */ 468c2ecf20Sopenharmony_ci if (num_skipped) 478c2ecf20Sopenharmony_ci *num_skipped = n; 488c2ecf20Sopenharmony_ci return buffer - buffer0; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev, 528c2ecf20Sopenharmony_ci int cfgno, int inum, int asnum, struct usb_host_endpoint *ep, 538c2ecf20Sopenharmony_ci unsigned char *buffer, int size) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct usb_ssp_isoc_ep_comp_descriptor *desc; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* 588c2ecf20Sopenharmony_ci * The SuperSpeedPlus Isoc endpoint companion descriptor immediately 598c2ecf20Sopenharmony_ci * follows the SuperSpeed Endpoint Companion descriptor 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer; 628c2ecf20Sopenharmony_ci if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP || 638c2ecf20Sopenharmony_ci size < USB_DT_SSP_ISOC_EP_COMP_SIZE) { 648c2ecf20Sopenharmony_ci dev_notice(ddev, "Invalid SuperSpeedPlus isoc endpoint companion" 658c2ecf20Sopenharmony_ci "for config %d interface %d altsetting %d ep %d.\n", 668c2ecf20Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 678c2ecf20Sopenharmony_ci return; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci memcpy(&ep->ssp_isoc_ep_comp, desc, USB_DT_SSP_ISOC_EP_COMP_SIZE); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, 738c2ecf20Sopenharmony_ci int inum, int asnum, struct usb_host_endpoint *ep, 748c2ecf20Sopenharmony_ci unsigned char *buffer, int size) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct usb_ss_ep_comp_descriptor *desc; 778c2ecf20Sopenharmony_ci int max_tx; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* The SuperSpeed endpoint companion descriptor is supposed to 808c2ecf20Sopenharmony_ci * be the first thing immediately following the endpoint descriptor. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci desc = (struct usb_ss_ep_comp_descriptor *) buffer; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP || 858c2ecf20Sopenharmony_ci size < USB_DT_SS_EP_COMP_SIZE) { 868c2ecf20Sopenharmony_ci dev_notice(ddev, "No SuperSpeed endpoint companion for config %d " 878c2ecf20Sopenharmony_ci " interface %d altsetting %d ep %d: " 888c2ecf20Sopenharmony_ci "using minimum values\n", 898c2ecf20Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* Fill in some default values. 928c2ecf20Sopenharmony_ci * Leave bmAttributes as zero, which will mean no streams for 938c2ecf20Sopenharmony_ci * bulk, and isoc won't support multiple bursts of packets. 948c2ecf20Sopenharmony_ci * With bursts of only one packet, and a Mult of 1, the max 958c2ecf20Sopenharmony_ci * amount of data moved per endpoint service interval is one 968c2ecf20Sopenharmony_ci * packet. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE; 998c2ecf20Sopenharmony_ci ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; 1008c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_isoc(&ep->desc) || 1018c2ecf20Sopenharmony_ci usb_endpoint_xfer_int(&ep->desc)) 1028c2ecf20Sopenharmony_ci ep->ss_ep_comp.wBytesPerInterval = 1038c2ecf20Sopenharmony_ci ep->desc.wMaxPacketSize; 1048c2ecf20Sopenharmony_ci return; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci buffer += desc->bLength; 1078c2ecf20Sopenharmony_ci size -= desc->bLength; 1088c2ecf20Sopenharmony_ci memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Check the various values */ 1118c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) { 1128c2ecf20Sopenharmony_ci dev_notice(ddev, "Control endpoint with bMaxBurst = %d in " 1138c2ecf20Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 1148c2ecf20Sopenharmony_ci "setting to zero\n", desc->bMaxBurst, 1158c2ecf20Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 1168c2ecf20Sopenharmony_ci ep->ss_ep_comp.bMaxBurst = 0; 1178c2ecf20Sopenharmony_ci } else if (desc->bMaxBurst > 15) { 1188c2ecf20Sopenharmony_ci dev_notice(ddev, "Endpoint with bMaxBurst = %d in " 1198c2ecf20Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 1208c2ecf20Sopenharmony_ci "setting to 15\n", desc->bMaxBurst, 1218c2ecf20Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 1228c2ecf20Sopenharmony_ci ep->ss_ep_comp.bMaxBurst = 15; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if ((usb_endpoint_xfer_control(&ep->desc) || 1268c2ecf20Sopenharmony_ci usb_endpoint_xfer_int(&ep->desc)) && 1278c2ecf20Sopenharmony_ci desc->bmAttributes != 0) { 1288c2ecf20Sopenharmony_ci dev_notice(ddev, "%s endpoint with bmAttributes = %d in " 1298c2ecf20Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 1308c2ecf20Sopenharmony_ci "setting to zero\n", 1318c2ecf20Sopenharmony_ci usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk", 1328c2ecf20Sopenharmony_ci desc->bmAttributes, 1338c2ecf20Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 1348c2ecf20Sopenharmony_ci ep->ss_ep_comp.bmAttributes = 0; 1358c2ecf20Sopenharmony_ci } else if (usb_endpoint_xfer_bulk(&ep->desc) && 1368c2ecf20Sopenharmony_ci desc->bmAttributes > 16) { 1378c2ecf20Sopenharmony_ci dev_notice(ddev, "Bulk endpoint with more than 65536 streams in " 1388c2ecf20Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 1398c2ecf20Sopenharmony_ci "setting to max\n", 1408c2ecf20Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 1418c2ecf20Sopenharmony_ci ep->ss_ep_comp.bmAttributes = 16; 1428c2ecf20Sopenharmony_ci } else if (usb_endpoint_xfer_isoc(&ep->desc) && 1438c2ecf20Sopenharmony_ci !USB_SS_SSP_ISOC_COMP(desc->bmAttributes) && 1448c2ecf20Sopenharmony_ci USB_SS_MULT(desc->bmAttributes) > 3) { 1458c2ecf20Sopenharmony_ci dev_notice(ddev, "Isoc endpoint has Mult of %d in " 1468c2ecf20Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 1478c2ecf20Sopenharmony_ci "setting to 3\n", 1488c2ecf20Sopenharmony_ci USB_SS_MULT(desc->bmAttributes), 1498c2ecf20Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress); 1508c2ecf20Sopenharmony_ci ep->ss_ep_comp.bmAttributes = 2; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_isoc(&ep->desc)) 1548c2ecf20Sopenharmony_ci max_tx = (desc->bMaxBurst + 1) * 1558c2ecf20Sopenharmony_ci (USB_SS_MULT(desc->bmAttributes)) * 1568c2ecf20Sopenharmony_ci usb_endpoint_maxp(&ep->desc); 1578c2ecf20Sopenharmony_ci else if (usb_endpoint_xfer_int(&ep->desc)) 1588c2ecf20Sopenharmony_ci max_tx = usb_endpoint_maxp(&ep->desc) * 1598c2ecf20Sopenharmony_ci (desc->bMaxBurst + 1); 1608c2ecf20Sopenharmony_ci else 1618c2ecf20Sopenharmony_ci max_tx = 999999; 1628c2ecf20Sopenharmony_ci if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) { 1638c2ecf20Sopenharmony_ci dev_notice(ddev, "%s endpoint with wBytesPerInterval of %d in " 1648c2ecf20Sopenharmony_ci "config %d interface %d altsetting %d ep %d: " 1658c2ecf20Sopenharmony_ci "setting to %d\n", 1668c2ecf20Sopenharmony_ci usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int", 1678c2ecf20Sopenharmony_ci le16_to_cpu(desc->wBytesPerInterval), 1688c2ecf20Sopenharmony_ci cfgno, inum, asnum, ep->desc.bEndpointAddress, 1698c2ecf20Sopenharmony_ci max_tx); 1708c2ecf20Sopenharmony_ci ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci /* Parse a possible SuperSpeedPlus isoc ep companion descriptor */ 1738c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_isoc(&ep->desc) && 1748c2ecf20Sopenharmony_ci USB_SS_SSP_ISOC_COMP(desc->bmAttributes)) 1758c2ecf20Sopenharmony_ci usb_parse_ssp_isoc_endpoint_companion(ddev, cfgno, inum, asnum, 1768c2ecf20Sopenharmony_ci ep, buffer, size); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const unsigned short low_speed_maxpacket_maxes[4] = { 1808c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = 8, 1818c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = 0, 1828c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = 0, 1838c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = 8, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_cistatic const unsigned short full_speed_maxpacket_maxes[4] = { 1868c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = 64, 1878c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = 1023, 1888c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = 64, 1898c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = 64, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_cistatic const unsigned short high_speed_maxpacket_maxes[4] = { 1928c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = 64, 1938c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = 1024, 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* Bulk should be 512, but some devices use 1024: we will warn below */ 1968c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = 1024, 1978c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = 1024, 1988c2ecf20Sopenharmony_ci}; 1998c2ecf20Sopenharmony_cistatic const unsigned short super_speed_maxpacket_maxes[4] = { 2008c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_CONTROL] = 512, 2018c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_ISOC] = 1024, 2028c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_BULK] = 1024, 2038c2ecf20Sopenharmony_ci [USB_ENDPOINT_XFER_INT] = 1024, 2048c2ecf20Sopenharmony_ci}; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1, 2078c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *e2) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci if (e1->bEndpointAddress == e2->bEndpointAddress) 2108c2ecf20Sopenharmony_ci return true; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) { 2138c2ecf20Sopenharmony_ci if (usb_endpoint_num(e1) == usb_endpoint_num(e2)) 2148c2ecf20Sopenharmony_ci return true; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return false; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* 2218c2ecf20Sopenharmony_ci * Check for duplicate endpoint addresses in other interfaces and in the 2228c2ecf20Sopenharmony_ci * altsetting currently being parsed. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_cistatic bool config_endpoint_is_duplicate(struct usb_host_config *config, 2258c2ecf20Sopenharmony_ci int inum, int asnum, struct usb_endpoint_descriptor *d) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *epd; 2288c2ecf20Sopenharmony_ci struct usb_interface_cache *intfc; 2298c2ecf20Sopenharmony_ci struct usb_host_interface *alt; 2308c2ecf20Sopenharmony_ci int i, j, k; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci for (i = 0; i < config->desc.bNumInterfaces; ++i) { 2338c2ecf20Sopenharmony_ci intfc = config->intf_cache[i]; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci for (j = 0; j < intfc->num_altsetting; ++j) { 2368c2ecf20Sopenharmony_ci alt = &intfc->altsetting[j]; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (alt->desc.bInterfaceNumber == inum && 2398c2ecf20Sopenharmony_ci alt->desc.bAlternateSetting != asnum) 2408c2ecf20Sopenharmony_ci continue; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci for (k = 0; k < alt->desc.bNumEndpoints; ++k) { 2438c2ecf20Sopenharmony_ci epd = &alt->endpoint[k].desc; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (endpoint_is_duplicate(epd, d)) 2468c2ecf20Sopenharmony_ci return true; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return false; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int usb_parse_endpoint(struct device *ddev, int cfgno, 2558c2ecf20Sopenharmony_ci struct usb_host_config *config, int inum, int asnum, 2568c2ecf20Sopenharmony_ci struct usb_host_interface *ifp, int num_ep, 2578c2ecf20Sopenharmony_ci unsigned char *buffer, int size) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct usb_device *udev = to_usb_device(ddev); 2608c2ecf20Sopenharmony_ci unsigned char *buffer0 = buffer; 2618c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *d; 2628c2ecf20Sopenharmony_ci struct usb_host_endpoint *endpoint; 2638c2ecf20Sopenharmony_ci int n, i, j, retval; 2648c2ecf20Sopenharmony_ci unsigned int maxp; 2658c2ecf20Sopenharmony_ci const unsigned short *maxpacket_maxes; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci d = (struct usb_endpoint_descriptor *) buffer; 2688c2ecf20Sopenharmony_ci buffer += d->bLength; 2698c2ecf20Sopenharmony_ci size -= d->bLength; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE) 2728c2ecf20Sopenharmony_ci n = USB_DT_ENDPOINT_AUDIO_SIZE; 2738c2ecf20Sopenharmony_ci else if (d->bLength >= USB_DT_ENDPOINT_SIZE) 2748c2ecf20Sopenharmony_ci n = USB_DT_ENDPOINT_SIZE; 2758c2ecf20Sopenharmony_ci else { 2768c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has an " 2778c2ecf20Sopenharmony_ci "invalid endpoint descriptor of length %d, skipping\n", 2788c2ecf20Sopenharmony_ci cfgno, inum, asnum, d->bLength); 2798c2ecf20Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK; 2838c2ecf20Sopenharmony_ci if (i >= 16 || i == 0) { 2848c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has an " 2858c2ecf20Sopenharmony_ci "invalid endpoint with address 0x%X, skipping\n", 2868c2ecf20Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress); 2878c2ecf20Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Only store as many endpoints as we have room for */ 2918c2ecf20Sopenharmony_ci if (ifp->desc.bNumEndpoints >= num_ep) 2928c2ecf20Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Save a copy of the descriptor and use it instead of the original */ 2958c2ecf20Sopenharmony_ci endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; 2968c2ecf20Sopenharmony_ci memcpy(&endpoint->desc, d, n); 2978c2ecf20Sopenharmony_ci d = &endpoint->desc; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Clear the reserved bits in bEndpointAddress */ 3008c2ecf20Sopenharmony_ci i = d->bEndpointAddress & 3018c2ecf20Sopenharmony_ci (USB_ENDPOINT_DIR_MASK | USB_ENDPOINT_NUMBER_MASK); 3028c2ecf20Sopenharmony_ci if (i != d->bEndpointAddress) { 3038c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has an endpoint descriptor with address 0x%X, changing to 0x%X\n", 3048c2ecf20Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress, i); 3058c2ecf20Sopenharmony_ci endpoint->desc.bEndpointAddress = i; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Check for duplicate endpoint addresses */ 3098c2ecf20Sopenharmony_ci if (config_endpoint_is_duplicate(config, inum, asnum, d)) { 3108c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", 3118c2ecf20Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress); 3128c2ecf20Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Ignore some endpoints */ 3168c2ecf20Sopenharmony_ci if (udev->quirks & USB_QUIRK_ENDPOINT_IGNORE) { 3178c2ecf20Sopenharmony_ci if (usb_endpoint_is_ignored(udev, ifp, d)) { 3188c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping\n", 3198c2ecf20Sopenharmony_ci cfgno, inum, asnum, 3208c2ecf20Sopenharmony_ci d->bEndpointAddress); 3218c2ecf20Sopenharmony_ci goto skip_to_next_endpoint_or_interface_descriptor; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Accept this endpoint */ 3268c2ecf20Sopenharmony_ci ++ifp->desc.bNumEndpoints; 3278c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&endpoint->urb_list); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* 3308c2ecf20Sopenharmony_ci * Fix up bInterval values outside the legal range. 3318c2ecf20Sopenharmony_ci * Use 10 or 8 ms if no proper value can be guessed. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci i = 0; /* i = min, j = max, n = default */ 3348c2ecf20Sopenharmony_ci j = 255; 3358c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_int(d)) { 3368c2ecf20Sopenharmony_ci i = 1; 3378c2ecf20Sopenharmony_ci switch (udev->speed) { 3388c2ecf20Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 3398c2ecf20Sopenharmony_ci case USB_SPEED_SUPER: 3408c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 3418c2ecf20Sopenharmony_ci /* 3428c2ecf20Sopenharmony_ci * Many device manufacturers are using full-speed 3438c2ecf20Sopenharmony_ci * bInterval values in high-speed interrupt endpoint 3448c2ecf20Sopenharmony_ci * descriptors. Try to fix those and fall back to an 3458c2ecf20Sopenharmony_ci * 8-ms default value otherwise. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci n = fls(d->bInterval*8); 3488c2ecf20Sopenharmony_ci if (n == 0) 3498c2ecf20Sopenharmony_ci n = 7; /* 8 ms = 2^(7-1) uframes */ 3508c2ecf20Sopenharmony_ci j = 16; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* 3538c2ecf20Sopenharmony_ci * Adjust bInterval for quirked devices. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci /* 3568c2ecf20Sopenharmony_ci * This quirk fixes bIntervals reported in ms. 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci if (udev->quirks & USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) { 3598c2ecf20Sopenharmony_ci n = clamp(fls(d->bInterval) + 3, i, j); 3608c2ecf20Sopenharmony_ci i = j = n; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci /* 3638c2ecf20Sopenharmony_ci * This quirk fixes bIntervals reported in 3648c2ecf20Sopenharmony_ci * linear microframes. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci if (udev->quirks & USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) { 3678c2ecf20Sopenharmony_ci n = clamp(fls(d->bInterval), i, j); 3688c2ecf20Sopenharmony_ci i = j = n; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci default: /* USB_SPEED_FULL or _LOW */ 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * For low-speed, 10 ms is the official minimum. 3748c2ecf20Sopenharmony_ci * But some "overclocked" devices might want faster 3758c2ecf20Sopenharmony_ci * polling so we'll allow it. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci n = 10; 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci } else if (usb_endpoint_xfer_isoc(d)) { 3818c2ecf20Sopenharmony_ci i = 1; 3828c2ecf20Sopenharmony_ci j = 16; 3838c2ecf20Sopenharmony_ci switch (udev->speed) { 3848c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 3858c2ecf20Sopenharmony_ci n = 7; /* 8 ms = 2^(7-1) uframes */ 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci default: /* USB_SPEED_FULL */ 3888c2ecf20Sopenharmony_ci n = 4; /* 8 ms = 2^(4-1) frames */ 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci if (d->bInterval < i || d->bInterval > j) { 3938c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d " 3948c2ecf20Sopenharmony_ci "endpoint 0x%X has an invalid bInterval %d, " 3958c2ecf20Sopenharmony_ci "changing to %d\n", 3968c2ecf20Sopenharmony_ci cfgno, inum, asnum, 3978c2ecf20Sopenharmony_ci d->bEndpointAddress, d->bInterval, n); 3988c2ecf20Sopenharmony_ci endpoint->desc.bInterval = n; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Some buggy low-speed devices have Bulk endpoints, which is 4028c2ecf20Sopenharmony_ci * explicitly forbidden by the USB spec. In an attempt to make 4038c2ecf20Sopenharmony_ci * them usable, we will try treating them as Interrupt endpoints. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ci if (udev->speed == USB_SPEED_LOW && usb_endpoint_xfer_bulk(d)) { 4068c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d " 4078c2ecf20Sopenharmony_ci "endpoint 0x%X is Bulk; changing to Interrupt\n", 4088c2ecf20Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress); 4098c2ecf20Sopenharmony_ci endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT; 4108c2ecf20Sopenharmony_ci endpoint->desc.bInterval = 1; 4118c2ecf20Sopenharmony_ci if (usb_endpoint_maxp(&endpoint->desc) > 8) 4128c2ecf20Sopenharmony_ci endpoint->desc.wMaxPacketSize = cpu_to_le16(8); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* 4168c2ecf20Sopenharmony_ci * Validate the wMaxPacketSize field. 4178c2ecf20Sopenharmony_ci * Some devices have isochronous endpoints in altsetting 0; 4188c2ecf20Sopenharmony_ci * the USB-2 spec requires such endpoints to have wMaxPacketSize = 0 4198c2ecf20Sopenharmony_ci * (see the end of section 5.6.3), so don't warn about them. 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize); 4228c2ecf20Sopenharmony_ci if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) { 4238c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n", 4248c2ecf20Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Find the highest legal maxpacket size for this endpoint */ 4288c2ecf20Sopenharmony_ci i = 0; /* additional transactions per microframe */ 4298c2ecf20Sopenharmony_ci switch (udev->speed) { 4308c2ecf20Sopenharmony_ci case USB_SPEED_LOW: 4318c2ecf20Sopenharmony_ci maxpacket_maxes = low_speed_maxpacket_maxes; 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci case USB_SPEED_FULL: 4348c2ecf20Sopenharmony_ci maxpacket_maxes = full_speed_maxpacket_maxes; 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 4378c2ecf20Sopenharmony_ci /* Multiple-transactions bits are allowed only for HS periodic endpoints */ 4388c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) { 4398c2ecf20Sopenharmony_ci i = maxp & USB_EP_MAXP_MULT_MASK; 4408c2ecf20Sopenharmony_ci maxp &= ~i; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci fallthrough; 4438c2ecf20Sopenharmony_ci default: 4448c2ecf20Sopenharmony_ci maxpacket_maxes = high_speed_maxpacket_maxes; 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci case USB_SPEED_SUPER: 4478c2ecf20Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 4488c2ecf20Sopenharmony_ci maxpacket_maxes = super_speed_maxpacket_maxes; 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)]; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (maxp > j) { 4548c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n", 4558c2ecf20Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress, maxp, j); 4568c2ecf20Sopenharmony_ci maxp = j; 4578c2ecf20Sopenharmony_ci endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* 4618c2ecf20Sopenharmony_ci * Some buggy high speed devices have bulk endpoints using 4628c2ecf20Sopenharmony_ci * maxpacket sizes other than 512. High speed HCDs may not 4638c2ecf20Sopenharmony_ci * be able to handle that particular bug, so let's warn... 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) { 4668c2ecf20Sopenharmony_ci if (maxp != 512) 4678c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d " 4688c2ecf20Sopenharmony_ci "bulk endpoint 0x%X has invalid maxpacket %d\n", 4698c2ecf20Sopenharmony_ci cfgno, inum, asnum, d->bEndpointAddress, 4708c2ecf20Sopenharmony_ci maxp); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* Parse a possible SuperSpeed endpoint companion descriptor */ 4748c2ecf20Sopenharmony_ci if (udev->speed >= USB_SPEED_SUPER) 4758c2ecf20Sopenharmony_ci usb_parse_ss_endpoint_companion(ddev, cfgno, 4768c2ecf20Sopenharmony_ci inum, asnum, endpoint, buffer, size); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* Skip over any Class Specific or Vendor Specific descriptors; 4798c2ecf20Sopenharmony_ci * find the next endpoint or interface descriptor */ 4808c2ecf20Sopenharmony_ci endpoint->extra = buffer; 4818c2ecf20Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 4828c2ecf20Sopenharmony_ci USB_DT_INTERFACE, &n); 4838c2ecf20Sopenharmony_ci endpoint->extralen = i; 4848c2ecf20Sopenharmony_ci retval = buffer - buffer0 + i; 4858c2ecf20Sopenharmony_ci if (n > 0) 4868c2ecf20Sopenharmony_ci dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 4878c2ecf20Sopenharmony_ci n, plural(n), "endpoint"); 4888c2ecf20Sopenharmony_ci return retval; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ciskip_to_next_endpoint_or_interface_descriptor: 4918c2ecf20Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 4928c2ecf20Sopenharmony_ci USB_DT_INTERFACE, NULL); 4938c2ecf20Sopenharmony_ci return buffer - buffer0 + i; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_civoid usb_release_interface_cache(struct kref *ref) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); 4998c2ecf20Sopenharmony_ci int j; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci for (j = 0; j < intfc->num_altsetting; j++) { 5028c2ecf20Sopenharmony_ci struct usb_host_interface *alt = &intfc->altsetting[j]; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci kfree(alt->endpoint); 5058c2ecf20Sopenharmony_ci kfree(alt->string); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci kfree(intfc); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int usb_parse_interface(struct device *ddev, int cfgno, 5118c2ecf20Sopenharmony_ci struct usb_host_config *config, unsigned char *buffer, int size, 5128c2ecf20Sopenharmony_ci u8 inums[], u8 nalts[]) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci unsigned char *buffer0 = buffer; 5158c2ecf20Sopenharmony_ci struct usb_interface_descriptor *d; 5168c2ecf20Sopenharmony_ci int inum, asnum; 5178c2ecf20Sopenharmony_ci struct usb_interface_cache *intfc; 5188c2ecf20Sopenharmony_ci struct usb_host_interface *alt; 5198c2ecf20Sopenharmony_ci int i, n; 5208c2ecf20Sopenharmony_ci int len, retval; 5218c2ecf20Sopenharmony_ci int num_ep, num_ep_orig; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci d = (struct usb_interface_descriptor *) buffer; 5248c2ecf20Sopenharmony_ci buffer += d->bLength; 5258c2ecf20Sopenharmony_ci size -= d->bLength; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (d->bLength < USB_DT_INTERFACE_SIZE) 5288c2ecf20Sopenharmony_ci goto skip_to_next_interface_descriptor; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* Which interface entry is this? */ 5318c2ecf20Sopenharmony_ci intfc = NULL; 5328c2ecf20Sopenharmony_ci inum = d->bInterfaceNumber; 5338c2ecf20Sopenharmony_ci for (i = 0; i < config->desc.bNumInterfaces; ++i) { 5348c2ecf20Sopenharmony_ci if (inums[i] == inum) { 5358c2ecf20Sopenharmony_ci intfc = config->intf_cache[i]; 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci if (!intfc || intfc->num_altsetting >= nalts[i]) 5408c2ecf20Sopenharmony_ci goto skip_to_next_interface_descriptor; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* Check for duplicate altsetting entries */ 5438c2ecf20Sopenharmony_ci asnum = d->bAlternateSetting; 5448c2ecf20Sopenharmony_ci for ((i = 0, alt = &intfc->altsetting[0]); 5458c2ecf20Sopenharmony_ci i < intfc->num_altsetting; 5468c2ecf20Sopenharmony_ci (++i, ++alt)) { 5478c2ecf20Sopenharmony_ci if (alt->desc.bAlternateSetting == asnum) { 5488c2ecf20Sopenharmony_ci dev_notice(ddev, "Duplicate descriptor for config %d " 5498c2ecf20Sopenharmony_ci "interface %d altsetting %d, skipping\n", 5508c2ecf20Sopenharmony_ci cfgno, inum, asnum); 5518c2ecf20Sopenharmony_ci goto skip_to_next_interface_descriptor; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci ++intfc->num_altsetting; 5568c2ecf20Sopenharmony_ci memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* Skip over any Class Specific or Vendor Specific descriptors; 5598c2ecf20Sopenharmony_ci * find the first endpoint or interface descriptor */ 5608c2ecf20Sopenharmony_ci alt->extra = buffer; 5618c2ecf20Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 5628c2ecf20Sopenharmony_ci USB_DT_INTERFACE, &n); 5638c2ecf20Sopenharmony_ci alt->extralen = i; 5648c2ecf20Sopenharmony_ci if (n > 0) 5658c2ecf20Sopenharmony_ci dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 5668c2ecf20Sopenharmony_ci n, plural(n), "interface"); 5678c2ecf20Sopenharmony_ci buffer += i; 5688c2ecf20Sopenharmony_ci size -= i; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* Allocate space for the right(?) number of endpoints */ 5718c2ecf20Sopenharmony_ci num_ep = num_ep_orig = alt->desc.bNumEndpoints; 5728c2ecf20Sopenharmony_ci alt->desc.bNumEndpoints = 0; /* Use as a counter */ 5738c2ecf20Sopenharmony_ci if (num_ep > USB_MAXENDPOINTS) { 5748c2ecf20Sopenharmony_ci dev_notice(ddev, "too many endpoints for config %d interface %d " 5758c2ecf20Sopenharmony_ci "altsetting %d: %d, using maximum allowed: %d\n", 5768c2ecf20Sopenharmony_ci cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS); 5778c2ecf20Sopenharmony_ci num_ep = USB_MAXENDPOINTS; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (num_ep > 0) { 5818c2ecf20Sopenharmony_ci /* Can't allocate 0 bytes */ 5828c2ecf20Sopenharmony_ci len = sizeof(struct usb_host_endpoint) * num_ep; 5838c2ecf20Sopenharmony_ci alt->endpoint = kzalloc(len, GFP_KERNEL); 5848c2ecf20Sopenharmony_ci if (!alt->endpoint) 5858c2ecf20Sopenharmony_ci return -ENOMEM; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Parse all the endpoint descriptors */ 5898c2ecf20Sopenharmony_ci n = 0; 5908c2ecf20Sopenharmony_ci while (size > 0) { 5918c2ecf20Sopenharmony_ci if (((struct usb_descriptor_header *) buffer)->bDescriptorType 5928c2ecf20Sopenharmony_ci == USB_DT_INTERFACE) 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum, 5958c2ecf20Sopenharmony_ci alt, num_ep, buffer, size); 5968c2ecf20Sopenharmony_ci if (retval < 0) 5978c2ecf20Sopenharmony_ci return retval; 5988c2ecf20Sopenharmony_ci ++n; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci buffer += retval; 6018c2ecf20Sopenharmony_ci size -= retval; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (n != num_ep_orig) 6058c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d altsetting %d has %d " 6068c2ecf20Sopenharmony_ci "endpoint descriptor%s, different from the interface " 6078c2ecf20Sopenharmony_ci "descriptor's value: %d\n", 6088c2ecf20Sopenharmony_ci cfgno, inum, asnum, n, plural(n), num_ep_orig); 6098c2ecf20Sopenharmony_ci return buffer - buffer0; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ciskip_to_next_interface_descriptor: 6128c2ecf20Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, 6138c2ecf20Sopenharmony_ci USB_DT_INTERFACE, NULL); 6148c2ecf20Sopenharmony_ci return buffer - buffer0 + i; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int usb_parse_configuration(struct usb_device *dev, int cfgidx, 6188c2ecf20Sopenharmony_ci struct usb_host_config *config, unsigned char *buffer, int size) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct device *ddev = &dev->dev; 6218c2ecf20Sopenharmony_ci unsigned char *buffer0 = buffer; 6228c2ecf20Sopenharmony_ci int cfgno; 6238c2ecf20Sopenharmony_ci int nintf, nintf_orig; 6248c2ecf20Sopenharmony_ci int i, j, n; 6258c2ecf20Sopenharmony_ci struct usb_interface_cache *intfc; 6268c2ecf20Sopenharmony_ci unsigned char *buffer2; 6278c2ecf20Sopenharmony_ci int size2; 6288c2ecf20Sopenharmony_ci struct usb_descriptor_header *header; 6298c2ecf20Sopenharmony_ci int retval; 6308c2ecf20Sopenharmony_ci u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES]; 6318c2ecf20Sopenharmony_ci unsigned iad_num = 0; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); 6348c2ecf20Sopenharmony_ci nintf = nintf_orig = config->desc.bNumInterfaces; 6358c2ecf20Sopenharmony_ci config->desc.bNumInterfaces = 0; // Adjusted later 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (config->desc.bDescriptorType != USB_DT_CONFIG || 6388c2ecf20Sopenharmony_ci config->desc.bLength < USB_DT_CONFIG_SIZE || 6398c2ecf20Sopenharmony_ci config->desc.bLength > size) { 6408c2ecf20Sopenharmony_ci dev_notice(ddev, "invalid descriptor for config index %d: " 6418c2ecf20Sopenharmony_ci "type = 0x%X, length = %d\n", cfgidx, 6428c2ecf20Sopenharmony_ci config->desc.bDescriptorType, config->desc.bLength); 6438c2ecf20Sopenharmony_ci return -EINVAL; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci cfgno = config->desc.bConfigurationValue; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci buffer += config->desc.bLength; 6488c2ecf20Sopenharmony_ci size -= config->desc.bLength; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (nintf > USB_MAXINTERFACES) { 6518c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d has too many interfaces: %d, " 6528c2ecf20Sopenharmony_ci "using maximum allowed: %d\n", 6538c2ecf20Sopenharmony_ci cfgno, nintf, USB_MAXINTERFACES); 6548c2ecf20Sopenharmony_ci nintf = USB_MAXINTERFACES; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* Go through the descriptors, checking their length and counting the 6588c2ecf20Sopenharmony_ci * number of altsettings for each interface */ 6598c2ecf20Sopenharmony_ci n = 0; 6608c2ecf20Sopenharmony_ci for ((buffer2 = buffer, size2 = size); 6618c2ecf20Sopenharmony_ci size2 > 0; 6628c2ecf20Sopenharmony_ci (buffer2 += header->bLength, size2 -= header->bLength)) { 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (size2 < sizeof(struct usb_descriptor_header)) { 6658c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d descriptor has %d excess " 6668c2ecf20Sopenharmony_ci "byte%s, ignoring\n", 6678c2ecf20Sopenharmony_ci cfgno, size2, plural(size2)); 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci header = (struct usb_descriptor_header *) buffer2; 6728c2ecf20Sopenharmony_ci if ((header->bLength > size2) || (header->bLength < 2)) { 6738c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d has an invalid descriptor " 6748c2ecf20Sopenharmony_ci "of length %d, skipping remainder of the config\n", 6758c2ecf20Sopenharmony_ci cfgno, header->bLength); 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (header->bDescriptorType == USB_DT_INTERFACE) { 6808c2ecf20Sopenharmony_ci struct usb_interface_descriptor *d; 6818c2ecf20Sopenharmony_ci int inum; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci d = (struct usb_interface_descriptor *) header; 6848c2ecf20Sopenharmony_ci if (d->bLength < USB_DT_INTERFACE_SIZE) { 6858c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d has an invalid " 6868c2ecf20Sopenharmony_ci "interface descriptor of length %d, " 6878c2ecf20Sopenharmony_ci "skipping\n", cfgno, d->bLength); 6888c2ecf20Sopenharmony_ci continue; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci inum = d->bInterfaceNumber; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) && 6948c2ecf20Sopenharmony_ci n >= nintf_orig) { 6958c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d has more interface " 6968c2ecf20Sopenharmony_ci "descriptors, than it declares in " 6978c2ecf20Sopenharmony_ci "bNumInterfaces, ignoring interface " 6988c2ecf20Sopenharmony_ci "number: %d\n", cfgno, inum); 6998c2ecf20Sopenharmony_ci continue; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (inum >= nintf_orig) 7038c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d has an invalid " 7048c2ecf20Sopenharmony_ci "interface number: %d but max is %d\n", 7058c2ecf20Sopenharmony_ci cfgno, inum, nintf_orig - 1); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Have we already encountered this interface? 7088c2ecf20Sopenharmony_ci * Count its altsettings */ 7098c2ecf20Sopenharmony_ci for (i = 0; i < n; ++i) { 7108c2ecf20Sopenharmony_ci if (inums[i] == inum) 7118c2ecf20Sopenharmony_ci break; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci if (i < n) { 7148c2ecf20Sopenharmony_ci if (nalts[i] < 255) 7158c2ecf20Sopenharmony_ci ++nalts[i]; 7168c2ecf20Sopenharmony_ci } else if (n < USB_MAXINTERFACES) { 7178c2ecf20Sopenharmony_ci inums[n] = inum; 7188c2ecf20Sopenharmony_ci nalts[n] = 1; 7198c2ecf20Sopenharmony_ci ++n; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci } else if (header->bDescriptorType == 7238c2ecf20Sopenharmony_ci USB_DT_INTERFACE_ASSOCIATION) { 7248c2ecf20Sopenharmony_ci struct usb_interface_assoc_descriptor *d; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci d = (struct usb_interface_assoc_descriptor *)header; 7278c2ecf20Sopenharmony_ci if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) { 7288c2ecf20Sopenharmony_ci dev_notice(ddev, 7298c2ecf20Sopenharmony_ci "config %d has an invalid interface association descriptor of length %d, skipping\n", 7308c2ecf20Sopenharmony_ci cfgno, d->bLength); 7318c2ecf20Sopenharmony_ci continue; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (iad_num == USB_MAXIADS) { 7358c2ecf20Sopenharmony_ci dev_notice(ddev, "found more Interface " 7368c2ecf20Sopenharmony_ci "Association Descriptors " 7378c2ecf20Sopenharmony_ci "than allocated for in " 7388c2ecf20Sopenharmony_ci "configuration %d\n", cfgno); 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci config->intf_assoc[iad_num] = d; 7418c2ecf20Sopenharmony_ci iad_num++; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci } else if (header->bDescriptorType == USB_DT_DEVICE || 7458c2ecf20Sopenharmony_ci header->bDescriptorType == USB_DT_CONFIG) 7468c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d contains an unexpected " 7478c2ecf20Sopenharmony_ci "descriptor of type 0x%X, skipping\n", 7488c2ecf20Sopenharmony_ci cfgno, header->bDescriptorType); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci } /* for ((buffer2 = buffer, size2 = size); ...) */ 7518c2ecf20Sopenharmony_ci size = buffer2 - buffer; 7528c2ecf20Sopenharmony_ci config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (n != nintf) 7558c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d has %d interface%s, different from " 7568c2ecf20Sopenharmony_ci "the descriptor's value: %d\n", 7578c2ecf20Sopenharmony_ci cfgno, n, plural(n), nintf_orig); 7588c2ecf20Sopenharmony_ci else if (n == 0) 7598c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d has no interfaces?\n", cfgno); 7608c2ecf20Sopenharmony_ci config->desc.bNumInterfaces = nintf = n; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* Check for missing interface numbers */ 7638c2ecf20Sopenharmony_ci for (i = 0; i < nintf; ++i) { 7648c2ecf20Sopenharmony_ci for (j = 0; j < nintf; ++j) { 7658c2ecf20Sopenharmony_ci if (inums[j] == i) 7668c2ecf20Sopenharmony_ci break; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci if (j >= nintf) 7698c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d has no interface number " 7708c2ecf20Sopenharmony_ci "%d\n", cfgno, i); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* Allocate the usb_interface_caches and altsetting arrays */ 7748c2ecf20Sopenharmony_ci for (i = 0; i < nintf; ++i) { 7758c2ecf20Sopenharmony_ci j = nalts[i]; 7768c2ecf20Sopenharmony_ci if (j > USB_MAXALTSETTING) { 7778c2ecf20Sopenharmony_ci dev_notice(ddev, "too many alternate settings for " 7788c2ecf20Sopenharmony_ci "config %d interface %d: %d, " 7798c2ecf20Sopenharmony_ci "using maximum allowed: %d\n", 7808c2ecf20Sopenharmony_ci cfgno, inums[i], j, USB_MAXALTSETTING); 7818c2ecf20Sopenharmony_ci nalts[i] = j = USB_MAXALTSETTING; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci intfc = kzalloc(struct_size(intfc, altsetting, j), GFP_KERNEL); 7858c2ecf20Sopenharmony_ci config->intf_cache[i] = intfc; 7868c2ecf20Sopenharmony_ci if (!intfc) 7878c2ecf20Sopenharmony_ci return -ENOMEM; 7888c2ecf20Sopenharmony_ci kref_init(&intfc->ref); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* FIXME: parse the BOS descriptor */ 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* Skip over any Class Specific or Vendor Specific descriptors; 7948c2ecf20Sopenharmony_ci * find the first interface descriptor */ 7958c2ecf20Sopenharmony_ci config->extra = buffer; 7968c2ecf20Sopenharmony_ci i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, 7978c2ecf20Sopenharmony_ci USB_DT_INTERFACE, &n); 7988c2ecf20Sopenharmony_ci config->extralen = i; 7998c2ecf20Sopenharmony_ci if (n > 0) 8008c2ecf20Sopenharmony_ci dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 8018c2ecf20Sopenharmony_ci n, plural(n), "configuration"); 8028c2ecf20Sopenharmony_ci buffer += i; 8038c2ecf20Sopenharmony_ci size -= i; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* Parse all the interface/altsetting descriptors */ 8068c2ecf20Sopenharmony_ci while (size > 0) { 8078c2ecf20Sopenharmony_ci retval = usb_parse_interface(ddev, cfgno, config, 8088c2ecf20Sopenharmony_ci buffer, size, inums, nalts); 8098c2ecf20Sopenharmony_ci if (retval < 0) 8108c2ecf20Sopenharmony_ci return retval; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci buffer += retval; 8138c2ecf20Sopenharmony_ci size -= retval; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* Check for missing altsettings */ 8178c2ecf20Sopenharmony_ci for (i = 0; i < nintf; ++i) { 8188c2ecf20Sopenharmony_ci intfc = config->intf_cache[i]; 8198c2ecf20Sopenharmony_ci for (j = 0; j < intfc->num_altsetting; ++j) { 8208c2ecf20Sopenharmony_ci for (n = 0; n < intfc->num_altsetting; ++n) { 8218c2ecf20Sopenharmony_ci if (intfc->altsetting[n].desc. 8228c2ecf20Sopenharmony_ci bAlternateSetting == j) 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci if (n >= intfc->num_altsetting) 8268c2ecf20Sopenharmony_ci dev_notice(ddev, "config %d interface %d has no " 8278c2ecf20Sopenharmony_ci "altsetting %d\n", cfgno, inums[i], j); 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci/* hub-only!! ... and only exported for reset/reinit path. 8358c2ecf20Sopenharmony_ci * otherwise used internally on disconnect/destroy path 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_civoid usb_destroy_configuration(struct usb_device *dev) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci int c, i; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (!dev->config) 8428c2ecf20Sopenharmony_ci return; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (dev->rawdescriptors) { 8458c2ecf20Sopenharmony_ci for (i = 0; i < dev->descriptor.bNumConfigurations; i++) 8468c2ecf20Sopenharmony_ci kfree(dev->rawdescriptors[i]); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci kfree(dev->rawdescriptors); 8498c2ecf20Sopenharmony_ci dev->rawdescriptors = NULL; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { 8538c2ecf20Sopenharmony_ci struct usb_host_config *cf = &dev->config[c]; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci kfree(cf->string); 8568c2ecf20Sopenharmony_ci for (i = 0; i < cf->desc.bNumInterfaces; i++) { 8578c2ecf20Sopenharmony_ci if (cf->intf_cache[i]) 8588c2ecf20Sopenharmony_ci kref_put(&cf->intf_cache[i]->ref, 8598c2ecf20Sopenharmony_ci usb_release_interface_cache); 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci kfree(dev->config); 8638c2ecf20Sopenharmony_ci dev->config = NULL; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci/* 8688c2ecf20Sopenharmony_ci * Get the USB config descriptors, cache and parse'em 8698c2ecf20Sopenharmony_ci * 8708c2ecf20Sopenharmony_ci * hub-only!! ... and only in reset path, or usb_new_device() 8718c2ecf20Sopenharmony_ci * (used by real hubs and virtual root hubs) 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_ciint usb_get_configuration(struct usb_device *dev) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct device *ddev = &dev->dev; 8768c2ecf20Sopenharmony_ci int ncfg = dev->descriptor.bNumConfigurations; 8778c2ecf20Sopenharmony_ci unsigned int cfgno, length; 8788c2ecf20Sopenharmony_ci unsigned char *bigbuffer; 8798c2ecf20Sopenharmony_ci struct usb_config_descriptor *desc; 8808c2ecf20Sopenharmony_ci int result; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (ncfg > USB_MAXCONFIG) { 8838c2ecf20Sopenharmony_ci dev_notice(ddev, "too many configurations: %d, " 8848c2ecf20Sopenharmony_ci "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); 8858c2ecf20Sopenharmony_ci dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (ncfg < 1) { 8898c2ecf20Sopenharmony_ci dev_err(ddev, "no configurations\n"); 8908c2ecf20Sopenharmony_ci return -EINVAL; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci length = ncfg * sizeof(struct usb_host_config); 8948c2ecf20Sopenharmony_ci dev->config = kzalloc(length, GFP_KERNEL); 8958c2ecf20Sopenharmony_ci if (!dev->config) 8968c2ecf20Sopenharmony_ci return -ENOMEM; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci length = ncfg * sizeof(char *); 8998c2ecf20Sopenharmony_ci dev->rawdescriptors = kzalloc(length, GFP_KERNEL); 9008c2ecf20Sopenharmony_ci if (!dev->rawdescriptors) 9018c2ecf20Sopenharmony_ci return -ENOMEM; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); 9048c2ecf20Sopenharmony_ci if (!desc) 9058c2ecf20Sopenharmony_ci return -ENOMEM; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci for (cfgno = 0; cfgno < ncfg; cfgno++) { 9088c2ecf20Sopenharmony_ci /* We grab just the first descriptor so we know how long 9098c2ecf20Sopenharmony_ci * the whole configuration is */ 9108c2ecf20Sopenharmony_ci result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, 9118c2ecf20Sopenharmony_ci desc, USB_DT_CONFIG_SIZE); 9128c2ecf20Sopenharmony_ci if (result < 0) { 9138c2ecf20Sopenharmony_ci dev_err(ddev, "unable to read config index %d " 9148c2ecf20Sopenharmony_ci "descriptor/%s: %d\n", cfgno, "start", result); 9158c2ecf20Sopenharmony_ci if (result != -EPIPE) 9168c2ecf20Sopenharmony_ci goto err; 9178c2ecf20Sopenharmony_ci dev_notice(ddev, "chopping to %d config(s)\n", cfgno); 9188c2ecf20Sopenharmony_ci dev->descriptor.bNumConfigurations = cfgno; 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci } else if (result < 4) { 9218c2ecf20Sopenharmony_ci dev_err(ddev, "config index %d descriptor too short " 9228c2ecf20Sopenharmony_ci "(expected %i, got %i)\n", cfgno, 9238c2ecf20Sopenharmony_ci USB_DT_CONFIG_SIZE, result); 9248c2ecf20Sopenharmony_ci result = -EINVAL; 9258c2ecf20Sopenharmony_ci goto err; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci length = max((int) le16_to_cpu(desc->wTotalLength), 9288c2ecf20Sopenharmony_ci USB_DT_CONFIG_SIZE); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* Now that we know the length, get the whole thing */ 9318c2ecf20Sopenharmony_ci bigbuffer = kmalloc(length, GFP_KERNEL); 9328c2ecf20Sopenharmony_ci if (!bigbuffer) { 9338c2ecf20Sopenharmony_ci result = -ENOMEM; 9348c2ecf20Sopenharmony_ci goto err; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (dev->quirks & USB_QUIRK_DELAY_INIT) 9388c2ecf20Sopenharmony_ci msleep(200); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, 9418c2ecf20Sopenharmony_ci bigbuffer, length); 9428c2ecf20Sopenharmony_ci if (result < 0) { 9438c2ecf20Sopenharmony_ci dev_err(ddev, "unable to read config index %d " 9448c2ecf20Sopenharmony_ci "descriptor/%s\n", cfgno, "all"); 9458c2ecf20Sopenharmony_ci kfree(bigbuffer); 9468c2ecf20Sopenharmony_ci goto err; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci if (result < length) { 9498c2ecf20Sopenharmony_ci dev_notice(ddev, "config index %d descriptor too short " 9508c2ecf20Sopenharmony_ci "(expected %i, got %i)\n", cfgno, length, result); 9518c2ecf20Sopenharmony_ci length = result; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci dev->rawdescriptors[cfgno] = bigbuffer; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci result = usb_parse_configuration(dev, cfgno, 9578c2ecf20Sopenharmony_ci &dev->config[cfgno], bigbuffer, length); 9588c2ecf20Sopenharmony_ci if (result < 0) { 9598c2ecf20Sopenharmony_ci ++cfgno; 9608c2ecf20Sopenharmony_ci goto err; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cierr: 9658c2ecf20Sopenharmony_ci kfree(desc); 9668c2ecf20Sopenharmony_ci dev->descriptor.bNumConfigurations = cfgno; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return result; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_civoid usb_release_bos_descriptor(struct usb_device *dev) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci if (dev->bos) { 9748c2ecf20Sopenharmony_ci kfree(dev->bos->desc); 9758c2ecf20Sopenharmony_ci kfree(dev->bos); 9768c2ecf20Sopenharmony_ci dev->bos = NULL; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic const __u8 bos_desc_len[256] = { 9818c2ecf20Sopenharmony_ci [USB_CAP_TYPE_WIRELESS_USB] = USB_DT_USB_WIRELESS_CAP_SIZE, 9828c2ecf20Sopenharmony_ci [USB_CAP_TYPE_EXT] = USB_DT_USB_EXT_CAP_SIZE, 9838c2ecf20Sopenharmony_ci [USB_SS_CAP_TYPE] = USB_DT_USB_SS_CAP_SIZE, 9848c2ecf20Sopenharmony_ci [USB_SSP_CAP_TYPE] = USB_DT_USB_SSP_CAP_SIZE(1), 9858c2ecf20Sopenharmony_ci [CONTAINER_ID_TYPE] = USB_DT_USB_SS_CONTN_ID_SIZE, 9868c2ecf20Sopenharmony_ci [USB_PTM_CAP_TYPE] = USB_DT_USB_PTM_ID_SIZE, 9878c2ecf20Sopenharmony_ci}; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci/* Get BOS descriptor set */ 9908c2ecf20Sopenharmony_ciint usb_get_bos_descriptor(struct usb_device *dev) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct device *ddev = &dev->dev; 9938c2ecf20Sopenharmony_ci struct usb_bos_descriptor *bos; 9948c2ecf20Sopenharmony_ci struct usb_dev_cap_header *cap; 9958c2ecf20Sopenharmony_ci struct usb_ssp_cap_descriptor *ssp_cap; 9968c2ecf20Sopenharmony_ci unsigned char *buffer, *buffer0; 9978c2ecf20Sopenharmony_ci int length, total_len, num, i, ssac; 9988c2ecf20Sopenharmony_ci __u8 cap_type; 9998c2ecf20Sopenharmony_ci int ret; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL); 10028c2ecf20Sopenharmony_ci if (!bos) 10038c2ecf20Sopenharmony_ci return -ENOMEM; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* Get BOS descriptor */ 10068c2ecf20Sopenharmony_ci ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE); 10078c2ecf20Sopenharmony_ci if (ret < USB_DT_BOS_SIZE || bos->bLength < USB_DT_BOS_SIZE) { 10088c2ecf20Sopenharmony_ci dev_notice(ddev, "unable to get BOS descriptor or descriptor too short\n"); 10098c2ecf20Sopenharmony_ci if (ret >= 0) 10108c2ecf20Sopenharmony_ci ret = -ENOMSG; 10118c2ecf20Sopenharmony_ci kfree(bos); 10128c2ecf20Sopenharmony_ci return ret; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci length = bos->bLength; 10168c2ecf20Sopenharmony_ci total_len = le16_to_cpu(bos->wTotalLength); 10178c2ecf20Sopenharmony_ci num = bos->bNumDeviceCaps; 10188c2ecf20Sopenharmony_ci kfree(bos); 10198c2ecf20Sopenharmony_ci if (total_len < length) 10208c2ecf20Sopenharmony_ci return -EINVAL; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL); 10238c2ecf20Sopenharmony_ci if (!dev->bos) 10248c2ecf20Sopenharmony_ci return -ENOMEM; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* Now let's get the whole BOS descriptor set */ 10278c2ecf20Sopenharmony_ci buffer = kzalloc(total_len, GFP_KERNEL); 10288c2ecf20Sopenharmony_ci if (!buffer) { 10298c2ecf20Sopenharmony_ci ret = -ENOMEM; 10308c2ecf20Sopenharmony_ci goto err; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci dev->bos->desc = (struct usb_bos_descriptor *)buffer; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len); 10358c2ecf20Sopenharmony_ci if (ret < total_len) { 10368c2ecf20Sopenharmony_ci dev_notice(ddev, "unable to get BOS descriptor set\n"); 10378c2ecf20Sopenharmony_ci if (ret >= 0) 10388c2ecf20Sopenharmony_ci ret = -ENOMSG; 10398c2ecf20Sopenharmony_ci goto err; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci buffer0 = buffer; 10438c2ecf20Sopenharmony_ci total_len -= length; 10448c2ecf20Sopenharmony_ci buffer += length; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 10478c2ecf20Sopenharmony_ci cap = (struct usb_dev_cap_header *)buffer; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (total_len < sizeof(*cap) || total_len < cap->bLength) { 10508c2ecf20Sopenharmony_ci dev->bos->desc->bNumDeviceCaps = i; 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci cap_type = cap->bDevCapabilityType; 10548c2ecf20Sopenharmony_ci length = cap->bLength; 10558c2ecf20Sopenharmony_ci if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) { 10568c2ecf20Sopenharmony_ci dev->bos->desc->bNumDeviceCaps = i; 10578c2ecf20Sopenharmony_ci break; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { 10618c2ecf20Sopenharmony_ci dev_notice(ddev, "descriptor type invalid, skip\n"); 10628c2ecf20Sopenharmony_ci goto skip_to_next_descriptor; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci switch (cap_type) { 10668c2ecf20Sopenharmony_ci case USB_CAP_TYPE_WIRELESS_USB: 10678c2ecf20Sopenharmony_ci /* Wireless USB cap descriptor is handled by wusb */ 10688c2ecf20Sopenharmony_ci break; 10698c2ecf20Sopenharmony_ci case USB_CAP_TYPE_EXT: 10708c2ecf20Sopenharmony_ci dev->bos->ext_cap = 10718c2ecf20Sopenharmony_ci (struct usb_ext_cap_descriptor *)buffer; 10728c2ecf20Sopenharmony_ci break; 10738c2ecf20Sopenharmony_ci case USB_SS_CAP_TYPE: 10748c2ecf20Sopenharmony_ci dev->bos->ss_cap = 10758c2ecf20Sopenharmony_ci (struct usb_ss_cap_descriptor *)buffer; 10768c2ecf20Sopenharmony_ci break; 10778c2ecf20Sopenharmony_ci case USB_SSP_CAP_TYPE: 10788c2ecf20Sopenharmony_ci ssp_cap = (struct usb_ssp_cap_descriptor *)buffer; 10798c2ecf20Sopenharmony_ci ssac = (le32_to_cpu(ssp_cap->bmAttributes) & 10808c2ecf20Sopenharmony_ci USB_SSP_SUBLINK_SPEED_ATTRIBS); 10818c2ecf20Sopenharmony_ci if (length >= USB_DT_USB_SSP_CAP_SIZE(ssac)) 10828c2ecf20Sopenharmony_ci dev->bos->ssp_cap = ssp_cap; 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case CONTAINER_ID_TYPE: 10858c2ecf20Sopenharmony_ci dev->bos->ss_id = 10868c2ecf20Sopenharmony_ci (struct usb_ss_container_id_descriptor *)buffer; 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci case USB_PTM_CAP_TYPE: 10898c2ecf20Sopenharmony_ci dev->bos->ptm_cap = 10908c2ecf20Sopenharmony_ci (struct usb_ptm_cap_descriptor *)buffer; 10918c2ecf20Sopenharmony_ci default: 10928c2ecf20Sopenharmony_ci break; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ciskip_to_next_descriptor: 10968c2ecf20Sopenharmony_ci total_len -= length; 10978c2ecf20Sopenharmony_ci buffer += length; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci dev->bos->desc->wTotalLength = cpu_to_le16(buffer - buffer0); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci return 0; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cierr: 11048c2ecf20Sopenharmony_ci usb_release_bos_descriptor(dev); 11058c2ecf20Sopenharmony_ci return ret; 11068c2ecf20Sopenharmony_ci} 1107