patch-2.3.15 linux/drivers/usb/usb.c

Next file: linux/drivers/usb/usb.h
Previous file: linux/drivers/usb/usb-debug.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.14/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
@@ -2,6 +2,7 @@
  * 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,6 @@
  * 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
- */
-
 #include <linux/config.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
@@ -67,7 +44,7 @@
 	 */
 	tmp = usb_bus_list.next;
 	while (tmp != &usb_bus_list) {
-		struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
+		struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
 
 	        tmp = tmp->next;
 		usb_check_support(bus->root_hub);
@@ -96,12 +73,13 @@
 	}
 }
 
-/* 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;
+	int i;
 
 	if (!dev) {
 		printk(KERN_ERR "usbcore: null device being purged!!!\n");
@@ -158,16 +136,16 @@
 	if (!bus)
 		return;
 
-	if (bus->bus_list.next != &bus->bus_list)
-		printk(KERN_ERR "usbcore: freeing non-empty bus\n");
-
 	kfree(bus);
 }
 
-void usb_register_bus(struct usb_bus *new_bus)
+void usb_register_bus(struct usb_bus *bus)
 {
+	proc_usb_add_bus(bus);
+
 	/* Add it to the list of buses */
-	list_add(&new_bus->bus_list, &usb_bus_list);
+	list_add(&bus->bus_list, &usb_bus_list);
+
 	printk("New USB bus registered\n");
 }
 
@@ -179,13 +157,15 @@
 	 * 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;
 
@@ -209,7 +189,7 @@
  * looking for one that will accept this device as
  * his..
  */
-int usb_find_driver(struct usb_device *dev)
+static int usb_find_driver(struct usb_device *dev)
 {
 	struct list_head *tmp = usb_driver_list.next;
 
@@ -231,283 +211,311 @@
 }
 
 /*
- * 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;
-	}
-	
-	printk("Found %02X:%02X\n",
-		desctype, descindex);
-	return parsed;
+	dev->bus->op->allocate(dev);
+
+	return dev;
 }
 
-/*
- * 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_free_dev(struct usb_device *dev)
 {
-	int n_len = ptr[0];
-
-	if (len <= 0)
-		return -1;
+	if (atomic_dec_and_test(&dev->refcnt)) {
+		usb_destroy_configuration(dev);
+		kfree(dev);
 
-	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]);
-		return -1;
+		dev->bus->op->deallocate(dev);
 	}
-
-	if (ptr[1] == desctype)
-		return 0;
-		
-	return -1;
 }
 
-
-static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len)
+void usb_inc_dev_use(struct usb_device *dev)
 {
-	int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE);
-	int i;
-
-	if (parsed < 0)
-		return parsed;
-	memcpy(endpoint, ptr + parsed, ptr[parsed]);
-	le16_to_cpus(&endpoint->wMaxPacketSize);
-
-	parsed += ptr[parsed];
-	len -= parsed;
-
-	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];
-	}
-	
-	return parsed;// + ptr[parsed];
+	atomic_inc(&dev->refcnt);
 }
 
-static int usb_parse_altsetting(struct usb_device *dev, struct usb_interface_descriptor *altsetting, unsigned char *ptr, int len)
+static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
 {
-	int i;
-	int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE);
-	int retval;
+	struct usb_descriptor_header *header;
+	int parsed = 0;
 
-	if (parsed < 0)
-		return parsed;
+	header = (struct usb_descriptor_header *)buffer;
 
-	memcpy(altsetting, ptr + parsed, *ptr);
-	len -= ptr[parsed];
-	parsed += ptr[parsed];
-
-	while((i=usb_check_descriptor(ptr+parsed, len, 0x24)) >= 0) {
-		usb_audio_interface(altsetting, ptr+parsed+i);
-		len -= ptr[parsed+i];
-		parsed += ptr[parsed+i];
-	}
-	
-	if (altsetting->bNumEndpoints > USB_MAXENDPOINTS) {
-		printk(KERN_WARNING "usb: too many endpoints.\n");
+	/* 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;
 	}
-
-	altsetting->endpoint = (struct usb_endpoint_descriptor *)
-		kmalloc(altsetting->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
-	if (!altsetting->endpoint) {
-		printk(KERN_WARNING "usb: out of memory.\n");
-		return -1;	
+		
+	if (header->bDescriptorType != USB_DT_ENDPOINT) {
+		printk(KERN_INFO "usb: unexpected descriptor 0x%X\n",
+			endpoint->bDescriptorType);
+		return parsed;
 	}
-	memset(altsetting->endpoint, 0, altsetting->bNumEndpoints*sizeof(struct usb_endpoint_descriptor));
-	
-	for (i = 0; i < altsetting->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, altsetting->endpoint + i, ptr + parsed, len);
-		if (retval < 0)
-			return retval;
-		parsed += retval;
-		len -= retval;
+
+	memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE);
+        le16_to_cpus(&endpoint->wMaxPacketSize);
+
+	buffer += header->bLength;
+	size -= header->bLength;
+	parsed += header->bLength;
+
+	/* Skip over the rest of the Class Specific or Vendor Specific */
+	/*  descriptors */
+	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_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;
 }
 
