summaryrefslogtreecommitdiffstats
path: root/drivers/usb/usb.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /drivers/usb/usb.c
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'drivers/usb/usb.c')
-rw-r--r--drivers/usb/usb.c1329
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
+