Commit 6caf5656 authored by Patrick Mochel's avatar Patrick Mochel

USB: Move configuration parsing code from usb.c to config.c

parent 1a2f7297
......@@ -2,9 +2,10 @@
# Makefile for USB Core files and filesystem
#
export-objs := usb.o hcd.o urb.o message.o
export-objs := usb.o hcd.o urb.o message.o config.o
usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o message.o
usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o message.o \
config.o
ifeq ($(CONFIG_USB_DEVICEFS),y)
usbcore-objs += devio.o inode.o drivers.o devices.o
......
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
{
struct usb_descriptor_header *header;
unsigned char *begin;
int parsed = 0, len, numskipped;
header = (struct usb_descriptor_header *)buffer;
/* Everything should be fine being passed into here, but we sanity */
/* check JIC */
if (header->bLength > size) {
err("ran out of descriptors parsing");
return -1;
}
if (header->bDescriptorType != USB_DT_ENDPOINT) {
warn("unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X",
endpoint->bDescriptorType, USB_DT_ENDPOINT);
return parsed;
}
if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE)
memcpy(endpoint, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
else
memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE);
le16_to_cpus(&endpoint->wMaxPacketSize);
buffer += header->bLength;
size -= header->bLength;
parsed += header->bLength;
/* Skip over the rest of the Class Specific or Vendor Specific */
/* descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
dbg("skipping descriptor 0x%X",
header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
parsed += header->bLength;
}
if (numskipped)
dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for drivers */
/* to later parse */
len = (int)(buffer - begin);
if (!len) {
endpoint->extra = NULL;
endpoint->extralen = 0;
return parsed;
}
endpoint->extra = kmalloc(len, GFP_KERNEL);
if (!endpoint->extra) {
err("couldn't allocate memory for endpoint extra descriptors");
endpoint->extralen = 0;
return parsed;
}
memcpy(endpoint->extra, begin, len);
endpoint->extralen = len;
return parsed;
}
static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size)
{
int i, len, numskipped, retval, parsed = 0;
struct usb_descriptor_header *header;
struct usb_interface_descriptor *ifp;
unsigned char *begin;
interface->act_altsetting = 0;
interface->num_altsetting = 0;
interface->max_altsetting = USB_ALTSETTINGALLOC;
interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
if (!interface->altsetting) {
err("couldn't kmalloc interface->altsetting");
return -1;
}
while (size > 0) {
if (interface->num_altsetting >= interface->max_altsetting) {
void *ptr;
int oldmas;
oldmas = interface->max_altsetting;
interface->max_altsetting += USB_ALTSETTINGALLOC;
if (interface->max_altsetting > USB_MAXALTSETTING) {
warn("too many alternate settings (max %d)",
USB_MAXALTSETTING);
return -1;
}
ptr = interface->altsetting;
interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
if (!interface->altsetting) {
err("couldn't kmalloc interface->altsetting");
interface->altsetting = ptr;
return -1;
}
memcpy(interface->altsetting, ptr, sizeof(struct usb_interface_descriptor) * oldmas);
kfree(ptr);
}
ifp = interface->altsetting + interface->num_altsetting;
ifp->endpoint = NULL;
ifp->extra = NULL;
ifp->extralen = 0;
interface->num_altsetting++;
memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE);
/* Skip over the interface */
buffer += ifp->bLength;
parsed += ifp->bLength;
size -= ifp->bLength;
begin = buffer;
numskipped = 0;
/* Skip over any interface, class or vendor descriptors */
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
numskipped++;
buffer += header->bLength;
parsed += header->bLength;
size -= header->bLength;
}
if (numskipped)
dbg("skipped %d class/vendor specific interface descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
ifp->extra = kmalloc(len, GFP_KERNEL);
if (!ifp->extra) {
err("couldn't allocate memory for interface extra descriptors");
ifp->extralen = 0;
return -1;
}
memcpy(ifp->extra, begin, len);
ifp->extralen = len;
}
/* Did we hit an unexpected descriptor? */
header = (struct usb_descriptor_header *)buffer;
if ((size >= sizeof(struct usb_descriptor_header)) &&
((header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE)))
return parsed;
if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
warn("too many endpoints");
return -1;
}
ifp->endpoint = (struct usb_endpoint_descriptor *)
kmalloc(ifp->bNumEndpoints *
sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
if (!ifp->endpoint) {
err("out of memory");
return -1;
}
memset(ifp->endpoint, 0, ifp->bNumEndpoints *
sizeof(struct usb_endpoint_descriptor));
for (i = 0; i < ifp->bNumEndpoints; i++) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength > size) {
err("ran out of descriptors parsing");
return -1;
}
retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
if (retval < 0)
return retval;
buffer += retval;
parsed += retval;
size -= retval;
}
/* We check to see if it's an alternate to this one */
ifp = (struct usb_interface_descriptor *)buffer;
if (size < USB_DT_INTERFACE_SIZE ||
ifp->bDescriptorType != USB_DT_INTERFACE ||
!ifp->bAlternateSetting)
return parsed;
}
return parsed;
}
int usb_parse_configuration(struct usb_config_descriptor *config, char *buffer)
{
int i, retval, size;
struct usb_descriptor_header *header;
memcpy(config, buffer, USB_DT_CONFIG_SIZE);
le16_to_cpus(&config->wTotalLength);
size = config->wTotalLength;
if (config->bNumInterfaces > USB_MAXINTERFACES) {
warn("too many interfaces");
return -1;
}
config->interface = (struct usb_interface *)
kmalloc(config->bNumInterfaces *
sizeof(struct usb_interface), GFP_KERNEL);
dbg("kmalloc IF %p, numif %i", config->interface, config->bNumInterfaces);
if (!config->interface) {
err("out of memory");
return -1;
}
memset(config->interface, 0,
config->bNumInterfaces * sizeof(struct usb_interface));
buffer += config->bLength;
size -= config->bLength;
config->extra = NULL;
config->extralen = 0;
for (i = 0; i < config->bNumInterfaces; i++) {
int numskipped, len;
char *begin;
/* Skip over the rest of the Class Specific or Vendor */
/* Specific descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if ((header->bLength > size) || (header->bLength < 2)) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
dbg("skipping descriptor 0x%X", header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped)
dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
if (config->extralen) {
warn("extra config descriptor");
} else {
config->extra = kmalloc(len, GFP_KERNEL);
if (!config->extra) {
err("couldn't allocate memory for config extra descriptors");
config->extralen = 0;
return -1;
}
memcpy(config->extra, begin, len);
config->extralen = len;
}
}
retval = usb_parse_interface(config->interface + i, buffer, size);
if (retval < 0)
return retval;
buffer += retval;
size -= retval;
}
return size;
}
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally on disconnect/destroy path
void usb_destroy_configuration(struct usb_device *dev)
{
int c, i, j, k;
if (!dev->config)
return;
if (dev->rawdescriptors) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
kfree(dev->rawdescriptors[i]);
kfree(dev->rawdescriptors);
}
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
struct usb_config_descriptor *cf = &dev->config[c];
if (!cf->interface)
break;
for (i = 0; i < cf->bNumInterfaces; i++) {
struct usb_interface *ifp =
&cf->interface[i];
if (!ifp->altsetting)
break;
for (j = 0; j < ifp->num_altsetting; j++) {
struct usb_interface_descriptor *as =
&ifp->altsetting[j];
if(as->extra) {
kfree(as->extra);
}
if (!as->endpoint)
break;
for(k = 0; k < as->bNumEndpoints; k++) {
if(as->endpoint[k].extra) {
kfree(as->endpoint[k].extra);
}
}
kfree(as->endpoint);
}
kfree(ifp->altsetting);
}
kfree(cf->interface);
}
kfree(dev->config);
}
// hub-only!! ... and only in reset path, or usb_new_device()
// (used by real hubs and virtual root hubs)
int usb_get_configuration(struct usb_device *dev)
{
int result;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
warn("too many configurations");
return -EINVAL;
}
if (dev->descriptor.bNumConfigurations < 1) {
warn("not enough configurations");
return -EINVAL;
}
dev->config = (struct usb_config_descriptor *)
kmalloc(dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor), GFP_KERNEL);
if (!dev->config) {
err("out of memory");
return -ENOMEM;
}
memset(dev->config, 0, dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor));
dev->rawdescriptors = (char **)kmalloc(sizeof(char *) *
dev->descriptor.bNumConfigurations, GFP_KERNEL);
if (!dev->rawdescriptors) {
err("out of memory");
return -ENOMEM;
}
buffer = kmalloc(8, GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
return -ENOMEM;
}
desc = (struct usb_config_descriptor *)buffer;
for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
/* We grab the first 8 bytes so we know how long the whole */
/* configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
if (result < 8) {
if (result < 0)
err("unable to get descriptor");
else {
err("config descriptor too short (expected %i, got %i)", 8, result);
result = -EINVAL;
}
goto err;
}
/* Get the full buffer */
length = le16_to_cpu(desc->wTotalLength);
bigbuffer = kmalloc(length, GFP_KERNEL);
if (!bigbuffer) {
err("unable to allocate memory for configuration descriptors");
result = -ENOMEM;
goto err;
}
/* Now that we know the length, get the whole thing */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
if (result < 0) {
err("couldn't get all of config descriptors");
kfree(bigbuffer);
goto err;
}
if (result < length) {
err("config descriptor too short (expected %i, got %i)", length, result);
result = -EINVAL;
kfree(bigbuffer);
goto err;
}
dev->rawdescriptors[cfgno] = bigbuffer;
result = usb_parse_configuration(&dev->config[cfgno], bigbuffer);
if (result > 0)
dbg("descriptor data left");
else if (result < 0) {
result = -EINVAL;
goto err;
}
}
kfree(buffer);
return 0;
err:
kfree(buffer);
dev->descriptor.bNumConfigurations = cfgno;
return result;
}
......@@ -33,7 +33,6 @@
#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <asm/byteorder.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
......@@ -1035,390 +1034,6 @@ int usb_get_current_frame_number(struct usb_device *dev)
/*-------------------------------------------------------------------*/
static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
{
struct usb_descriptor_header *header;
unsigned char *begin;
int parsed = 0, len, numskipped;
header = (struct usb_descriptor_header *)buffer;
/* Everything should be fine being passed into here, but we sanity */
/* check JIC */
if (header->bLength > size) {
err("ran out of descriptors parsing");
return -1;
}
if (header->bDescriptorType != USB_DT_ENDPOINT) {
warn("unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X",
endpoint->bDescriptorType, USB_DT_ENDPOINT);
return parsed;
}
if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE)
memcpy(endpoint, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
else
memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE);
le16_to_cpus(&endpoint->wMaxPacketSize);
buffer += header->bLength;
size -= header->bLength;
parsed += header->bLength;
/* Skip over the rest of the Class Specific or Vendor Specific */
/* descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
dbg("skipping descriptor 0x%X",
header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
parsed += header->bLength;
}
if (numskipped)
dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for drivers */
/* to later parse */
len = (int)(buffer - begin);
if (!len) {
endpoint->extra = NULL;
endpoint->extralen = 0;
return parsed;
}
endpoint->extra = kmalloc(len, GFP_KERNEL);
if (!endpoint->extra) {
err("couldn't allocate memory for endpoint extra descriptors");
endpoint->extralen = 0;
return parsed;
}
memcpy(endpoint->extra, begin, len);
endpoint->extralen = len;
return parsed;
}
static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size)
{
int i, len, numskipped, retval, parsed = 0;
struct usb_descriptor_header *header;
struct usb_interface_descriptor *ifp;
unsigned char *begin;
interface->act_altsetting = 0;
interface->num_altsetting = 0;
interface->max_altsetting = USB_ALTSETTINGALLOC;
interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
if (!interface->altsetting) {
err("couldn't kmalloc interface->altsetting");
return -1;
}
while (size > 0) {
if (interface->num_altsetting >= interface->max_altsetting) {
void *ptr;
int oldmas;
oldmas = interface->max_altsetting;
interface->max_altsetting += USB_ALTSETTINGALLOC;
if (interface->max_altsetting > USB_MAXALTSETTING) {
warn("too many alternate settings (max %d)",
USB_MAXALTSETTING);
return -1;
}
ptr = interface->altsetting;
interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
if (!interface->altsetting) {
err("couldn't kmalloc interface->altsetting");
interface->altsetting = ptr;
return -1;
}
memcpy(interface->altsetting, ptr, sizeof(struct usb_interface_descriptor) * oldmas);
kfree(ptr);
}
ifp = interface->altsetting + interface->num_altsetting;
ifp->endpoint = NULL;
ifp->extra = NULL;
ifp->extralen = 0;
interface->num_altsetting++;
memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE);
/* Skip over the interface */
buffer += ifp->bLength;
parsed += ifp->bLength;
size -= ifp->bLength;
begin = buffer;
numskipped = 0;
/* Skip over any interface, class or vendor descriptors */
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
numskipped++;
buffer += header->bLength;
parsed += header->bLength;
size -= header->bLength;
}
if (numskipped)
dbg("skipped %d class/vendor specific interface descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
ifp->extra = kmalloc(len, GFP_KERNEL);
if (!ifp->extra) {
err("couldn't allocate memory for interface extra descriptors");
ifp->extralen = 0;
return -1;
}
memcpy(ifp->extra, begin, len);
ifp->extralen = len;
}
/* Did we hit an unexpected descriptor? */
header = (struct usb_descriptor_header *)buffer;
if ((size >= sizeof(struct usb_descriptor_header)) &&
((header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE)))
return parsed;
if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
warn("too many endpoints");
return -1;
}
ifp->endpoint = (struct usb_endpoint_descriptor *)
kmalloc(ifp->bNumEndpoints *
sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
if (!ifp->endpoint) {
err("out of memory");
return -1;
}
memset(ifp->endpoint, 0, ifp->bNumEndpoints *
sizeof(struct usb_endpoint_descriptor));
for (i = 0; i < ifp->bNumEndpoints; i++) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength > size) {
err("ran out of descriptors parsing");
return -1;
}
retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
if (retval < 0)
return retval;
buffer += retval;
parsed += retval;
size -= retval;
}
/* We check to see if it's an alternate to this one */
ifp = (struct usb_interface_descriptor *)buffer;
if (size < USB_DT_INTERFACE_SIZE ||
ifp->bDescriptorType != USB_DT_INTERFACE ||
!ifp->bAlternateSetting)
return parsed;
}
return parsed;
}
int usb_parse_configuration(struct usb_config_descriptor *config, char *buffer)
{
int i, retval, size;
struct usb_descriptor_header *header;
memcpy(config, buffer, USB_DT_CONFIG_SIZE);
le16_to_cpus(&config->wTotalLength);
size = config->wTotalLength;
if (config->bNumInterfaces > USB_MAXINTERFACES) {
warn("too many interfaces");
return -1;
}
config->interface = (struct usb_interface *)
kmalloc(config->bNumInterfaces *
sizeof(struct usb_interface), GFP_KERNEL);
dbg("kmalloc IF %p, numif %i", config->interface, config->bNumInterfaces);
if (!config->interface) {
err("out of memory");
return -1;
}
memset(config->interface, 0,
config->bNumInterfaces * sizeof(struct usb_interface));
buffer += config->bLength;
size -= config->bLength;
config->extra = NULL;
config->extralen = 0;
for (i = 0; i < config->bNumInterfaces; i++) {
int numskipped, len;
char *begin;
/* Skip over the rest of the Class Specific or Vendor */
/* Specific descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if ((header->bLength > size) || (header->bLength < 2)) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
dbg("skipping descriptor 0x%X", header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped)
dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
if (config->extralen) {
warn("extra config descriptor");
} else {
config->extra = kmalloc(len, GFP_KERNEL);
if (!config->extra) {
err("couldn't allocate memory for config extra descriptors");
config->extralen = 0;
return -1;
}
memcpy(config->extra, begin, len);
config->extralen = len;
}
}
retval = usb_parse_interface(config->interface + i, buffer, size);
if (retval < 0)
return retval;
buffer += retval;
size -= retval;
}
return size;
}
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally on disconnect/destroy path
void usb_destroy_configuration(struct usb_device *dev)
{
int c, i, j, k;
if (!dev->config)
return;
if (dev->rawdescriptors) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
kfree(dev->rawdescriptors[i]);
kfree(dev->rawdescriptors);
}
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
struct usb_config_descriptor *cf = &dev->config[c];
if (!cf->interface)
break;
for (i = 0; i < cf->bNumInterfaces; i++) {
struct usb_interface *ifp =
&cf->interface[i];
if (!ifp->altsetting)
break;
for (j = 0; j < ifp->num_altsetting; j++) {
struct usb_interface_descriptor *as =
&ifp->altsetting[j];
if(as->extra) {
kfree(as->extra);
}
if (!as->endpoint)
break;
for(k = 0; k < as->bNumEndpoints; k++) {
if(as->endpoint[k].extra) {
kfree(as->endpoint[k].extra);
}
}
kfree(as->endpoint);
}
kfree(ifp->altsetting);
}
kfree(cf->interface);
}
kfree(dev->config);
}
/* for returning string descriptors in UTF-16LE */
static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
......@@ -1619,108 +1234,6 @@ int usb_set_address(struct usb_device *dev)
}
// hub-only!! ... and only in reset path, or usb_new_device()
// (used by real hubs and virtual root hubs)
int usb_get_configuration(struct usb_device *dev)
{
int result;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
warn("too many configurations");
return -EINVAL;
}
if (dev->descriptor.bNumConfigurations < 1) {
warn("not enough configurations");
return -EINVAL;
}
dev->config = (struct usb_config_descriptor *)
kmalloc(dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor), GFP_KERNEL);
if (!dev->config) {
err("out of memory");
return -ENOMEM;
}
memset(dev->config, 0, dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor));
dev->rawdescriptors = (char **)kmalloc(sizeof(char *) *
dev->descriptor.bNumConfigurations, GFP_KERNEL);
if (!dev->rawdescriptors) {
err("out of memory");
return -ENOMEM;
}
buffer = kmalloc(8, GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
return -ENOMEM;
}
desc = (struct usb_config_descriptor *)buffer;
for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
/* We grab the first 8 bytes so we know how long the whole */
/* configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
if (result < 8) {
if (result < 0)
err("unable to get descriptor");
else {
err("config descriptor too short (expected %i, got %i)", 8, result);
result = -EINVAL;
}
goto err;
}
/* Get the full buffer */
length = le16_to_cpu(desc->wTotalLength);
bigbuffer = kmalloc(length, GFP_KERNEL);
if (!bigbuffer) {
err("unable to allocate memory for configuration descriptors");
result = -ENOMEM;
goto err;
}
/* Now that we know the length, get the whole thing */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
if (result < 0) {
err("couldn't get all of config descriptors");
kfree(bigbuffer);
goto err;
}
if (result < length) {
err("config descriptor too short (expected %i, got %i)", length, result);
result = -EINVAL;
kfree(bigbuffer);
goto err;
}
dev->rawdescriptors[cfgno] = bigbuffer;
result = usb_parse_configuration(&dev->config[cfgno], bigbuffer);
if (result > 0)
dbg("descriptor data left");
else if (result < 0) {
result = -EINVAL;
goto err;
}
}
kfree(buffer);
return 0;
err:
kfree(buffer);
dev->descriptor.bNumConfigurations = cfgno;
return result;
}
/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
......
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