On Mon, 15 Dec 2003, Greg KH wrote:

> Anyway, yeah, I'd like to have that patch, but without the sorting.  Can
> you redo that and send it again?
> 
> thanks,
> 
> greg k-h

Here it is.  The sort from patch as121 is removed and a couple of comments 
altered, otherwise it's the same.

Alan Stern


===== drivers/usb/core/config.c 1.28 vs edited =====
--- 1.28/drivers/usb/core/config.c      Fri Sep 26 12:37:44 2003
+++ edited/drivers/usb/core/config.c    Tue Dec 16 16:41:44 2003
@@ -8,9 +8,7 @@
 #define USB_MAXALTSETTING              128     /* Hard limit */
 #define USB_MAXENDPOINTS               30      /* Hard limit */
 
-/* these maximums are arbitrary */
-#define USB_MAXCONFIG                  8
-#define USB_MAXINTERFACES              32
+#define USB_MAXCONFIG                  8       /* Arbitrary limit */
 
 static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char 
*buffer, int size)
 {
@@ -90,7 +88,8 @@
        kfree(intf);
 }
 
-static int usb_parse_interface(struct usb_host_config *config, unsigned char *buffer, 
int size)
+static int usb_parse_interface(struct usb_host_config *config,
+               unsigned char *buffer, int size, u8 inums[])
 {
        unsigned char *buffer0 = buffer;
        struct usb_interface_descriptor *d;
@@ -109,8 +108,15 @@
                return -EINVAL;
        }
 
+       interface = NULL;
        inum = d->bInterfaceNumber;
-       if (inum >= config->desc.bNumInterfaces) {
+       for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+               if (inums[i] == inum) {
+                       interface = config->interface[i];
+                       break;
+               }
+       }
+       if (!interface) {
 
                /* Skip to the next interface descriptor */
                buffer += d->bLength;
@@ -126,7 +132,6 @@
                return buffer - buffer0;
        }
 
