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;
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 *bethefirstthingimmediatelyfollowingtheendpointdescriptor.
*/
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
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);
/* *FixupbIntervalvaluesoutsidethelegalrange. *Use10or8msifnopropervaluecanbeguessed.
*/
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: /* *Manydevicemanufacturersareusingfull-speed *bIntervalvaluesinhigh-speedinterruptendpoint *descriptors.Trytofixthoseandfallbacktoan *8-msdefaultvalueotherwise.
*/
n = fls(d->bInterval*8); if (n == 0)
n = 7; /* 8 ms = 2^(7-1) uframes */
j = 16;
/* *AdjustbIntervalforquirkeddevices.
*/ /* *ThisquirkfixesbIntervalsreportedinms.
*/ if (udev->quirks & USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
n = clamp(fls(d->bInterval) + 3, i, j);
i = j = n;
} /* *ThisquirkfixesbIntervalsreportedin *linearmicroframes.
*/ 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 */ /* *Forlow-speed,10msistheofficialminimum. *Butsome"overclocked"devicesmightwantfaster *pollingsowe'llallowit.
*/
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 *explicitlyforbiddenbytheUSBspec.Inanattempttomake *themusable,wewilltrytreatingthemasInterruptendpoints.
*/ 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);
}
/* 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);
}
}
return0;
}
/* hub-only!! ... and only exported for reset/reinit path. *otherwiseusedinternallyondisconnect/destroypath
*/ 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]);
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.