Commit 104cc087 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: Changes to core/config.c (7 of 9)

This patch changes the usb_parse_interface() routine so that it only
handles a single interface/altsetting descriptor at a time, rather than
trying to handle all the altsettings for an interface at once.  Besides
shrinking the code slightly, this has the advantage of not requiring the
interfaces to be listed in order or all the altsetting descriptors for an
interface to be contiguous.  While there probably aren't any devices that
have _discontiguous_ altsetting descriptors, there's no harm in allowing
it -- particularly since doing so provides an overall simplification.

This is another of those hard-to-read patches.  It moves most of the body
of the usb_parse_interface() function out of a loop, thereby changing the
indentation level without actually altering the code.
parent 326d4645
......@@ -99,108 +99,114 @@ static void usb_release_intf(struct device *dev)
kfree(intf);
}
static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size)
static int usb_parse_interface(struct usb_host_config *config, unsigned char *buffer, int size)
{
unsigned char *buffer0 = buffer;
int i, len, numskipped, retval;
struct usb_descriptor_header *header;
struct usb_interface_descriptor *d;
int inum, asnum;
struct usb_interface *interface;
struct usb_host_interface *ifp;
int len, numskipped;
struct usb_descriptor_header *header;
unsigned char *begin;
int i, retval;
ifp = interface->altsetting;
while (size >= sizeof(struct usb_descriptor_header)) {
struct usb_interface_descriptor *d;
d = (struct usb_interface_descriptor *) buffer;
if (d->bDescriptorType != USB_DT_INTERFACE) {
warn("unexpected descriptor 0x%X, expecting interface, 0x%X",
d->bDescriptorType, USB_DT_INTERFACE);
return -EINVAL;
}
d = (struct usb_interface_descriptor *) buffer;
if (d->bAlternateSetting >= interface->num_altsetting) {
inum = d->bInterfaceNumber;
if (inum >= config->desc.bNumInterfaces) {
/* Skip to the next interface descriptor */
buffer += d->bLength;
size -= d->bLength;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *) buffer;
/* Skip to the next interface descriptor */
buffer += d->bLength;
size -= d->bLength;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *) buffer;
if (header->bDescriptorType == USB_DT_INTERFACE)
break;
buffer += header->bLength;
size -= header->bLength;
}
continue;
if (header->bDescriptorType == USB_DT_INTERFACE)
break;
buffer += header->bLength;
size -= header->bLength;
}
return buffer - buffer0;
}
memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE);
buffer += ifp->desc.bLength;
size -= ifp->desc.bLength;
interface = config->interface[inum];
asnum = d->bAlternateSetting;
if (asnum >= interface->num_altsetting) {
warn("invalid alternate setting %d for interface %d",
asnum, inum);
return -EINVAL;
}
/* Skip over any Class Specific or Vendor Specific descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
ifp = &interface->altsetting[asnum];
memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE);
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_ENDPOINT))
break;
buffer += d->bLength;
size -= d->bLength;
dbg("skipping descriptor 0x%X", header->bDescriptorType);
numskipped++;
/* Skip over any Class Specific or Vendor Specific descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped) {
dbg("skipped %d class/vendor specific interface descriptors", numskipped);
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_ENDPOINT))
break;
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = buffer - begin;
ifp->extra = kmalloc(len, GFP_KERNEL);
dbg("skipping descriptor 0x%X", header->bDescriptorType);
numskipped++;
if (!ifp->extra) {
err("couldn't allocate memory for interface extra descriptors");
return -ENOMEM;
}
memcpy(ifp->extra, begin, len);
ifp->extralen = len;
}
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped) {
dbg("skipped %d class/vendor specific interface descriptors", numskipped);
if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
warn("too many endpoints");
return -EINVAL;
}
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = buffer - begin;
ifp->extra = kmalloc(len, GFP_KERNEL);
len = ifp->desc.bNumEndpoints * sizeof(struct usb_host_endpoint);
ifp->endpoint = kmalloc(len, GFP_KERNEL);
if (!ifp->endpoint) {
err("out of memory");
if (!ifp->extra) {
err("couldn't allocate memory for interface extra descriptors");
return -ENOMEM;
}
memset(ifp->endpoint, 0, len);
memcpy(ifp->extra, begin, len);
ifp->extralen = len;
}
for (i = 0; i < ifp->desc.bNumEndpoints; i++) {
if (size < USB_DT_ENDPOINT_SIZE) {
err("ran out of descriptors parsing");
return -EINVAL;
}
if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
warn("too many endpoints");
return -EINVAL;
}
retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
if (retval < 0)
return retval;
len = ifp->desc.bNumEndpoints * sizeof(struct usb_host_endpoint);
ifp->endpoint = kmalloc(len, GFP_KERNEL);
if (!ifp->endpoint) {
err("out of memory");
return -ENOMEM;
}
memset(ifp->endpoint, 0, len);
buffer += retval;
size -= retval;
for (i = 0; i < ifp->desc.bNumEndpoints; i++) {
if (size < USB_DT_ENDPOINT_SIZE) {
err("ran out of descriptors parsing");
return -EINVAL;
}
/* We check to see if it's an alternate to this one */
d = (struct usb_interface_descriptor *)buffer;
if (size < USB_DT_INTERFACE_SIZE
|| d->bDescriptorType != USB_DT_INTERFACE
|| !d->bAlternateSetting)
break;
retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
if (retval < 0)
return retval;
++ifp;
buffer += retval;
size -= retval;
}
return buffer - buffer0;
......@@ -344,8 +350,8 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
}
/* Parse all the interface/altsetting descriptors */
for (i = 0; i < nintf_orig; i++) {
retval = usb_parse_interface(config->interface[i], buffer, size);
while (size >= sizeof(struct usb_descriptor_header)) {
retval = usb_parse_interface(config, buffer, size);
if (retval < 0)
return retval;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment