--- ../ko/linux-2.6.2/drivers/usb/core/config.c 2004-02-04 05:43:06.000000000 +0200 +++ drivers/usb/core/config.c 2004-02-16 16:36:15.000000000 +0200 @@ -202,8 +202,9 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer, int size) { int nintf, nintf_orig; - int i, j; + int i, j, k; // added k, v2 18:52 2004-02-15 struct usb_interface *interface; + struct usb_host_interface *altsetbuf; // added, v2 12:17 2004-02-16 char *buffer2; int size2; struct usb_descriptor_header *header; @@ -265,8 +266,20 @@ i, nintf_orig); return -EINVAL; } - if (i < nintf) - ++config->interface[i]->num_altsetting; + if (i < nintf) { + // modified, v2 18:19 2004-02-15 + // instead of increasing the number of altsettings by one per alternate setting + // found, set the number to largest found altsetting plus one + // Example: + // d->bAlternateSetting = 0,1,3 + // config->interface[i]->num_altsetting = 4 + + if (config->interface[i]->num_altsetting < d->bAlternateSetting+1) + config->interface[i]->num_altsetting = d->bAlternateSetting+1; + + // old code + //++config->interface[i]->num_altsetting; + } } else if ((header->bDescriptorType == USB_DT_DEVICE || header->bDescriptorType == USB_DT_CONFIG) && j) { @@ -340,12 +353,40 @@ /* Check for missing altsettings */ for (i = 0; i < nintf; ++i) { interface = config->interface[i]; + size2 = interface->num_altsetting; for (j = 0; j < interface->num_altsetting; ++j) { if (!interface->altsetting[j].desc.bLength) { + // new code, v2 18:54 2004-02-15 + // move interfaces at j+1..interface->num_altsetting one left and + // decrease interface->num_altsetting by one + + warn("missing altsetting %d for interface %d, moving alternate settings left", j, i); + --interface->num_altsetting; + for (k=j; knum_altsetting; ++k) + interface->altsetting[k] = interface->altsetting[k+1]; + --j; + + /* old code warn("missing altsetting %d for interface %d", j, i); return -EINVAL; + */ } } + if (size2 != interface->num_altsetting) { + // new code, v2 12:34 2004-02-16 + // allocate new interface->altsetting with the truncated size and free + // the old buffer + len = sizeof(*interface->altsetting) * interface->num_altsetting; + + altsetbuf = interface->altsetting; + interface->altsetting = kmalloc(len, GFP_KERNEL); + memcpy(interface->altsetting,altsetbuf,len); + + kfree(altsetbuf); + + warn("truncated alternate settings on interface %d from %d to %d", + i,size2,interface->num_altsetting); + } } return size; @@ -484,3 +525,4 @@ return result; } +