-static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor *config, 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 retval;
-	struct usb_interface *intf;
-	struct usb_interface_descriptor as;	/* This is needing for copying. */
-	int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9);
-	unsigned short bNumInterfaces;
-	unsigned short bIntfaceNum = 0, bAltSetting = 0;
 
 	if (parsed < 0)
 		return parsed;
 
-	memcpy(config, ptr + parsed, *ptr);
-	len -= *ptr;
-	parsed += *ptr;
-	le16_to_cpus(&config->wTotalLength);
-	bNumInterfaces = config->bNumInterfaces;
+	memcpy(hid, ptr + parsed, ptr[parsed]);
+	le16_to_cpus(&hid->bcdHID);
 
-	if (bNumInterfaces > USB_MAXINTERFACES) {
-		printk(KERN_WARNING "usb: too many interfaces.\n");
-		return -1;
-	}
+	for (i=0; i<hid->bNumDescriptors; i++)
+		le16_to_cpus(&(hid->desc[i].wDescriptorLength));
 
-	config->interface = (struct usb_interface *)
-	        kmalloc(bNumInterfaces * sizeof(struct usb_interface), GFP_KERNEL);
-	if (!config->interface) {
-		printk(KERN_WARNING "usb: out of memory.\n");
+	return parsed + ptr[parsed];
+}
+#endif
+
+static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size)
+{
+	int i;
+	int retval, parsed = 0;
+	struct usb_descriptor_header *header;
+	struct usb_interface_descriptor *ifp;
+
+	interface->act_altsetting = 0;
+	interface->num_altsetting = 0;
+
+	interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * USB_MAXALTSETTING, GFP_KERNEL);
+	if (!interface->altsetting) {
+		printk("couldn't kmalloc interface->altsetting\n");
 		return -1;
 	}
-	memset(config->interface, 
-		   0, (bNumInterfaces) * sizeof(struct usb_interface));
 