-       interface = config->interface[inum];
        asnum = d->bAlternateSetting;
        if (asnum >= interface->num_altsetting) {
                warn("invalid alternate setting %d for interface %d",
@@ -210,6 +215,8 @@
        int numskipped, len;
        char *begin;
        int retval;
+       int n;
+       u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
 
        memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
        if (config->desc.bDescriptorType != USB_DT_CONFIG ||
@@ -225,25 +232,14 @@
                    nintf, USB_MAXINTERFACES);
                config->desc.bNumInterfaces = nintf = USB_MAXINTERFACES;
        }
-
-       for (i = 0; i < nintf; ++i) {
-               interface = config->interface[i] =
-                   kmalloc(sizeof(struct usb_interface), GFP_KERNEL);
-               dbg("kmalloc IF %p, numif %i", interface, i);
-               if (!interface) {
-                       err("out of memory");
-                       return -ENOMEM;
-               }
-               memset(interface, 0, sizeof(struct usb_interface));
-               interface->dev.release = usb_release_intf;
-               device_initialize(&interface->dev);
-       }
+       if (nintf == 0)
+               warn("no interfaces?");
 
        /* Go through the descriptors, checking their length and counting the
         * number of altsettings for each interface */
+       n = 0;
        buffer2 = buffer;
        size2 = size;
-       j = 0;
        while (size2 >= sizeof(struct usb_descriptor_header)) {
                header = (struct usb_descriptor_header *) buffer2;
                if ((header->bLength > size2) || (header->bLength < 2)) {
@@ -253,42 +249,67 @@
 
                if (header->bDescriptorType == USB_DT_INTERFACE) {
                        struct usb_interface_descriptor *d;
+                       int inum;
 
                        if (header->bLength < USB_DT_INTERFACE_SIZE) {
                                warn("invalid interface descriptor");
                                return -EINVAL;
                        }
                        d = (struct usb_interface_descriptor *) header;
-                       i = d->bInterfaceNumber;
-                       if (i >= nintf_orig) {
+                       inum = d->bInterfaceNumber;
+                       if (inum > nintf_orig) {
                                warn("invalid interface number (%d/%d)",
-                                   i, nintf_orig);
+                                   inum, nintf_orig);
+                               return -EINVAL;
+                       }
+
+                       /* Have we already encountered this interface? */
+                       for (i = n - 1; i >= 0; --i) {
+                               if (inums[i] == inum)
+                                       break;
+                       }
+                       if (i >= 0)
+                               ++nalts[i];
+                       else if (n >= nintf_orig) {
+                               warn("too many interfaces (> %d)", nintf_orig);
                                return -EINVAL;
+                       } else if (n < nintf) {
+                               inums[n] = inum;
+                               nalts[n] = 1;
+                               ++n;
                        }
-                       if (i < nintf)
-                               ++config->interface[i]->num_altsetting;
 
                } else if ((header->bDescriptorType == USB_DT_DEVICE ||
-                   header->bDescriptorType == USB_DT_CONFIG) && j) {
+                   header->bDescriptorType == USB_DT_CONFIG) && buffer2 > buffer) {
                        warn("unexpected descriptor type 0x%X", 
header->bDescriptorType);
                        return -EINVAL;
                }
 
-               j = 1;
                buffer2 += header->bLength;
                size2 -= header->bLength;
        }
+       if (n < nintf) {
+               warn("not enough interfaces (%d/%d)", n, nintf);
+               return -EINVAL;
+       }
 
-       /* Allocate the altsetting arrays */
-       for (i = 0; i < config->desc.bNumInterfaces; ++i) {
-               interface = config->interface[i];
+       /* Allocate the interfaces and altsetting arrays */
+       for (i = 0; i < nintf; ++i) {
+               interface = config->interface[i] =
+                   kmalloc(sizeof(struct usb_interface), GFP_KERNEL);
+               dbg("kmalloc IF %p, numif %i", interface, i);
+               if (!interface) {
+                       err("out of memory");
+                       return -ENOMEM;
+               }
+               memset(interface, 0, sizeof(struct usb_interface));
+               interface->dev.release = usb_release_intf;
+               device_initialize(&interface->dev);
+
+               interface->num_altsetting = nalts[i];
                if (interface->num_altsetting > USB_MAXALTSETTING) {
                        warn("too many alternate settings for interface %d (%d max 
%d)\n",
-                           i, interface->num_altsetting, USB_MAXALTSETTING);
-                       return -EINVAL;
-               }
-               if (interface->num_altsetting == 0) {
-                       warn("no alternate settings for interface %d", i);
+                           inums[i], interface->num_altsetting, USB_MAXALTSETTING);
                        return -EINVAL;
                }
 
@@ -329,7 +350,7 @@
 
        /* Parse all the interface/altsetting descriptors */
        while (size >= sizeof(struct usb_descriptor_header)) {
-               retval = usb_parse_interface(config, buffer, size);
+               retval = usb_parse_interface(config, buffer, size, inums);
                if (retval < 0)
                        return retval;
 
===== include/linux/usb.h 1.165 vs edited =====
--- 1.165/include/linux/usb.h   Mon Dec  8 12:39:26 2003
+++ edited/include/linux/usb.h  Tue Dec 16 16:49:47 2003
@@ -74,8 +74,8 @@
  * struct usb_interface - what usb device drivers talk to
  * @altsetting: array of interface descriptors, one for each alternate
  *     setting that may be selected.  Each one includes a set of
- *     endpoint configurations and will be in numberic order,
- *     0..num_altsetting.
+ *     endpoint configurations, and they will be in numeric order:
+ *     0..num_altsetting-1.
  * @num_altsetting: number of altsettings defined.
  * @act_altsetting: index of current altsetting.  this number is always
  *     less than num_altsetting.  after the device is configured, each
@@ -110,10 +110,8 @@
  * will use them in non-default settings.
  */
 struct usb_interface {
-       /* array of alternate settings for this interface.
-        * these will be in numeric order, 0..num_altsettting
-        */
-       struct usb_host_interface *altsetting;
+       struct usb_host_interface *altsetting;  /* array of alternate */
+                       /* setting structures for this interface */
 
        unsigned act_altsetting;        /* active alternate setting */
        unsigned num_altsetting;        /* number of alternate settings */
@@ -150,8 +148,12 @@
 struct usb_host_config {
        struct usb_config_descriptor    desc;
 
-       /* the interfaces associated with this configuration
-        * these will be in numeric order, 0..desc.bNumInterfaces
+       /* The interfaces associated with this configuration.
+        * There are desc.bNumInterfaces of them, and they are
+        * *not* guaranteed to be in numeric order.  Even worse,
+        * some non-compliant devices number the interfaces
+        * starting with 1, not 0.  To be safe don't index this
+        * array directly; instead use usb_ifnum_to_if().
         */
        struct usb_interface *interface[USB_MAXINTERFACES];
 



-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id=1278&alloc_id=3371&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to