Commit 46c4d99b authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[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.
parent 5446ab92
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
/* these maximums are arbitrary */ /* these maximums are arbitrary */
#define USB_MAXCONFIG 8 #define USB_MAXCONFIG 8
#define USB_ALTSETTINGALLOC 4
#define USB_MAXINTERFACES 32 #define USB_MAXINTERFACES 32
static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size) 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 ...@@ -108,43 +107,27 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
struct usb_host_interface *ifp; struct usb_host_interface *ifp;
unsigned char *begin; unsigned char *begin;
interface->max_altsetting = USB_ALTSETTINGALLOC; ifp = interface->altsetting;
interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting, while (size >= sizeof(struct usb_descriptor_header)) {
GFP_KERNEL);
if (!interface->altsetting) {
err("couldn't kmalloc interface->altsetting");
return -ENOMEM;
}
while (size > 0) {
struct usb_interface_descriptor *d; struct usb_interface_descriptor *d;
if (interface->num_altsetting >= interface->max_altsetting) { d = (struct usb_interface_descriptor *) buffer;
struct usb_host_interface *ptr; if (d->bAlternateSetting >= interface->num_altsetting) {
int oldmas;
oldmas = interface->max_altsetting; /* Skip to the next interface descriptor */
interface->max_altsetting += USB_ALTSETTINGALLOC; buffer += d->bLength;
if (interface->max_altsetting > USB_MAXALTSETTING) { size -= d->bLength;
warn("too many alternate settings (incr %d max %d)\n", while (size >= sizeof(struct usb_descriptor_header)) {
USB_ALTSETTINGALLOC, USB_MAXALTSETTING); header = (struct usb_descriptor_header *) buffer;
return -EINVAL;
}
ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL); if (header->bDescriptorType == USB_DT_INTERFACE)
if (ptr == NULL) { break;
err("couldn't kmalloc interface->altsetting"); buffer += header->bLength;
return -ENOMEM; size -= header->bLength;
} }
memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas); continue;
kfree(interface->altsetting);
interface->altsetting = ptr;
} }
ifp = interface->altsetting + interface->num_altsetting;
memset(ifp, 0, sizeof(*ifp));
interface->num_altsetting++;
memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE);
buffer += ifp->desc.bLength; buffer += ifp->desc.bLength;
...@@ -216,6 +199,8 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -216,6 +199,8 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
|| d->bDescriptorType != USB_DT_INTERFACE || d->bDescriptorType != USB_DT_INTERFACE
|| !d->bAlternateSetting) || !d->bAlternateSetting)
break; break;
++ifp;
} }
return buffer - buffer0; return buffer - buffer0;
...@@ -223,7 +208,7 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -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 usb_parse_configuration(struct usb_host_config *config, char *buffer)
{ {
int nintf; int nintf, nintf_orig;
int i, j, size; int i, j, size;
struct usb_interface *interface; struct usb_interface *interface;
char *buffer2; char *buffer2;
...@@ -237,7 +222,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -237,7 +222,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
le16_to_cpus(&config->desc.wTotalLength); le16_to_cpus(&config->desc.wTotalLength);
size = config->desc.wTotalLength; size = config->desc.wTotalLength;
nintf = config->desc.bNumInterfaces; nintf = nintf_orig = config->desc.bNumInterfaces;
if (nintf > USB_MAXINTERFACES) { if (nintf > USB_MAXINTERFACES) {
warn("too many interfaces (%d max %d)", warn("too many interfaces (%d max %d)",
nintf, USB_MAXINTERFACES); nintf, USB_MAXINTERFACES);
...@@ -260,7 +245,8 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -260,7 +245,8 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
get_device(&interface->dev); 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; buffer2 = buffer;
size2 = size; size2 = size;
j = 0; j = 0;
...@@ -272,10 +258,21 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -272,10 +258,21 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
} }
if (header->bDescriptorType == USB_DT_INTERFACE) { if (header->bDescriptorType == USB_DT_INTERFACE) {
struct usb_interface_descriptor *d;
if (header->bLength < USB_DT_INTERFACE_SIZE) { if (header->bLength < USB_DT_INTERFACE_SIZE) {
warn("invalid interface descriptor"); warn("invalid interface descriptor");
return -EINVAL; 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 || } else if ((header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG) && j) { header->bDescriptorType == USB_DT_CONFIG) && j) {
...@@ -288,6 +285,28 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -288,6 +285,28 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
size2 -= header->bLength; 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; buffer += config->desc.bLength;
size -= config->desc.bLength; size -= config->desc.bLength;
...@@ -325,7 +344,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -325,7 +344,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
} }
/* Parse all the interface/altsetting descriptors */ /* 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); retval = usb_parse_interface(config->interface[i], buffer, size);
if (retval < 0) if (retval < 0)
return retval; return retval;
......
...@@ -80,7 +80,6 @@ struct usb_host_interface { ...@@ -80,7 +80,6 @@ struct usb_host_interface {
* @act_altsetting: index of current altsetting. this number is always * @act_altsetting: index of current altsetting. this number is always
* less than num_altsetting. after the device is configured, each * less than num_altsetting. after the device is configured, each
* interface uses its default setting of zero. * 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. * @driver: the USB driver that is bound to this interface.
* @minor: the minor number assigned to this interface, if this * @minor: the minor number assigned to this interface, if this
* interface is bound to a driver that uses the USB major number. * interface is bound to a driver that uses the USB major number.
...@@ -118,7 +117,6 @@ struct usb_interface { ...@@ -118,7 +117,6 @@ struct usb_interface {
unsigned act_altsetting; /* active alternate setting */ unsigned act_altsetting; /* active alternate setting */
unsigned num_altsetting; /* number of alternate settings */ unsigned num_altsetting; /* number of alternate settings */
unsigned max_altsetting; /* total memory allocated */
struct usb_driver *driver; /* driver */ struct usb_driver *driver; /* driver */
int minor; /* minor number this interface is bound to */ int minor; /* minor number this interface is bound to */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment