diff options
Diffstat (limited to 'drivers/usb/usb.c')
-rw-r--r-- | drivers/usb/usb.c | 1329 |
1 files changed, 780 insertions, 549 deletions
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index b73c34eca..5895bb6df 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -1,7 +1,8 @@ /* - * driver/usb/usb.c + * drivers/usb/usb.c * * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999 * * NOTE! This is not actually a driver at all, rather this is * just a collection of helper routines that implement the @@ -12,30 +13,9 @@ * are evil. */ -/* - * Table 9-2 - * - * Offset Field Size Value Desc - * 0 bmRequestType 1 Bitmap D7: Direction - * 0 = Host-to-device - * 1 = Device-to-host - * D6..5: Type - * 0 = Standard - * 1 = Class - * 2 = Vendor - * 3 = Reserved - * D4..0: Recipient - * 0 = Device - * 1 = Interface - * 2 = Endpoint - * 3 = Other - * 4..31 = Reserved - * 1 bRequest 1 Value Specific request (9-3) - * 2 wValue 2 Value Varies - * 4 wIndex 2 Index/Offset Varies - * 6 wLength 2 Count Bytes for data - */ +#define USB_DEBUG 1 +#include <linux/config.h> #include <linux/string.h> #include <linux/bitops.h> #include <linux/malloc.h> @@ -50,108 +30,238 @@ static LIST_HEAD(usb_bus_list); int usb_register(struct usb_driver *new_driver) { - struct list_head *tmp = usb_bus_list.next; + struct list_head *tmp; + + printk("usbcore: Registering new driver %s\n", new_driver->name); + /* Add it to the list of known drivers */ list_add(&new_driver->driver_list, &usb_driver_list); /* - * We go through all existing devices, and see if any of them would - * be acceptable to the new driver.. This is done using a depth-first - * search for devices without a registered driver already, then + * We go through all existing devices, and see if any of them would + * be acceptable to the new driver.. This is done using a depth-first + * search for devices without a registered driver already, then * running 'probe' with each of the drivers registered on every one * of these. */ - while (tmp!= &usb_bus_list) { - struct usb_bus * bus = list_entry(tmp,struct - usb_bus,bus_list); - tmp=tmp->next; + tmp = usb_bus_list.next; + while (tmp != &usb_bus_list) { + struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list); + + tmp = tmp->next; usb_check_support(bus->root_hub); - } + } return 0; } void usb_deregister(struct usb_driver *driver) { - struct list_head *tmp = usb_bus_list.next; - /*first we remove the driver, to be sure it doesn't get used by - *another thread while we are stepping through removing entries - */ + struct list_head *tmp; + + printk("usbcore: Deregistering driver %s\n", driver->name); + + /* + * first we remove the driver, to be sure it doesn't get used by + * another thread while we are stepping through removing entries + */ list_del(&driver->driver_list); - printk("usbcore: deregistering driver\n"); - while (tmp!= &usb_bus_list) { - struct usb_bus * bus = list_entry(tmp,struct - usb_bus,bus_list); - tmp=tmp->next; - usb_driver_purge(driver,bus->root_hub); - } + + tmp = usb_bus_list.next; + while (tmp != &usb_bus_list) { + struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list); + + tmp = tmp->next; + usb_driver_purge(driver, bus->root_hub); + } } -/* This function is part of a depth-first search down the device tree, +/* + * This function is part of a depth-first search down the device tree, * removing any instances of a device driver. */ -void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev) +static void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev) { - int i; - if (dev==NULL){ - printk("null device being passed in!!!\n"); - return; - } - for (i=0;i<USB_MAXCHILDREN;i++) - if (dev->children[i]!=NULL) - usb_driver_purge(driver,dev->children[i]); - /*now we check this device*/ - if(dev->driver==driver) { - /* - * Note: this is not the correct way to do this, this - * uninitializes and reinitializes EVERY driver - */ - printk("disconnecting driverless device\n"); - dev->driver->disconnect(dev); - dev->driver=NULL; - /* This will go back through the list looking for a driver - * that can handle the device - */ - usb_device_descriptor(dev); - } + int i; + + if (!dev) { + printk(KERN_ERR "usbcore: null device being purged!!!\n"); + return; + } + + for (i=0; i<USB_MAXCHILDREN; i++) + if (dev->children[i]) + usb_driver_purge(driver, dev->children[i]); + + /* now we check this device */ + if (dev->driver == driver) { + /* + * Note: this is not the correct way to do this, this + * uninitializes and reinitializes EVERY driver + */ + printk(KERN_INFO "disconnect driverless device %d\n", + dev->devnum); + dev->driver->disconnect(dev); + dev->driver = NULL; + + /* + * This will go back through the list looking for a driver + * that can handle the device + */ + usb_find_driver(dev); + } } /* + * calc_bus_time: + * + * returns (approximate) USB bus time in nanoseconds for a USB transaction. + */ +static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount) +{ + unsigned long tmp; + + if (low_speed) /* no isoc. here */ + { + if (input_dir) + { + tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } + else + { + tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } + } + + /* for full-speed: */ + + if (!isoc) /* Input or Output */ + { + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (9107L + BW_HOST_DELAY + tmp); + } /* end not Isoc */ + + /* for isoc: */ + + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); +} /* end calc_bus_time */ + +/* + * check_bandwidth_alloc(): + * + * old_alloc is from host_controller->bandwidth_allocated in microseconds; + * bustime is from calc_bus_time(), but converted to microseconds. + * + * returns 0 if successful, + * -1 if bandwidth request fails. + * + * FIXME: + * This initial implementation does not use Endpoint.bInterval + * in managing bandwidth allocation. + * It probably needs to be expanded to use Endpoint.bInterval. + * This can be done as a later enhancement (correction). + * This will also probably require some kind of + * frame allocation tracking...meaning, for example, + * that if multiple drivers request interrupts every 10 USB frames, + * they don't all have to be allocated at + * frame numbers N, N+10, N+20, etc. Some of them could be at + * N+11, N+21, N+31, etc., and others at + * N+12, N+22, N+32, etc. + * However, this first cut at USB bandwidth allocation does not + * contain any frame allocation tracking. + */ +int check_bandwidth_alloc (unsigned int old_alloc, long bustime) +{ + unsigned int new_alloc; + + new_alloc = old_alloc + bustime; + /* what new total allocated bus time would be */ + + PRINTD ("usb-bandwidth-alloc: was: %ld, new: %ld, bustime = %ld us, Pipe allowed: %s", + old_alloc, new_alloc, bustime, + (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? + "yes" : "no"); + + return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? 0 : -1; +} /* end check_bandwidth_alloc */ + +/* * New functions for (de)registering a controller */ -void usb_register_bus(struct usb_bus *new_bus) +struct usb_bus *usb_alloc_bus(struct usb_operations *op) { - /* Add it to the list of buses */ - list_add(&new_bus->bus_list, &usb_bus_list); - printk("New bus registered\n"); + struct usb_bus *bus; + + bus = kmalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) + return NULL; + + memset(&bus->devmap, 0, sizeof(struct usb_devmap)); + + bus->op = op; + bus->root_hub = NULL; + bus->hcpriv = NULL; + bus->bandwidth_allocated = 0; + bus->bandwidth_int_reqs = 0; + bus->bandwidth_isoc_reqs = 0; + + INIT_LIST_HEAD(&bus->bus_list); + + return bus; +} + +void usb_free_bus(struct usb_bus *bus) +{ + if (!bus) + return; + + kfree(bus); +} + +void usb_register_bus(struct usb_bus *bus) +{ + proc_usb_add_bus(bus); + + /* Add it to the list of buses */ + list_add(&bus->bus_list, &usb_bus_list); + + printk("New USB bus registered\n"); } void usb_deregister_bus(struct usb_bus *bus) { - /* NOTE: make sure that all the devices are removed by the - * controller code, as well as having it call this when cleaning + /* + * NOTE: make sure that all the devices are removed by the + * controller code, as well as having it call this when cleaning * itself up - */ + */ list_del(&bus->bus_list); + + proc_usb_remove_bus(bus); } /* * This function is for doing a depth-first search for devices which * have support, for dynamic loading of driver modules. */ -void usb_check_support(struct usb_device *dev) +static void usb_check_support(struct usb_device *dev) { - int i; - if (dev==NULL) - { - printk("null device being passed in!!!\n"); - return; - } - for (i=0;i<USB_MAXCHILDREN;i++) - if (dev->children[i]!=NULL) - usb_check_support(dev->children[i]); - /*now we check this device*/ - if (dev->driver==NULL) - usb_device_descriptor(dev); + int i; + + if (!dev) { + printk(KERN_ERR "usbcore: null device being checked!!!\n"); + return; + } + + for (i=0; i<USB_MAXCHILDREN; i++) + if (dev->children[i]) + usb_check_support(dev->children[i]); + + /* now we check this device */ + if (!dev->driver && dev->devnum > 0) + usb_find_driver(dev); } /* * This entrypoint gets called for each new device. @@ -160,7 +270,7 @@ void usb_check_support(struct usb_device *dev) * looking for one that will accept this device as * his.. */ -int usb_device_descriptor(struct usb_device *dev) +static int usb_find_driver(struct usb_device *dev) { struct list_head *tmp = usb_driver_list.next; @@ -173,6 +283,7 @@ int usb_device_descriptor(struct usb_device *dev) dev->driver = driver; return 1; } + /* * Ok, no driver accepted the device, so show the info * for debugging.. @@ -181,305 +292,320 @@ int usb_device_descriptor(struct usb_device *dev) } /* - * Parse the fairly incomprehensible output of - * the USB configuration data, and build up the - * USB device database. + * Only HC's should call usb_alloc_dev and usb_free_dev directly + * Anybody may use usb_inc_dev_use or usb_dec_dev_use */ -static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desctype, unsigned char descindex) +struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus) { - int parsed = 0; - int n_len; - unsigned short n_desc; + struct usb_device *dev; - for (;;) { - int i; + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; - if (len < descindex) - return -1; - n_desc = le16_to_cpup((unsigned short *)ptr); - n_len = ptr[0]; + memset(dev, 0, sizeof(*dev)); - if (n_desc == ((desctype << 8) + descindex)) - break; + dev->bus = bus; + dev->parent = parent; + atomic_set(&dev->refcnt, 1); - if (((n_desc >> 8)&0xFF) == desctype && - n_len > descindex) - { - printk("bug: oversized descriptor.\n"); - break; - } - - if (n_len < 2 || n_len > len) - { - printk("Short descriptor\n"); - return -1; - } - printk( - "Expected descriptor %02X/%02X, got %02X/%02X - skipping\n", - desctype, descindex, - (n_desc >> 8) & 0xFF, n_desc & 0xFF); - for (i = 0 ; i < n_len; i++) - printk(" %d %02x\n", i, ptr[i]); - len -= n_len; - ptr += n_len; - parsed += n_len; + dev->bus->op->allocate(dev); + + return dev; +} + +void usb_free_dev(struct usb_device *dev) +{ + if (atomic_dec_and_test(&dev->refcnt)) { + usb_destroy_configuration(dev); + + dev->bus->op->deallocate(dev); + kfree(dev); } - - printk("Found %02X:%02X\n", - desctype, descindex); - return parsed; } -/* - * Parse the even more incomprehensible mess made of the USB spec - * by USB audio having private magic to go with it. - */ - -static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desctype) +void usb_inc_dev_use(struct usb_device *dev) { - int n_len = ptr[0]; + atomic_inc(&dev->refcnt); +} - if (len <= 0) - return -1; +static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) +{ + struct usb_descriptor_header *header; + int parsed = 0; - if (n_len < 2 || n_len > len) - { - int i; - printk("Short descriptor. (%d, %d):\n", len, n_len); - for (i = 0; i < len; ++i) - printk(" %d: %x\n", i, ptr[i]); + header = (struct usb_descriptor_header *)buffer; + + /* Everything should be fine being passed into here, but we sanity */ + /* check JIC */ + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); return -1; } - - if (ptr[1] == desctype) - return 0; - return -1; -} + if (header->bDescriptorType != USB_DT_ENDPOINT) { + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + endpoint->bDescriptorType); + return parsed; + } + memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE); + le16_to_cpus(&endpoint->wMaxPacketSize); -static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len) -{ - int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE); - int i; + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; - if (parsed < 0) - return parsed; - memcpy(endpoint, ptr + parsed, ptr[parsed]); - le16_to_cpus(&endpoint->wMaxPacketSize); + /* Skip over the rest of the Class Specific or Vendor Specific */ + /* descriptors */ + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; - parsed += ptr[parsed]; - len -= parsed; + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } - while((i = usb_check_descriptor(ptr+parsed, len, 0x25))>=0) - { - usb_audio_endpoint(endpoint, ptr+parsed+i); - len -= ptr[parsed+i]; - parsed += ptr[parsed+i]; + /* If we find another descriptor which is at or below us */ + /* in the descriptor heirarchy then return */ + if ((header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + return parsed; + + printk(KERN_INFO "usb: skipping descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; } - - return parsed;// + ptr[parsed]; + + return parsed; } -static int usb_parse_interface(struct usb_device *dev, struct usb_interface_descriptor *interface, unsigned char *ptr, int len) +#if 0 +static int usb_parse_hid(struct usb_device *dev, struct usb_hid_descriptor *hid, unsigned char *ptr, int len) { + int parsed = usb_expect_descriptor(ptr, len, USB_DT_HID, ptr[0]); int i; - int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE); - int retval; if (parsed < 0) return parsed; - memcpy(interface, ptr + parsed, *ptr); - len -= ptr[parsed]; - parsed += ptr[parsed]; + memcpy(hid, ptr + parsed, ptr[parsed]); + le16_to_cpus(&hid->bcdHID); - while((i=usb_check_descriptor(ptr+parsed, len, 0x24))>=0) - { - usb_audio_interface(interface, ptr+parsed+i); - len -= ptr[parsed+i]; - parsed += ptr[parsed+i]; - } - - if (interface->bNumEndpoints > USB_MAXENDPOINTS) - { - printk(KERN_WARNING "usb: too many endpoints.\n"); - return -1; - } + for (i=0; i<hid->bNumDescriptors; i++) + le16_to_cpus(&(hid->desc[i].wDescriptorLength)); - interface->endpoint = (struct usb_endpoint_descriptor *) - kmalloc(interface->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL); - if(interface->endpoint==NULL) - { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - memset(interface->endpoint, 0, interface->bNumEndpoints*sizeof(struct usb_endpoint_descriptor)); - - for (i = 0; i < interface->bNumEndpoints; i++) { -// if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) { -// parsed += 9; /* skip over the HID descriptor for now */ -// len -= 9; -// } - retval = usb_parse_endpoint(dev, interface->endpoint + i, ptr + parsed, len); - if (retval < 0) return retval; - parsed += retval; - len -= retval; - } - return parsed; + return parsed + ptr[parsed]; } +#endif -static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor *config, unsigned char *ptr, int len) +static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size) { - int i, j; - int retval; - struct usb_alternate_setting *as; - int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9); - - if (parsed < 0) - return parsed; + int i; + int retval, parsed = 0; + struct usb_descriptor_header *header; + struct usb_interface_descriptor *ifp; - memcpy(config, ptr + parsed, *ptr); - len -= *ptr; - parsed += *ptr; - le16_to_cpus(&config->wTotalLength); + interface->act_altsetting = 0; + interface->num_altsetting = 0; - if (config->MaxPower == 200) { - printk("bNumInterfaces kludge\n"); - config->bNumInterfaces += 3; + interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * USB_MAXALTSETTING, GFP_KERNEL); + if (!interface->altsetting) { + printk("couldn't kmalloc interface->altsetting\n"); + return -1; } - if (config->bNumInterfaces > USB_MAXINTERFACES) - { - printk(KERN_WARNING "usb: too many interfaces.\n"); - return -1; + while (size > 0) { + ifp = interface->altsetting + interface->num_altsetting; + interface->num_altsetting++; - } + if (interface->num_altsetting >= USB_MAXALTSETTING) { + printk(KERN_WARNING "usb: too many alternate settings\n"); + return -1; + } + memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE); - config->altsetting = (struct usb_alternate_setting *) - kmalloc(USB_MAXALTSETTING * sizeof(struct usb_alternate_setting), GFP_KERNEL); - if (config->altsetting == NULL) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - config->act_altsetting = 0; - config->num_altsetting = 1; + /* Skip over the interface */ + buffer += ifp->bLength; + parsed += ifp->bLength; + size -= ifp->bLength; - config->altsetting->interface = (struct usb_interface_descriptor *) - kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL); - if(config->altsetting->interface==NULL) - { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - memset(config->altsetting->interface, - 0, config->bNumInterfaces*sizeof(struct usb_interface_descriptor)); + /* Skip over at Interface class or vendor descriptors */ + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below us */ + /* in the descriptor heirarchy then return */ + if ((header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_ENDPOINT)) + break; + + if ((header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + return parsed; + + if (header->bDescriptorType == USB_DT_HID) + printk(KERN_INFO "usb: skipping HID descriptor\n"); + else + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + parsed += header->bLength; + size -= header->bLength; + } + + if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { + printk(KERN_WARNING "usb: too many endpoints\n"); + return -1; + } + + ifp->endpoint = (struct usb_endpoint_descriptor *) + kmalloc(ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor), GFP_KERNEL); + if (!ifp->endpoint) { + printk(KERN_WARNING "usb: out of memory\n"); + return -1; + } + + memset(ifp->endpoint, 0, ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor)); - for (i = 0; i < config->bNumInterfaces; i++) { - retval = usb_parse_interface(dev, config->altsetting->interface + i, ptr + parsed, len); - if (retval < 0) - return parsed; // HACK -// return retval; - parsed += retval; - len -= retval; - } + for (i = 0; i < ifp->bNumEndpoints; i++) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); + return -1; + } + + retval = usb_parse_endpoint(dev, ifp->endpoint + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + parsed += retval; + size -= retval; + } - printk("parsed = %d len = %d\n", parsed, len); - - // now parse for additional alternate settings - for (j = 1; j < USB_MAXALTSETTING; j++) { - retval = usb_expect_descriptor(ptr + parsed, len, USB_DT_INTERFACE, 9); - if (retval) - break; - config->num_altsetting++; - as = config->altsetting + j; - as->interface = (struct usb_interface_descriptor *) - kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL); - if (as->interface == NULL) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - memset(as->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface_descriptor)); - for (i = 0; i < config->bNumInterfaces; i++) { - retval = usb_parse_interface(dev, as->interface + i, - ptr + parsed, len); - if (retval < 0) - return parsed; - parsed += retval; - len -= 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_device *dev, void *__buf, int bytes) +static int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config, char *buffer) { int i; - unsigned char *ptr = __buf; + int retval; + int size; + struct usb_descriptor_header *header; - if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) - { - printk(KERN_WARNING "usb: too many configurations.\n"); + memcpy(config, buffer, USB_DT_INTERFACE_SIZE); + + le16_to_cpus(&config->wTotalLength); + size = config->wTotalLength; + + if (config->bNumInterfaces > USB_MAXINTERFACES) { + printk(KERN_WARNING "usb: too many interfaces\n"); return -1; } - dev->config = (struct usb_config_descriptor *) - kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL); - if(dev->config==NULL) - { - printk(KERN_WARNING "usb: out of memory.\n"); + config->interface = (struct usb_interface *) + kmalloc(config->bNumInterfaces * + sizeof(struct usb_interface), GFP_KERNEL); + if (!config->interface) { + printk(KERN_WARNING "usb: out of memory\n"); return -1; } - memset(dev->config, 0, dev->descriptor.bNumConfigurations*sizeof(struct usb_config_descriptor)); - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - int retval = usb_parse_config(dev, dev->config + i, ptr, bytes); + + memset(config->interface, 0, + config->bNumInterfaces*sizeof(struct usb_interface_descriptor)); + + buffer += config->bLength; + size -= config->bLength; + + for (i = 0; i < config->bNumInterfaces; i++) { + header = (struct usb_descriptor_header *)buffer; + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); + return -1; + } + + if (header->bDescriptorType != USB_DT_INTERFACE) { + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + size -= header->bLength; + continue; + } + + retval = usb_parse_interface(dev, config->interface + i, buffer, size); if (retval < 0) return retval; - ptr += retval; - bytes -= retval; + + buffer += retval; + size -= retval; } - if (bytes) - printk(KERN_WARNING "usb: %d bytes of extra configuration data left\n", bytes); - return 0; + + return size; } void usb_destroy_configuration(struct usb_device *dev) { - int c, a, i; - struct usb_config_descriptor *cf; - struct usb_alternate_setting *as; - struct usb_interface_descriptor *ifp; + int c, i, j; - if(dev->config==NULL) + if (!dev->config) return; - for(c = 0; c < dev->descriptor.bNumConfigurations; c++) - { - cf = &dev->config[c]; - if (cf->altsetting == NULL) + for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { + struct usb_config_descriptor *cf = &dev->config[c]; + + if (!cf->interface) break; - for (a = 0; a < cf->num_altsetting; a++) - { - as = &cf->altsetting[a]; - if (as->interface == NULL) + + for (i = 0; i < cf->bNumInterfaces; i++) { + struct usb_interface *ifp = + &cf->interface[i]; + + if (!ifp->altsetting) break; - for(i=0;i<cf->bNumInterfaces;i++) - { - ifp = &as->interface[i]; - if(ifp->endpoint==NULL) - break; - kfree(ifp->endpoint); + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_interface_descriptor *as = + &ifp->altsetting[j]; + + if (!as->endpoint) + break; + + kfree(as->endpoint); } - kfree(as->interface); + kfree(ifp->altsetting); } - kfree(cf->altsetting); + kfree(cf->interface); } kfree(dev->config); - if (dev->stringindex) - kfree(dev->stringindex); - if (dev->stringtable) - kfree(dev->stringtable); + if (dev->string) { + kfree(dev->string); + dev->string = 0; + } } void usb_init_root_hub(struct usb_device *dev) @@ -494,29 +620,33 @@ void usb_init_root_hub(struct usb_device *dev) void usb_disconnect(struct usb_device **pdev) { struct usb_device * dev = *pdev; + int i; - if (dev) { - int i; - - *pdev = NULL; + if (!dev) + return; - printk("USB disconnect on device %d\n", dev->devnum); + *pdev = NULL; - if(dev->driver) dev->driver->disconnect(dev); + printk("USB disconnect on device %d\n", dev->devnum); - /* Free up all the children.. */ - for (i = 0; i < USB_MAXCHILDREN; i++) { - struct usb_device **child = dev->children + i; - usb_disconnect(child); - } + if (dev->driver) + dev->driver->disconnect(dev); - /* Free up the device itself, including its device number */ - if (dev->devnum > 0) - clear_bit(dev->devnum, &dev->bus->devmap.devicemap); - dev->bus->op->deallocate(dev); + /* Free up all the children.. */ + for (i = 0; i < USB_MAXCHILDREN; i++) { + struct usb_device **child = dev->children + i; + usb_disconnect(child); } -} + /* remove /proc/bus/usb entry */ + proc_usb_remove_device(dev); + + /* Free up the device itself, including its device number */ + if (dev->devnum > 0) + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + + usb_free_dev(dev); +} /* * Connect a new USB device. This basically just initializes @@ -560,14 +690,15 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char int i = 5; int result; - dr.requesttype = 0x80; + dr.requesttype = USB_DIR_IN; dr.request = USB_REQ_GET_DESCRIPTOR; dr.value = (type << 8) + index; dr.index = 0; dr.length = size; while (i--) { - if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size))) + if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size)) + || result == USB_ST_STALL) break; } return result; @@ -577,7 +708,7 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char { devrequest dr; - dr.requesttype = 0x80; + dr.requesttype = USB_DIR_IN; dr.request = USB_REQ_GET_DESCRIPTOR; dr.value = (USB_DT_STRING << 8) + index; dr.index = langid; @@ -588,76 +719,28 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char int usb_get_device_descriptor(struct usb_device *dev) { - return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); - le16_to_cpus(&dev->descriptor.bcdUSB); - le16_to_cpus(&dev->descriptor.idVendor); - le16_to_cpus(&dev->descriptor.idProduct); - le16_to_cpus(&dev->descriptor.bcdDevice); -} - -int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) -{ - devrequest dr; - - dr.requesttype = USB_RT_HUB | 0x80; - dr.request = USB_REQ_GET_DESCRIPTOR; - dr.value = (USB_DT_HUB << 8); - dr.index = 0; - dr.length = size; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, size); -} - -int usb_clear_port_feature(struct usb_device *dev, int port, int feature) -{ - devrequest dr; - - dr.requesttype = USB_RT_PORT; - dr.request = USB_REQ_CLEAR_FEATURE; - dr.value = feature; - dr.index = port; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_set_port_feature(struct usb_device *dev, int port, int feature) -{ - devrequest dr; - - dr.requesttype = USB_RT_PORT; - dr.request = USB_REQ_SET_FEATURE; - dr.value = feature; - dr.index = port; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); -} - -int usb_get_hub_status(struct usb_device *dev, void *data) -{ - devrequest dr; - - dr.requesttype = USB_RT_HUB | 0x80; - dr.request = USB_REQ_GET_STATUS; - dr.value = 0; - dr.index = 0; - dr.length = 4; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4); + int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, + sizeof(dev->descriptor)); + if (ret == 0) { + le16_to_cpus(&dev->descriptor.bcdUSB); + le16_to_cpus(&dev->descriptor.idVendor); + le16_to_cpus(&dev->descriptor.idProduct); + le16_to_cpus(&dev->descriptor.bcdDevice); + } + return ret; } -int usb_get_port_status(struct usb_device *dev, int port, void *data) +int usb_get_status (struct usb_device *dev, int type, int target, void *data) { devrequest dr; - dr.requesttype = USB_RT_PORT | 0x80; + dr.requesttype = USB_DIR_IN | type; /* USB_RECIP_DEVICE, _INTERFACE, or _ENDPOINT */ dr.request = USB_REQ_GET_STATUS; dr.value = 0; - dr.index = port; - dr.length = 4; + dr.index = target; + dr.length = 2; - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4); + return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2); } int usb_get_protocol(struct usb_device *dev) @@ -665,7 +748,7 @@ int usb_get_protocol(struct usb_device *dev) unsigned char buf[8]; devrequest dr; - dr.requesttype = USB_RT_HIDD | 0x80; + dr.requesttype = USB_RT_HIDD | USB_DIR_IN; dr.request = USB_REQ_GET_PROTOCOL; dr.value = 0; dr.index = 1; @@ -713,31 +796,40 @@ int usb_set_idle(struct usb_device *dev, int duration, int report_id) static void usb_set_maxpacket(struct usb_device *dev) { - int i; - struct usb_endpoint_descriptor *ep; - int act_as = dev->actconfig->act_altsetting; - struct usb_alternate_setting *as = dev->actconfig->altsetting + act_as; - struct usb_interface_descriptor *ip = as->interface; + int i, j; + struct usb_interface *ifp; for (i=0; i<dev->actconfig->bNumInterfaces; i++) { - if (as->interface[i].bInterfaceNumber == dev->ifnum) { - ip = &as->interface[i]; - break; + ifp = dev->actconfig->interface + i; + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_interface_descriptor *as = ifp->altsetting + j; + struct usb_endpoint_descriptor *ep = as->endpoint; + int e; + + for (e=0; e<as->bNumEndpoints; e++) { + if (usb_endpoint_out(ep[e].bEndpointAddress)) + dev->epmaxpacketout[ep[e].bEndpointAddress & 0x0f] = + ep[e].wMaxPacketSize; + else + dev->epmaxpacketin [ep[e].bEndpointAddress & 0x0f] = + ep[e].wMaxPacketSize; + } } } - ep = ip->endpoint; - for (i=0; i<ip->bNumEndpoints; i++) { - dev->epmaxpacket[ep[i].bEndpointAddress & 0x0f] = ep[i].wMaxPacketSize; - } } +/* + * endp: endpoint number in bits 0-3; + * direction flag in bit 7 (1 = IN, 0 = OUT) + */ int usb_clear_halt(struct usb_device *dev, int endp) { devrequest dr; int result; __u16 status; - //if (!usb_endpoint_halted(dev, endp)) + //if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp))) // return 0; dr.requesttype = USB_RT_ENDPOINT; @@ -748,31 +840,28 @@ int usb_clear_halt(struct usb_device *dev, int endp) result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); - /* dont clear if failed */ - if (result) { + /* don't clear if failed */ + if (result) return result; - } -#if 1 /* lets be really tough */ - dr.requesttype = 0x80 | USB_RT_ENDPOINT; +#if 1 /* let's be really tough */ + dr.requesttype = USB_DIR_IN | USB_RT_ENDPOINT; dr.request = USB_REQ_GET_STATUS; dr.length = 2; status = 0xffff; result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2); - if (result) { + if (result) return result; - } - if (status & 1) { + if (status & 1) return 1; /* still halted */ - } #endif - usb_endpoint_running(dev, endp & 0x0f); + usb_endpoint_running(dev, endp & 0x0f, usb_endpoint_out(endp)); /* toggle is reset on clear */ - usb_settoggle(dev, endp & 0x0f, ((endp >> 7) & 1) ^ 1, 0); + usb_settoggle(dev, endp & 0x0f, usb_endpoint_out(endp), 0); return 0; } @@ -791,7 +880,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) return -1; dev->ifnum = interface; - dev->actconfig->act_altsetting = alternate; + dev->actconfig->interface[interface].act_altsetting = alternate; usb_set_maxpacket(dev); return 0; } @@ -828,115 +917,121 @@ int usb_set_configuration(struct usb_device *dev, int configuration) return 0; } -int usb_get_report(struct usb_device *dev) +int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size) { - unsigned char buf[8]; devrequest dr; - dr.requesttype = USB_RT_HIDD | 0x80; + dr.requesttype = USB_RT_HIDD | USB_DIR_IN; dr.request = USB_REQ_GET_REPORT; - dr.value = 0x100; - dr.index = 1; - dr.length = 3; + dr.value = (type << 8) + id; + dr.index = index; + dr.length = size; - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 3)) + if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size)) return -1; - return buf[0]; + return 0; } int usb_get_configuration(struct usb_device *dev) { unsigned int cfgno; - unsigned char * bufptr; - unsigned char * buffer; - int parse; + unsigned char buffer[8]; + unsigned char *bigbuffer; + struct usb_config_descriptor *desc = + (struct usb_config_descriptor *)buffer; - buffer = (unsigned char *) __get_free_page (GFP_KERNEL); - if (!buffer) + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { + printk(KERN_WARNING "usb: too many configurations\n"); return -1; + } - bufptr = buffer; - for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) { - unsigned int size; - /* Get the first 8 bytes - guaranteed */ - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) { - __free_page ((struct page *) buffer); + dev->config = (struct usb_config_descriptor *) + kmalloc(dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor), GFP_KERNEL); + if (!dev->config) { + printk(KERN_WARNING "usb: out of memory.\n"); + return -1; + } + memset(dev->config, 0, dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor)); + + for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) { + int result; + + /* 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) return -1; - } /* Get the full buffer */ - size = le16_to_cpup((unsigned short *)(bufptr+2)); - if (bufptr+size > buffer+PAGE_SIZE) { - printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size); - size = buffer+PAGE_SIZE-bufptr; - } - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) { - __free_page ((struct page *) buffer); + le16_to_cpus(&desc->wTotalLength); + + bigbuffer = kmalloc(desc->wTotalLength, GFP_KERNEL); + if (!bigbuffer) + return -1; + + /* Now that we know the length, get the whole thing */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength); + if (result) { + kfree(bigbuffer); return -1; } - /* Prepare for next configuration */ - bufptr += size; + result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer); + kfree(bigbuffer); + + if (result > 0) + printk(KERN_INFO "usb: descriptor data left\n"); + else if (result < 0) + return -1; } - parse = usb_parse_configuration(dev, buffer, bufptr - buffer); - __free_page ((struct page *) buffer); - return parse; + + return 0; } -int usb_get_stringtable(struct usb_device *dev) -{ - int i; - int maxindex; - int langid; - unsigned char buffer[256]; - int totalchars; - struct usb_string_descriptor *sd = (struct usb_string_descriptor *)buffer; - char *string; - __u8 bLengths[USB_MAXSTRINGS+1]; - int j; - - dev->maxstring = 0; - if(usb_get_string(dev, 0, 0, buffer, 2) || - usb_get_string(dev, 0, 0, buffer, sd->bLength)) - return -1; - /* we are going to assume that the first ID is good */ - langid = le16_to_cpup(&sd->wData[0]); - /* whip through and find total length and max index */ - for (maxindex = 1, totalchars = 0; maxindex<=USB_MAXSTRINGS; maxindex++) { - if(usb_get_string(dev, langid, maxindex, buffer, 2)) - break; - totalchars += (sd->bLength - 2)/2 + 1; - bLengths[maxindex] = sd->bLength; +char *usb_string(struct usb_device *dev, int index) +{ + int len, i; + char *ptr; + union { + unsigned char buffer[256]; + struct usb_string_descriptor desc; + } u; + + if (index <= 0) + return 0; + if (dev->string) + kfree (dev->string); + + if (dev->string_langid == 0) { + /* read string descriptor 0 */ + if (usb_get_string(dev, 0, 0, u.buffer, 2) == 0 + && u.desc.bLength >= 4 + && usb_get_string(dev, 0, 0, u.buffer, 4) == 0) + dev->string_langid = le16_to_cpup(&u.desc.wData[0]); + dev->string_langid |= 0x10000; /* so it's non-zero */ } - if (--maxindex <= 0) - return -1; - /* get space for strings and index */ - dev->stringindex = kmalloc(sizeof(char *)*maxindex, GFP_KERNEL); - if (!dev->stringindex) - return -1; - dev->stringtable = kmalloc(totalchars, GFP_KERNEL); - if (!dev->stringtable) { - kfree(dev->stringindex); - dev->stringindex = NULL; - return -1; - } + if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2) || + usb_get_string(dev, dev->string_langid, index, u.buffer, + u.desc.bLength)) + return 0; - /* fill them in */ - memset(dev->stringindex, 0, sizeof(char *)*maxindex); - for (i=1, string = dev->stringtable; i <= maxindex; i++) { - if (usb_get_string(dev, langid, i, buffer, bLengths[i])) - continue; - dev->stringindex[i] = string; - for (j=0; j < (bLengths[i] - 2)/2; j++) { - *string++ = le16_to_cpup(&sd->wData[j]); - } - *string++ = '\0'; - } - dev->maxstring = maxindex; - return 0; + len = u.desc.bLength / 2; /* includes terminating null */ + + ptr = kmalloc(len, GFP_KERNEL); + if (!ptr) + return 0; + + for (i = 0; i < len - 1; ++i) + ptr[i] = le16_to_cpup(&u.desc.wData[i]); + ptr[i] = 0; + + dev->string = ptr; + return ptr; } /* @@ -944,74 +1039,59 @@ int usb_get_stringtable(struct usb_device *dev) * and is in the default state. We need to identify the thing and * get the ball rolling.. */ -void usb_new_device(struct usb_device *dev) +int usb_new_device(struct usb_device *dev) { - int addr, i; + int addr; - printk("USB new device connect, assigned device number %d\n", + printk(KERN_INFO "USB new device connect, assigned device number %d\n", dev->devnum); dev->maxpacketsize = 0; /* Default to 8 byte max packet size */ - dev->epmaxpacket[0] = 8; + dev->epmaxpacketin [0] = 8; + dev->epmaxpacketout[0] = 8; + /* We still haven't set the Address yet */ addr = dev->devnum; dev->devnum = 0; -#if 1 /* Slow devices */ - for (i = 0; i < 5; i++) { - if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) - break; - - printk("get_descriptor failed, waiting\n"); - wait_ms(200); - } - if (i == 5) { - printk("giving up\n"); - return; + if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) { + printk(KERN_ERR "usbcore: USB device not responding, giving up\n"); + dev->devnum = -1; + return 1; } -#endif -#if 0 - printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0); -#endif - dev->epmaxpacket[0] = dev->descriptor.bMaxPacketSize0; + dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; switch (dev->descriptor.bMaxPacketSize0) { case 8: dev->maxpacketsize = 0; break; case 16: dev->maxpacketsize = 1; break; case 32: dev->maxpacketsize = 2; break; case 64: dev->maxpacketsize = 3; break; } -#if 0 - printk("dev->mps: %d\n", dev->maxpacketsize); -#endif dev->devnum = addr; -#if 1 if (usb_set_address(dev)) { - printk("Unable to set address\n"); - /* FIXME: We should disable the port */ - return; + printk(KERN_ERR "usbcore: USB device not accepting new address\n"); + dev->devnum = -1; + return 1; } -#else - usb_set_address(dev); -#endif wait_ms(10); /* Let the SET_ADDRESS settle */ if (usb_get_device_descriptor(dev)) { - printk("Unable to get device descriptor\n"); - return; + printk(KERN_ERR "usbcore: unable to get device descriptor\n"); + dev->devnum = -1; + return 1; } if (usb_get_configuration(dev)) { - printk("Unable to get configuration\n"); - return; + printk(KERN_ERR "usbcore: unable to get configuration\n"); + dev->devnum = -1; + return 1; } - usb_get_stringtable(dev); - dev->actconfig = dev->config; dev->ifnum = 0; usb_set_maxpacket(dev); @@ -1020,23 +1100,174 @@ void usb_new_device(struct usb_device *dev) usb_show_string(dev, "Product", dev->descriptor.iProduct); usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); -#if 0 - printk("Vendor: %X\n", dev->descriptor.idVendor); - printk("Product: %X\n", dev->descriptor.idProduct); -#endif + /* now that the basic setup is over, add a /proc/bus/usb entry */ + proc_usb_add_device(dev); - if (usb_device_descriptor(dev)==0) - { + if (!usb_find_driver(dev)) { /* * Ok, no driver accepted the device, so show the info for * debugging */ - printk ("Unknown new USB device:\n"); + printk(KERN_DEBUG "Unknown new USB device:\n"); usb_show_device(dev); } + + return 0; } -int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size) { - return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id); + devrequest dr; + + dr.requesttype = requesttype; + dr.request = request; + dr.value = cpu_to_le16p(&value); + dr.index = cpu_to_le16p(&index); + dr.length = cpu_to_le16p(&size); + + return dev->bus->op->control_msg(dev, pipe, &dr, data, size); +} + +int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle) +{ + long bustime; + int ret; + + *handle = NULL; + + /* Check host controller's bandwidth for this int. request. */ + bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0, + usb_maxpacket(dev, pipe, usb_pipeout(pipe))); + bustime = NS_TO_US(bustime); /* work in microseconds */ + if (check_bandwidth_alloc (dev->bus->bandwidth_allocated, bustime)) + return (USB_ST_BANDWIDTH_ERROR); + + ret = dev->bus->op->request_irq(dev, pipe, handler, period, dev_id, handle); + + /* Claim the USB bandwidth if no error. */ + if (!ret) { + dev->bus->bandwidth_allocated += bustime; + dev->bus->bandwidth_int_reqs++; + PRINTD ("bw_alloc bumped to %d for %d requesters\n", + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs); + } + + return ret; +} + +void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id) +{ + return dev->bus->op->request_bulk(dev, pipe, handler, data, len, dev_id); +} + +int usb_terminate_bulk(struct usb_device *dev, void *first) +{ + return dev->bus->op->terminate_bulk(dev, first); +} + +int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe) +{ + long bustime; + int err; + + err = dev->bus->op->release_irq(dev, handle); + + /* Return the USB bandwidth if no error. */ + if (!err) { + bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0, + usb_maxpacket(dev, pipe, usb_pipeout(pipe))); + bustime = NS_TO_US(bustime); + dev->bus->bandwidth_allocated -= bustime; + dev->bus->bandwidth_int_reqs--; + PRINTD ("bw_alloc reduced to %d for %d requesters\n", + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs); + } + + return err; +} + +/* + * usb_get_current_frame_number() + * + * returns the current frame number for the parent USB bus/controller + * of the given USB device. + */ +int usb_get_current_frame_number (struct usb_device *usb_dev) +{ + return usb_dev->bus->op->get_frame_number (usb_dev); } + +int usb_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, + void *context, + struct usb_isoc_desc **isocdesc) +{ + long bustime; + int err; + + /* Check host controller's bandwidth for this Isoc. request. */ + /* TBD: some way to factor in frame_spacing ??? */ + bustime = calc_bus_time (0, usb_pipein(pipe), 1, + usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe))); + bustime = NS_TO_US(bustime); /* work in microseconds */ + if (check_bandwidth_alloc (usb_dev->bus->bandwidth_allocated, bustime)) + return USB_ST_BANDWIDTH_ERROR; + + err = usb_dev->bus->op->init_isoc (usb_dev, pipe, frame_count, context, isocdesc); + + /* Claim the USB bandwidth if no error. */ + if (!err) { + usb_dev->bus->bandwidth_allocated += bustime; + usb_dev->bus->bandwidth_isoc_reqs++; + PRINTD ("bw_alloc bumped to %d for %d requesters\n", + usb_dev->bus->bandwidth_allocated, + usb_dev->bus->bandwidth_isoc_reqs); + } + + return err; +} + +void usb_free_isoc (struct usb_isoc_desc *isocdesc) +{ + long bustime; + + /* Return the USB bandwidth. */ + bustime = calc_bus_time (0, usb_pipein(isocdesc->pipe), 1, + usb_maxpacket(isocdesc->usb_dev, isocdesc->pipe, + usb_pipeout(isocdesc->pipe))); + bustime = NS_TO_US(bustime); + isocdesc->usb_dev->bus->bandwidth_allocated -= bustime; + isocdesc->usb_dev->bus->bandwidth_isoc_reqs--; + PRINTD ("bw_alloc reduced to %d for %d requesters\n", + isocdesc->usb_dev->bus->bandwidth_allocated, + isocdesc->usb_dev->bus->bandwidth_isoc_reqs); + + isocdesc->usb_dev->bus->op->free_isoc (isocdesc); +} + +int usb_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc) +{ + return isocdesc->usb_dev->bus->op->run_isoc (isocdesc, pr_isocdesc); +} + +int usb_kill_isoc (struct usb_isoc_desc *isocdesc) +{ + return isocdesc->usb_dev->bus->op->kill_isoc (isocdesc); +} + +#ifdef CONFIG_PROC_FS +struct list_head *usb_driver_get_list(void) +{ + return &usb_driver_list; +} + +struct list_head *usb_bus_get_list(void) +{ + return &usb_bus_list; +} +#endif + |