ChangeSet 1.1315.8.27, 2003/09/18 14:33:14-07:00, stern@rowland.harvard.edu [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. drivers/usb/core/config.c | 166 +++++++++++++++++++++++----------------------- 1 files changed, 86 insertions(+), 80 deletions(-) diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c --- a/drivers/usb/core/config.c Fri Sep 19 17:08:54 2003 +++ b/drivers/usb/core/config.c Fri Sep 19 17:08:54 2003 @@ -99,108 +99,114 @@ 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; - - if (header->bDescriptorType == USB_DT_INTERFACE) - break; - buffer += header->bLength; - size -= header->bLength; - } - continue; + /* 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; } + return buffer - buffer0; + } - memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); + interface = config->interface[inum]; + asnum = d->bAlternateSetting; + if (asnum >= interface->num_altsetting) { + warn("invalid alternate setting %d for interface %d", + asnum, inum); + return -EINVAL; + } - buffer += ifp->desc.bLength; - size -= ifp->desc.bLength; + ifp = &interface->altsetting[asnum]; + memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); - /* 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 += d->bLength; + size -= d->bLength; - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_ENDPOINT)) - break; + /* 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; - dbg("skipping descriptor 0x%X", header->bDescriptorType); - numskipped++; + /* If we find another "proper" descriptor then we're done */ + if ((header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_ENDPOINT)) + break; - buffer += header->bLength; - size -= header->bLength; - } - if (numskipped) { - dbg("skipped %d class/vendor specific interface descriptors", numskipped); + dbg("skipping descriptor 0x%X", header->bDescriptorType); + numskipped++; - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = buffer - begin; - ifp->extra = kmalloc(len, GFP_KERNEL); - - 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; + } + + 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); - retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); - if (retval < 0) - return retval; - - 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 @@ } /* 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;