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