-	for (i = 0; i < bNumInterfaces; i++) {
-		intf = (config->interface) +i;
-		/* We have at least one interface */
-		intf->num_altsetting = 1;
-		intf->altsetting = (struct usb_interface_descriptor*)
-			kmalloc((USB_MAXALTSETTING +1) * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
-		if (!config->interface[i].altsetting) {
-			printk(KERN_WARNING "usb: out of memory.\n");
-			return -1;	
-		}
-		memset(intf->altsetting, 
-			   0, (USB_MAXALTSETTING+1) * sizeof(struct usb_interface_descriptor));
-	}
-		
-	/* Ok, we now have allocated the necessary structures, now decide
-     * where to put the parsed interface descriptors - sort by
-	 * bAltSetting and bInterfaceNumber.
-	 */
-	while (len > 0) {
-		retval = usb_parse_altsetting(dev, &as, ptr + parsed, len);
-		if (retval < 0)
-			return parsed; // HACK
-	//		return retval;
-		parsed += retval;
-		len -= retval;
-		bIntfaceNum = as.bInterfaceNumber;
-		if (bIntfaceNum > config->bNumInterfaces) {
-			printk(KERN_WARNING "usb: bInterfaceNumber %2u exceeding config->bNumINterfaces.\n", bIntfaceNum);
+	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;
 		}
-		bAltSetting = as.bAlternateSetting;
-		if (bAltSetting > USB_MAXALTSETTING) {
-			printk(KERN_WARNING "usb: illegal bAlternateSetting %2u.\n", bAltSetting);
+		memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE);
+
+		/* Skip over the interface */
+		buffer += ifp->bLength;
+		parsed += ifp->bLength;
+		size -= ifp->bLength;
+
+		/* 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;
 		}
-		if (bAltSetting > config->interface[bIntfaceNum].num_altsetting) {
-			config->interface[bIntfaceNum].num_altsetting = bAltSetting +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;	
 		}
-		memcpy( &(config->interface[bIntfaceNum].altsetting[bAltSetting]),
-		   		&as, sizeof(struct usb_interface_descriptor));
+
+		memset(ifp->endpoint, 0, ifp->bNumEndpoints *
+			sizeof(struct usb_endpoint_descriptor));
+	
+		for (i = 0; i < ifp->bNumEndpoints; i++) {
+			header = (struct usb_descriptor_header *)buffer;
+
+			if (header->bLength > size) {
+				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;
+		}
+
+		/* 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;
 	}
 
-	printk("parsed = %d len = %d\n", parsed, len);
 	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) {
-		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_interface *intf;
-	struct usb_interface_descriptor *as;
+	int c, i, j;
 	
 	if (!dev->config)
 		return;
 
 	for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
-		cf = &dev->config[c];
+		struct usb_config_descriptor *cf = &dev->config[c];
+
 		if (!cf->interface)
 		        break;
-		for (a = 0; a < cf->bNumInterfaces; a++) {
-		        intf = &cf->interface[a];
-			if (intf->altsetting == NULL)
+
+		for (i = 0; i < cf->bNumInterfaces; i++) {
+			struct usb_interface *ifp =
+				&cf->interface[i];
+
+			if (!ifp->altsetting)
 			        break;
-			for(i=0; i <= USB_MAXALTSETTING ;i++) {
-			        as = &intf->altsetting[i];
-				if(as->endpoint==NULL)
-				       break;
+
+			for (j = 0; j < ifp->num_altsetting; j++) {
+				struct usb_interface_descriptor *as =
+					&ifp->altsetting[j];
+
+				if (!as->endpoint)
+					break;
+
 				kfree(as->endpoint);
 			}
-			kfree(intf->altsetting);
+			kfree(ifp->altsetting);
 		}
 		kfree(cf->interface);
 	}
@@ -531,29 +539,33 @@
 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
@@ -704,12 +716,13 @@
 static void usb_set_maxpacket(struct usb_device *dev)
 {
 	int i, j;
-	struct usb_interface *intf;
+	struct usb_interface *ifp;
 
 	for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
-		intf = (dev->actconfig->interface) +i;
-		for (j = 0; j < intf->num_altsetting; j++) {
-			struct usb_interface_descriptor *as = intf->altsetting +j;
+		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;
 
@@ -718,7 +731,7 @@
 					dev->epmaxpacketout[ep[e].bEndpointAddress & 0x0f] =
 						ep[e].wMaxPacketSize;
 				else
-					dev->epmaxpacketin[ep[e].bEndpointAddress & 0x0f] =
+					dev->epmaxpacketin [ep[e].bEndpointAddress & 0x0f] =
 						ep[e].wMaxPacketSize;
 			}
 		}
@@ -823,60 +836,78 @@
 	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.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;
 }
 
 
@@ -903,14 +934,15 @@
 		dev->string_langid |= 0x10000;	/* so it's non-zero */
 	}
 
-	if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2)
-	    || usb_get_string(dev, dev->string_langid, index, u.buffer,
+	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;
 
 	len = u.desc.bLength / 2;	/* includes terminating null */
+
 	ptr = kmalloc(len, GFP_KERNEL);
-	if (ptr == 0)
+	if (!ptr)
 		return 0;
 
 	for (i = 0; i < len - 1; ++i)
@@ -943,7 +975,7 @@
 
 	/* Slow devices */
 	if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) {
-		printk(KERN_ERR "USB device not responding, giving up\n");
+		printk(KERN_ERR "usbcore: USB device not responding, giving up\n");
 		dev->devnum = -1;
 		return 1;
 	}
