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