staticint find_next_descriptor(unsignedchar *buffer, int size, int dt1, int dt2, int *num_skipped)
{ struct usb_descriptor_header *h; int n = 0; unsignedchar *buffer0 = buffer;
/* Find the next descriptor of type dt1 or dt2 */ while (size > 0) {
h = (struct usb_descriptor_header *) buffer; if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2) break;
buffer += h->bLength;
size -= h->bLength;
++n;
}
/* Store the number of descriptors skipped and return the
* number of bytes skipped */ if (num_skipped)
*num_skipped = n; return buffer - buffer0;
}
staticvoid usb_parse_ssp_isoc_endpoint_companion(struct device *ddev, int cfgno, int inum, int asnum, struct usb_host_endpoint *ep, unsignedchar *buffer, int size)
{ struct usb_ssp_isoc_ep_comp_descriptor *desc;
staticvoid usb_parse_eusb2_isoc_endpoint_companion(struct device *ddev, int cfgno, int inum, int asnum, struct usb_host_endpoint *ep, unsignedchar *buffer, int size)
{ struct usb_eusb2_isoc_ep_comp_descriptor *desc; struct usb_descriptor_header *h;
/* * eUSB2 isochronous endpoint companion descriptor for this endpoint * shall be declared before the next endpoint or interface descriptor
*/ while (size >= USB_DT_EUSB2_ISOC_EP_COMP_SIZE) {
h = (struct usb_descriptor_header *)buffer;
dev_notice(ddev, "No eUSB2 isoc ep %d companion for config %d interface %d altsetting %d\n",
ep->desc.bEndpointAddress, cfgno, inum, asnum);
}
staticvoid usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, int inum, int asnum, struct usb_host_endpoint *ep, unsignedchar *buffer, int size)
{ struct usb_ss_ep_comp_descriptor *desc; int max_tx;
/* The SuperSpeed endpoint companion descriptor is supposed to * be the first thing immediately following the endpoint descriptor.
*/
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
dev_notice(ddev, "No SuperSpeed endpoint companion for config %d " " interface %d altsetting %d ep %d: " "using minimum values\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
/* Fill in some default values. * Leave bmAttributes as zero, which will mean no streams for * bulk, and isoc won't support multiple bursts of packets. * With bursts of only one packet, and a Mult of 1, the max * amount of data moved per endpoint service interval is one * packet.
*/
ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE;
ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; if (usb_endpoint_xfer_isoc(&ep->desc) ||
usb_endpoint_xfer_int(&ep->desc))
ep->ss_ep_comp.wBytesPerInterval =
ep->desc.wMaxPacketSize; return;
}
buffer += desc->bLength;
size -= desc->bLength;
memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE);
/* Check the various values */ if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
dev_notice(ddev, "Control endpoint with bMaxBurst = %d in " "config %d interface %d altsetting %d ep %d: " "setting to zero\n", desc->bMaxBurst,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bMaxBurst = 0;
} elseif (desc->bMaxBurst > 15) {
dev_notice(ddev, "Endpoint with bMaxBurst = %d in " "config %d interface %d altsetting %d ep %d: " "setting to 15\n", desc->bMaxBurst,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bMaxBurst = 15;
}
if ((usb_endpoint_xfer_control(&ep->desc) ||
usb_endpoint_xfer_int(&ep->desc)) &&
desc->bmAttributes != 0) {
dev_notice(ddev, "%s endpoint with bmAttributes = %d in " "config %d interface %d altsetting %d ep %d: " "setting to zero\n",
usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
desc->bmAttributes,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bmAttributes = 0;
} elseif (usb_endpoint_xfer_bulk(&ep->desc) &&
desc->bmAttributes > 16) {
dev_notice(ddev, "Bulk endpoint with more than 65536 streams in " "config %d interface %d altsetting %d ep %d: " "setting to max\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bmAttributes = 16;
} elseif (usb_endpoint_xfer_isoc(&ep->desc) &&
!USB_SS_SSP_ISOC_COMP(desc->bmAttributes) &&
USB_SS_MULT(desc->bmAttributes) > 3) {
dev_notice(ddev, "Isoc endpoint has Mult of %d in " "config %d interface %d altsetting %d ep %d: " "setting to 3\n",
USB_SS_MULT(desc->bmAttributes),
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bmAttributes = 2;
}
if (usb_endpoint_xfer_isoc(&ep->desc))
max_tx = (desc->bMaxBurst + 1) *
(USB_SS_MULT(desc->bmAttributes)) *
usb_endpoint_maxp(&ep->desc); elseif (usb_endpoint_xfer_int(&ep->desc))
max_tx = usb_endpoint_maxp(&ep->desc) *
(desc->bMaxBurst + 1); else
max_tx = 999999; if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
dev_notice(ddev, "%s endpoint with wBytesPerInterval of %d in " "config %d interface %d altsetting %d ep %d: " "setting to %d\n",
usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
le16_to_cpu(desc->wBytesPerInterval),
cfgno, inum, asnum, ep->desc.bEndpointAddress,
max_tx);
ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx);
} /* Parse a possible SuperSpeedPlus isoc ep companion descriptor */ if (usb_endpoint_xfer_isoc(&ep->desc) &&
USB_SS_SSP_ISOC_COMP(desc->bmAttributes))
usb_parse_ssp_isoc_endpoint_companion(ddev, cfgno, inum, asnum,
ep, buffer, size);
}
if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) { if (usb_endpoint_num(e1) == usb_endpoint_num(e2)) returntrue;
}
returnfalse;
}
/* * Check for duplicate endpoint addresses in other interfaces and in the * altsetting currently being parsed.
*/ staticbool config_endpoint_is_duplicate(struct usb_host_config *config, int inum, int asnum, struct usb_endpoint_descriptor *d)
{ struct usb_endpoint_descriptor *epd; struct usb_interface_cache *intfc; struct usb_host_interface *alt; int i, j, k;
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intfc = config->intf_cache[i];
for (j = 0; j < intfc->num_altsetting; ++j) {
alt = &intfc->altsetting[j];
if (alt->desc.bInterfaceNumber == inum &&
alt->desc.bAlternateSetting != asnum) continue;
for (k = 0; k < alt->desc.bNumEndpoints; ++k) {
epd = &alt->endpoint[k].desc;
if (endpoint_is_duplicate(epd, d)) returntrue;
}
}
}
returnfalse;
}
staticint usb_parse_endpoint(struct device *ddev, int cfgno, struct usb_host_config *config, int inum, int asnum, struct usb_host_interface *ifp, int num_ep, unsignedchar *buffer, int size)
{ struct usb_device *udev = to_usb_device(ddev); unsignedchar *buffer0 = buffer; struct usb_endpoint_descriptor *d; struct usb_host_endpoint *endpoint; int n, i, j, retval; unsignedint maxp; constunsignedshort *maxpacket_maxes;
u16 bcdUSB;
if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE)
n = USB_DT_ENDPOINT_AUDIO_SIZE; elseif (d->bLength >= USB_DT_ENDPOINT_SIZE)
n = USB_DT_ENDPOINT_SIZE; else {
dev_notice(ddev, "config %d interface %d altsetting %d has an " "invalid endpoint descriptor of length %d, skipping\n",
cfgno, inum, asnum, d->bLength); goto skip_to_next_endpoint_or_interface_descriptor;
}
i = usb_endpoint_num(d); if (i == 0) {
dev_notice(ddev, "config %d interface %d altsetting %d has an " "invalid descriptor for endpoint zero, skipping\n",
cfgno, inum, asnum); goto skip_to_next_endpoint_or_interface_descriptor;
}
/* Only store as many endpoints as we have room for */ if (ifp->desc.bNumEndpoints >= num_ep) goto skip_to_next_endpoint_or_interface_descriptor;
/* Save a copy of the descriptor and use it instead of the original */
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
memcpy(&endpoint->desc, d, n);
d = &endpoint->desc;
/* Clear the reserved bits in bEndpointAddress */
i = d->bEndpointAddress &
(USB_ENDPOINT_DIR_MASK | USB_ENDPOINT_NUMBER_MASK); if (i != d->bEndpointAddress) {
dev_notice(ddev, "config %d interface %d altsetting %d has an endpoint descriptor with address 0x%X, changing to 0x%X\n",
cfgno, inum, asnum, d->bEndpointAddress, i);
endpoint->desc.bEndpointAddress = i;
}
/* Check for duplicate endpoint addresses */ if (config_endpoint_is_duplicate(config, inum, asnum, d)) {
dev_notice(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum, d->bEndpointAddress); goto skip_to_next_endpoint_or_interface_descriptor;
}
/* Ignore some endpoints */ if (udev->quirks & USB_QUIRK_ENDPOINT_IGNORE) { if (usb_endpoint_is_ignored(udev, ifp, d)) {
dev_notice(ddev, "config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum,
d->bEndpointAddress); goto skip_to_next_endpoint_or_interface_descriptor;
}
}
/* Accept this endpoint */
++ifp->desc.bNumEndpoints;
INIT_LIST_HEAD(&endpoint->urb_list);
/* * Fix up bInterval values outside the legal range. * Use 10 or 8 ms if no proper value can be guessed.
*/
i = 0; /* i = min, j = max, n = default */
j = 255; if (usb_endpoint_xfer_int(d)) {
i = 1; switch (udev->speed) { case USB_SPEED_SUPER_PLUS: case USB_SPEED_SUPER: case USB_SPEED_HIGH: /* * Many device manufacturers are using full-speed * bInterval values in high-speed interrupt endpoint * descriptors. Try to fix those and fall back to an * 8-ms default value otherwise.
*/
n = fls(d->bInterval*8); if (n == 0)
n = 7; /* 8 ms = 2^(7-1) uframes */
j = 16;
/* * Adjust bInterval for quirked devices.
*/ /* * This quirk fixes bIntervals reported in ms.
*/ if (udev->quirks & USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
n = clamp(fls(d->bInterval) + 3, i, j);
i = j = n;
} /* * This quirk fixes bIntervals reported in * linear microframes.
*/ if (udev->quirks & USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) {
n = clamp(fls(d->bInterval), i, j);
i = j = n;
} break; default: /* USB_SPEED_FULL or _LOW */ /* * For low-speed, 10 ms is the official minimum. * But some "overclocked" devices might want faster * polling so we'll allow it.
*/
n = 10; break;
}
} elseif (usb_endpoint_xfer_isoc(d)) {
i = 1;
j = 16; switch (udev->speed) { case USB_SPEED_HIGH:
n = 7; /* 8 ms = 2^(7-1) uframes */ break; default: /* USB_SPEED_FULL */
n = 4; /* 8 ms = 2^(4-1) frames */ break;
}
} if (d->bInterval < i || d->bInterval > j) {
dev_notice(ddev, "config %d interface %d altsetting %d " "endpoint 0x%X has an invalid bInterval %d, " "changing to %d\n",
cfgno, inum, asnum,
d->bEndpointAddress, d->bInterval, n);
endpoint->desc.bInterval = n;
}
/* Some buggy low-speed devices have Bulk endpoints, which is * explicitly forbidden by the USB spec. In an attempt to make * them usable, we will try treating them as Interrupt endpoints.
*/ if (udev->speed == USB_SPEED_LOW && usb_endpoint_xfer_bulk(d)) {
dev_notice(ddev, "config %d interface %d altsetting %d " "endpoint 0x%X is Bulk; changing to Interrupt\n",
cfgno, inum, asnum, d->bEndpointAddress);
endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
endpoint->desc.bInterval = 1; if (usb_endpoint_maxp(&endpoint->desc) > 8)
endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
}
/* * Validate the wMaxPacketSize field. * eUSB2 devices (see USB 2.0 Double Isochronous IN ECN 9.6.6 Endpoint) * and devices with isochronous endpoints in altsetting 0 (see USB 2.0 * end of section 5.6.3) have wMaxPacketSize = 0. * So don't warn about those.
*/
maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize);
/* * Some buggy high speed devices have bulk endpoints using * maxpacket sizes other than 512. High speed HCDs may not * be able to handle that particular bug, so let's warn...
*/ if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) { if (maxp != 512)
dev_notice(ddev, "config %d interface %d altsetting %d " "bulk endpoint 0x%X has invalid maxpacket %d\n",
cfgno, inum, asnum, d->bEndpointAddress,
maxp);
}
/* Parse a possible eUSB2 periodic endpoint companion descriptor */ if (bcdUSB == 0x0220 && d->wMaxPacketSize == 0 &&
(usb_endpoint_xfer_isoc(d) || usb_endpoint_xfer_int(d)))
usb_parse_eusb2_isoc_endpoint_companion(ddev, cfgno, inum, asnum,
endpoint, buffer, size);
/* Parse a possible SuperSpeed endpoint companion descriptor */ if (udev->speed >= USB_SPEED_SUPER)
usb_parse_ss_endpoint_companion(ddev, cfgno,
inum, asnum, endpoint, buffer, size);
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint->extra = buffer;
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, &n);
endpoint->extralen = i;
retval = buffer - buffer0 + i; if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, str_plural(n), "endpoint"); return retval;
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first endpoint or interface descriptor */
alt->extra = buffer;
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, &n);
alt->extralen = i; if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, str_plural(n), "interface");
buffer += i;
size -= i;
/* Allocate space for the right(?) number of endpoints */
num_ep = num_ep_orig = alt->desc.bNumEndpoints;
alt->desc.bNumEndpoints = 0; /* Use as a counter */ if (num_ep > USB_MAXENDPOINTS) {
dev_notice(ddev, "too many endpoints for config %d interface %d " "altsetting %d: %d, using maximum allowed: %d\n",
cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);
num_ep = USB_MAXENDPOINTS;
}
if (num_ep > 0) { /* Can't allocate 0 bytes */
len = sizeof(struct usb_host_endpoint) * num_ep;
alt->endpoint = kzalloc(len, GFP_KERNEL); if (!alt->endpoint) return -ENOMEM;
}
/* Parse all the endpoint descriptors */
n = 0; while (size > 0) { if (((struct usb_descriptor_header *) buffer)->bDescriptorType
== USB_DT_INTERFACE) break;
retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum,
alt, num_ep, buffer, size); if (retval < 0) return retval;
++n;
buffer += retval;
size -= retval;
}
if (n != num_ep_orig)
dev_notice(ddev, "config %d interface %d altsetting %d has %d " "endpoint descriptor%s, different from the interface " "descriptor's value: %d\n",
cfgno, inum, asnum, n, str_plural(n), num_ep_orig); return buffer - buffer0;
if (nintf > USB_MAXINTERFACES) {
dev_notice(ddev, "config %d has too many interfaces: %d, " "using maximum allowed: %d\n",
cfgno, nintf, USB_MAXINTERFACES);
nintf = USB_MAXINTERFACES;
}
/* Go through the descriptors, checking their length and counting the
* number of altsettings for each interface */
n = 0; for ((buffer2 = buffer, size2 = size);
size2 > 0;
(buffer2 += header->bLength, size2 -= header->bLength)) {
header = (struct usb_descriptor_header *) buffer2; if ((header->bLength > size2) || (header->bLength < 2)) {
dev_notice(ddev, "config %d has an invalid descriptor " "of length %d, skipping remainder of the config\n",
cfgno, header->bLength); break;
}
if (header->bDescriptorType == USB_DT_INTERFACE) { struct usb_interface_descriptor *d; int inum;
d = (struct usb_interface_descriptor *) header; if (d->bLength < USB_DT_INTERFACE_SIZE) {
dev_notice(ddev, "config %d has an invalid " "interface descriptor of length %d, " "skipping\n", cfgno, d->bLength); continue;
}
inum = d->bInterfaceNumber;
if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&
n >= nintf_orig) {
dev_notice(ddev, "config %d has more interface " "descriptors, than it declares in " "bNumInterfaces, ignoring interface " "number: %d\n", cfgno, inum); continue;
}
if (inum >= nintf_orig)
dev_notice(ddev, "config %d has an invalid " "interface number: %d but max is %d\n",
cfgno, inum, nintf_orig - 1);
/* Have we already encountered this interface?
* Count its altsettings */ for (i = 0; i < n; ++i) { if (inums[i] == inum) break;
} if (i < n) { if (nalts[i] < 255)
++nalts[i];
} elseif (n < USB_MAXINTERFACES) {
inums[n] = inum;
nalts[n] = 1;
++n;
}
d = (struct usb_interface_assoc_descriptor *)header; if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
dev_notice(ddev, "config %d has an invalid interface association descriptor of length %d, skipping\n",
cfgno, d->bLength); continue;
}
if (iad_num == USB_MAXIADS) {
dev_notice(ddev, "found more Interface " "Association Descriptors " "than allocated for in " "configuration %d\n", cfgno);
} else {
config->intf_assoc[iad_num] = d;
iad_num++;
}
} elseif (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG)
dev_notice(ddev, "config %d contains an unexpected " "descriptor of type 0x%X, skipping\n",
cfgno, header->bDescriptorType);
if (n != nintf)
dev_notice(ddev, "config %d has %d interface%s, different from " "the descriptor's value: %d\n",
cfgno, n, str_plural(n), nintf_orig); elseif (n == 0)
dev_notice(ddev, "config %d has no interfaces?\n", cfgno);
config->desc.bNumInterfaces = nintf = n;
/* Check for missing interface numbers */ for (i = 0; i < nintf; ++i) { for (j = 0; j < nintf; ++j) { if (inums[j] == i) break;
} if (j >= nintf)
dev_notice(ddev, "config %d has no interface number " "%d\n", cfgno, i);
}
/* Allocate the usb_interface_caches and altsetting arrays */ for (i = 0; i < nintf; ++i) {
j = nalts[i]; if (j > USB_MAXALTSETTING) {
dev_notice(ddev, "too many alternate settings for " "config %d interface %d: %d, " "using maximum allowed: %d\n",
cfgno, inums[i], j, USB_MAXALTSETTING);
nalts[i] = j = USB_MAXALTSETTING;
}
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first interface descriptor */
config->extra = buffer;
i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
USB_DT_INTERFACE, &n);
config->extralen = i; if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, str_plural(n), "configuration");
buffer += i;
size -= i;
/* Parse all the interface/altsetting descriptors */ while (size > 0) {
retval = usb_parse_interface(ddev, cfgno, config,
buffer, size, inums, nalts); if (retval < 0) return retval;
buffer += retval;
size -= retval;
}
/* Check for missing altsettings */ for (i = 0; i < nintf; ++i) {
intfc = config->intf_cache[i]; for (j = 0; j < intfc->num_altsetting; ++j) { for (n = 0; n < intfc->num_altsetting; ++n) { if (intfc->altsetting[n].desc.
bAlternateSetting == j) break;
} if (n >= intfc->num_altsetting)
dev_notice(ddev, "config %d interface %d has no " "altsetting %d\n", cfgno, inums[i], j);
}
}
return 0;
}
/* hub-only!! ... and only exported for reset/reinit path. * otherwise used internally on disconnect/destroy path
*/ void usb_destroy_configuration(struct usb_device *dev)
{ int c, i;
if (!dev->config) return;
if (dev->rawdescriptors) { for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
kfree(dev->rawdescriptors[i]);
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { struct usb_host_config *cf = &dev->config[c];
kfree(cf->string); for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i])
kref_put(&cf->intf_cache[i]->ref,
usb_release_interface_cache);
}
}
kfree(dev->config);
dev->config = NULL;
}
/* * Get the USB config descriptors, cache and parse'em * * hub-only!! ... and only in reset path, or usb_new_device() * (used by real hubs and virtual root hubs)
*/ int usb_get_configuration(struct usb_device *dev)
{ struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; unsignedint cfgno, length; unsignedchar *bigbuffer; struct usb_config_descriptor *desc; int result;
if (ncfg > USB_MAXCONFIG) {
dev_notice(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
if (ncfg < 1) {
dev_err(ddev, "no configurations\n"); return -EINVAL;
}
desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); if (!desc) return -ENOMEM;
for (cfgno = 0; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
desc, USB_DT_CONFIG_SIZE); if (result < 0) {
dev_err(ddev, "unable to read config index %d " "descriptor/%s: %d\n", cfgno, "start", result); if (result != -EPIPE) goto err;
dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno; break;
} elseif (result < 4) {
dev_err(ddev, "config index %d descriptor too short " "(expected %i, got %i)\n", cfgno,
USB_DT_CONFIG_SIZE, result);
result = -EINVAL; goto err;
}
length = max_t(int, le16_to_cpu(desc->wTotalLength),
USB_DT_CONFIG_SIZE);
/* Now that we know the length, get the whole thing */
bigbuffer = kmalloc(length, GFP_KERNEL); if (!bigbuffer) {
result = -ENOMEM; goto err;
}
if (dev->quirks & USB_QUIRK_DELAY_INIT)
msleep(200);
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
bigbuffer, length); if (result < 0) {
dev_err(ddev, "unable to read config index %d " "descriptor/%s\n", cfgno, "all");
kfree(bigbuffer); goto err;
} if (result < length) {
dev_notice(ddev, "config index %d descriptor too short " "(expected %i, got %i)\n", cfgno, length, result);
length = result;
}
dev->rawdescriptors[cfgno] = bigbuffer;
result = usb_parse_configuration(dev, cfgno,
&dev->config[cfgno], bigbuffer, length); if (result < 0) {
++cfgno; goto err;
}
}
/* Get BOS descriptor set */ int usb_get_bos_descriptor(struct usb_device *dev)
{ struct device *ddev = &dev->dev; struct usb_bos_descriptor *bos; struct usb_dev_cap_header *cap; struct usb_ssp_cap_descriptor *ssp_cap; unsignedchar *buffer, *buffer0; int length, total_len, num, i, ssac;
__u8 cap_type; int ret;
bos = kzalloc(sizeof(*bos), GFP_KERNEL); if (!bos) return -ENOMEM;
/* Get BOS descriptor */
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE); if (ret < USB_DT_BOS_SIZE || bos->bLength < USB_DT_BOS_SIZE) {
dev_notice(ddev, "unable to get BOS descriptor or descriptor too short\n"); if (ret >= 0)
ret = -ENOMSG;
kfree(bos); return ret;
}
length = bos->bLength;
total_len = le16_to_cpu(bos->wTotalLength);
num = bos->bNumDeviceCaps;
kfree(bos); if (total_len < length) return -EINVAL;
dev->bos = kzalloc(sizeof(*dev->bos), GFP_KERNEL); if (!dev->bos) return -ENOMEM;
/* Now let's get the whole BOS descriptor set */
buffer = kzalloc(total_len, GFP_KERNEL); if (!buffer) {
ret = -ENOMEM; goto err;
}
dev->bos->desc = (struct usb_bos_descriptor *)buffer;
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len); if (ret < total_len) {
dev_notice(ddev, "unable to get BOS descriptor set\n"); if (ret >= 0)
ret = -ENOMSG; goto err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.