@@ -960,7 +992,7 @@
 	dev->devnum = addr;
 
 	if (usb_set_address(dev)) {
-		printk(KERN_ERR "USB device not accepting new address\n");
+		printk(KERN_ERR "usbcore: USB device not accepting new address\n");
 		dev->devnum = -1;
 		return 1;
 	}
@@ -968,13 +1000,13 @@
 	wait_ms(10);	/* Let the SET_ADDRESS settle */
 
 	if (usb_get_device_descriptor(dev)) {
-		printk(KERN_ERR "Unable to get device descriptor\n");
+		printk(KERN_ERR "usbcore: unable to get device descriptor\n");
 		dev->devnum = -1;
 		return 1;
 	}
 
 	if (usb_get_configuration(dev)) {
-		printk(KERN_ERR "Unable to get configuration\n");
+		printk(KERN_ERR "usbcore: unable to get configuration\n");
 		dev->devnum = -1;
 		return 1;
 	}
@@ -987,6 +1019,9 @@
 	usb_show_string(dev, "Product", dev->descriptor.iProduct);
 	usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
 
+	/* now that the basic setup is over, add a /proc/bus/usb entry */
+	proc_usb_add_device(dev);
+
 	if (!usb_find_driver(dev)) {
 		/*
 		 * Ok, no driver accepted the device, so show the info for
@@ -999,7 +1034,21 @@
 	return 0;
 }
 
-void* 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)
+{
+        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, usb_rcvctrlpipe(dev,0), &dr,
+                data, size);
+}
+
+void *usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
 {
 	return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
 }
@@ -1014,44 +1063,56 @@
 	return dev->bus->op->terminate_bulk(dev, first);
 }
 
-void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+int usb_release_irq(struct usb_device *dev, void *handle)
 {
-	return usb_dev->bus->op->alloc_isoc (usb_dev, pipe, data, len, maxsze, completed, dev_id);
+	return dev->bus->op->release_irq(dev, handle);
 }
 
-void usb_delete_isochronous (struct usb_device *dev, void *_isodesc)
+/*
+ * 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 dev->bus->op->delete_isoc (dev, _isodesc);
+	return usb_dev->bus->op->get_frame_number (usb_dev);
 }
 
-int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
+int usb_init_isoc (struct usb_device *usb_dev,
+			unsigned int pipe,
+			int frame_count,
+			void *context,
+			struct usb_isoc_desc **isocdesc)
 {
-	return usb_dev->bus->op->sched_isoc (usb_dev, _isodesc, _pisodesc);
+	return usb_dev->bus->op->init_isoc (usb_dev, pipe, frame_count, context, isocdesc);
 }
 
-int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc)
+void usb_free_isoc (struct usb_isoc_desc *isocdesc)
 {
-	return usb_dev->bus->op->unsched_isoc (usb_dev, _isodesc);
+	isocdesc->usb_dev->bus->op->free_isoc (isocdesc);
 }
 
-int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
+int usb_run_isoc (struct usb_isoc_desc *isocdesc,
+			struct usb_isoc_desc *pr_isocdesc)
 {
-	return usb_dev->bus->op->compress_isoc (usb_dev, _isodesc);
+	return isocdesc->usb_dev->bus->op->run_isoc (isocdesc, pr_isocdesc);
 }
 
-int usb_release_irq(struct usb_device *dev, void* handle)
+int usb_kill_isoc (struct usb_isoc_desc *isocdesc)
 {
-	return dev->bus->op->release_irq(dev, handle);
+	return isocdesc->usb_dev->bus->op->kill_isoc (isocdesc);
 }
 
 #ifdef CONFIG_PROC_FS
-struct list_head * usb_driver_get_list (void)
+struct list_head *usb_driver_get_list(void)
 {
 	return &usb_driver_list;
 }
 
-struct list_head * usb_bus_get_list (void)
+struct list_head *usb_bus_get_list(void)
 {
 	return &usb_bus_list;
 }
 #endif
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)