Alan,
With this patch prism2_usb works.

Great fix, thanks!!!

//lauri

On Monday 27 October 2003 18:10, Alan Stern wrote:
> This patch makes config.c more liberal about the sorts of interface
> numbering it will accept when reading interface descriptors.  The current
> code only allows interfaces numbered 0..(bNumInterfaces-1), but a number
> of devices erroneously number their interfaces starting at 1.
>
> With this patch, the code will accept a total of bNumInterfaces with
> numbers in the interval 0..bNumInterfaces.  That will accomodate origin-1
> indexing (and a few other things beside).  Also included is a comment in
> include/linux/usb.h warning people that the interface numbers might not
> correspond to the locations in the usb_host_config->interface[] array and
> telling them they should use usb_ifnum_to_if().
>
> Lauri, can you try this out and see if it helps with your prism2_usb?
>
> 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  Mon Oct 27 09:52:20 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,72 @@
>
>               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;
> +                     }
> +
> +                     /* Insertion sort is slow but it works */
> +                     for (i = n - 1; i >= 0; --i) {
> +                             if (inums[i] < inum)
> +                                     break;
> +                     }
> +                     if (++i < n && inums[i] == inum)
> +                             ++nalts[i];
> +                     else if (n >= nintf_orig) {
> +                             warn("too many interfaces (> %d)", nintf_orig);
>                               return -EINVAL;
> +                     } else if (i < nintf) {
> +                             if (n < nintf)
> +                                     ++n;
> +                             for (j = n-1; j > i; --j) {
> +                                     inums[j] = inums[j-1];
> +                                     nalts[j] = nalts[j-1];
> +                             }
> +                             inums[i] = inum;
> +                             nalts[i] = 1;
>                       }
> -                     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 +355,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.164 vs edited =====
> --- 1.164/include/linux/usb.h Mon Oct  6 13:46:13 2003
> +++ edited/include/linux/usb.h        Mon Oct 27 10:02:27 2003
> @@ -75,7 +75,7 @@
>   * @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.
> + *   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
> @@ -111,7 +111,7 @@
>   */
>  struct usb_interface {
>       /* array of alternate settings for this interface.
> -      * these will be in numeric order, 0..num_altsettting
> +      * these will be in numeric order, 0..num_altsetting-1
>        */
>       struct usb_host_interface *altsetting;
>
> @@ -150,8 +150,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
> +      * in numeric order.  But 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: The SF.net Donation Program.
Do you like what SourceForge.net is doing for the Open
Source Community?  Make a contribution, and help us add new
features and functionality. Click here: http://sourceforge.net/donate/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to