summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2003-09-17 03:59:57 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2003-09-17 03:59:57 -0700
commit46c4d99be2f36abda46f51b33ecb2e9fb940e927 (patch)
tree3dcba5f09df10399bf6ebeda9d8a81205540f8dd
parent5446ab92b78853b432dbe47b8e555d3c65a1e61b (diff)
[PATCH] USB: Changes to core/config.c (6 of 9)
This patch removes the home-brewed resizeable arrays used to store altsetting structures, along with the now-unneeded max_altsetting field. Since we are already making a preliminary pass through all the descriptors to check their lengths, we take the opportunity to also count the number of altsetting descriptors for each interface. Then exactly the right number can be allocated all at once. This also moves the code that allocates the altsettings outside the usb_parse_interface() routine. Though not important now, this change will come in handy in the next patch.
-rw-r--r--drivers/usb/core/config.c89
-rw-r--r--include/linux/usb.h2
2 files changed, 54 insertions, 37 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 89112f2bde2f..4ce45e0091d7 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -10,7 +10,6 @@
/* these maximums are arbitrary */
#define USB_MAXCONFIG 8
-#define USB_ALTSETTINGALLOC 4
#define USB_MAXINTERFACES 32
static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size)
@@ -108,43 +107,27 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
struct usb_host_interface *ifp;
unsigned char *begin;
- interface->max_altsetting = USB_ALTSETTINGALLOC;
- interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting,
- GFP_KERNEL);
- if (!interface->altsetting) {
- err("couldn't kmalloc interface->altsetting");
- return -ENOMEM;
- }
-
- while (size > 0) {
+ ifp = interface->altsetting;
+ while (size >= sizeof(struct usb_descriptor_header)) {
struct usb_interface_descriptor *d;
- if (interface->num_altsetting >= interface->max_altsetting) {
- struct usb_host_interface *ptr;
- int oldmas;
+ d = (struct usb_interface_descriptor *) buffer;
+ if (d->bAlternateSetting >= interface->num_altsetting) {
- oldmas = interface->max_altsetting;
- interface->max_altsetting += USB_ALTSETTINGALLOC;
- if (interface->max_altsetting > USB_MAXALTSETTING) {
- warn("too many alternate settings (incr %d max %d)\n",
- USB_ALTSETTINGALLOC, USB_MAXALTSETTING);
- return -EINVAL;
- }
+ /* 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;
- ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL);
- if (ptr == NULL) {
- err("couldn't kmalloc interface->altsetting");
- return -ENOMEM;
+ if (header->bDescriptorType == USB_DT_INTERFACE)
+ break;
+ buffer += header->bLength;
+ size -= header->bLength;
}
- memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas);
- kfree(interface->altsetting);
- interface->altsetting = ptr;
+ continue;
}
- ifp = interface->altsetting + interface->num_altsetting;
- memset(ifp, 0, sizeof(*ifp));
- interface->num_altsetting++;
-
memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE);
buffer += ifp->desc.bLength;
@@ -216,6 +199,8 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
|| d->bDescriptorType != USB_DT_INTERFACE
|| !d->bAlternateSetting)
break;
+
+ ++ifp;
}
return buffer - buffer0;
@@ -223,7 +208,7 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
int usb_parse_configuration(struct usb_host_config *config, char *buffer)
{
- int nintf;
+ int nintf, nintf_orig;
int i, j, size;
struct usb_interface *interface;
char *buffer2;
@@ -237,7 +222,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
le16_to_cpus(&config->desc.wTotalLength);
size = config->desc.wTotalLength;
- nintf = config->desc.bNumInterfaces;
+ nintf = nintf_orig = config->desc.bNumInterfaces;
if (nintf > USB_MAXINTERFACES) {
warn("too many interfaces (%d max %d)",
nintf, USB_MAXINTERFACES);
@@ -260,7 +245,8 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
get_device(&interface->dev);
}
- /* Go through the descriptors, checking their length */
+ /* Go through the descriptors, checking their length and counting the
+ * number of altsettings for each interface */
buffer2 = buffer;
size2 = size;
j = 0;
@@ -272,10 +258,21 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
}
if (header->bDescriptorType == USB_DT_INTERFACE) {
+ struct usb_interface_descriptor *d;
+
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) {
+ warn("invalid interface number (%d/%d)",
+ i, nintf_orig);
+ return -EINVAL;
+ }
+ if (i < nintf)
+ ++config->interface[i]->num_altsetting;
} else if ((header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG) && j) {
@@ -288,6 +285,28 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
size2 -= header->bLength;
}
+ /* Allocate the altsetting arrays */
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ interface = config->interface[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);
+ return -EINVAL;
+ }
+
+ len = sizeof(*interface->altsetting) * interface->num_altsetting;
+ interface->altsetting = kmalloc(len, GFP_KERNEL);
+ if (!interface->altsetting) {
+ err("couldn't kmalloc interface->altsetting");
+ return -ENOMEM;
+ }
+ memset(interface->altsetting, 0, len);
+ }
+
buffer += config->desc.bLength;
size -= config->desc.bLength;
@@ -325,7 +344,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
}
/* Parse all the interface/altsetting descriptors */
- for (i = 0; i < nintf; i++) {
+ for (i = 0; i < nintf_orig; i++) {
retval = usb_parse_interface(config->interface[i], buffer, size);
if (retval < 0)
return retval;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a20b33d953aa..5575ebfb276d 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -80,7 +80,6 @@ struct usb_host_interface {
* @act_altsetting: index of current altsetting. this number is always
* less than num_altsetting. after the device is configured, each
* interface uses its default setting of zero.
- * @max_altsetting: the max number of altsettings for this interface.
* @driver: the USB driver that is bound to this interface.
* @minor: the minor number assigned to this interface, if this
* interface is bound to a driver that uses the USB major number.
@@ -118,7 +117,6 @@ struct usb_interface {
unsigned act_altsetting; /* active alternate setting */
unsigned num_altsetting; /* number of alternate settings */
- unsigned max_altsetting; /* total memory allocated */
struct usb_driver *driver; /* driver */
int minor; /* minor number this interface is bound to */