bk://kernel.bkbits.net/gregkh/linux/usb-2.6
mochel@digitalimplant.org|ChangeSet|20040326192525|49444 mochel

diff -Nru a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
--- a/drivers/isdn/hisax/hfc_usb.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/isdn/hisax/hfc_usb.c	Fri Mar 26 12:25:30 2004
@@ -262,7 +262,7 @@
 		hfc->ctrl_urb->transfer_buffer_length = 0;
 		hfc->ctrl_write.wIndex = hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg;
 		hfc->ctrl_write.wValue = hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val;
-		err = usb_submit_urb(hfc->ctrl_urb, GFP_KERNEL);	/* start transfer */
+		err = usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC);	/* start transfer */
 		printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err);
 	}
 }				/* ctrl_start_transfer */
@@ -754,7 +754,7 @@
 			}
         }
 
-		errcode = usb_submit_urb(urb, GFP_KERNEL);
+		errcode = usb_submit_urb(urb, GFP_ATOMIC);
 		if(errcode < 0)
 		{
 			printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n",  errcode);
@@ -821,7 +821,7 @@
 		fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets,
 			fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context);
 
-		errcode = usb_submit_urb(urb, GFP_KERNEL);
+		errcode = usb_submit_urb(urb, GFP_ATOMIC);
 		if(errcode < 0)
 		{
 			printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n",  errcode);
@@ -1345,7 +1345,7 @@
 /*************************************************/
 /* function called to probe a new plugged device */
 /*************************************************/
-static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *dev= interface_to_usbdev(intf);
 	hfcusb_data *context;
diff -Nru a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
--- a/drivers/isdn/hisax/st5481_b.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/isdn/hisax/st5481_b.c	Fri Mar 26 12:25:30 2004
@@ -119,7 +119,7 @@
 
 	DBG_ISO_PACKET(0x200,urb);
 
-	SUBMIT_URB(urb, GFP_KERNEL);
+	SUBMIT_URB(urb, GFP_NOIO);
 }
 
 /*
@@ -171,8 +171,8 @@
 	buf_nr = get_buf_nr(b_out->urb, urb);
 	test_and_clear_bit(buf_nr, &b_out->busy);
 
-	if (urb->status < 0) {
-		if (urb->status != -ENOENT) {
+	if (unlikely(urb->status < 0)) {
+		if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) {
 			WARN("urb status %d",urb->status);
 			if (b_out->busy == 0) {
 				st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL);
diff -Nru a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
--- a/drivers/isdn/hisax/st5481_d.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/isdn/hisax/st5481_d.c	Fri Mar 26 12:25:30 2004
@@ -381,8 +381,8 @@
 	buf_nr = get_buf_nr(d_out->urb, urb);
 	test_and_clear_bit(buf_nr, &d_out->busy);
 
-	if (urb->status < 0) {
-		if (urb->status != -ENOENT) {
+	if (unlikely(urb->status < 0)) {
+		if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) {
 			WARN("urb status %d",urb->status);
 			if (d_out->busy == 0) {
 				st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
@@ -649,7 +649,7 @@
 	st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
 }
 
-static int __devinit st5481_setup_d_out(struct st5481_adapter *adapter)
+static int st5481_setup_d_out(struct st5481_adapter *adapter)
 {
 	struct usb_device *dev = adapter->usb_dev;
 	struct usb_host_interface *altsetting;
@@ -682,7 +682,7 @@
 	st5481_release_isocpipes(d_out->urb);
 }
 
-int __devinit st5481_setup_d(struct st5481_adapter *adapter)
+int st5481_setup_d(struct st5481_adapter *adapter)
 {
 	int retval;
 
diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
--- a/drivers/isdn/hisax/st5481_init.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/isdn/hisax/st5481_init.c	Fri Mar 26 12:25:30 2004
@@ -58,8 +58,8 @@
  * This function will be called when the adapter is plugged
  * into the USB bus.
  */
-static int __devinit probe_st5481(struct usb_interface *intf,
-				     const struct usb_device_id *id)
+static int probe_st5481(struct usb_interface *intf,
+			const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct st5481_adapter *adapter;
diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
--- a/drivers/isdn/hisax/st5481_usb.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/isdn/hisax/st5481_usb.c	Fri Mar 26 12:25:30 2004
@@ -48,7 +48,7 @@
 	// Prepare the URB
 	urb->dev = adapter->usb_dev;
 
-	SUBMIT_URB(urb, GFP_KERNEL);
+	SUBMIT_URB(urb, GFP_ATOMIC);
 }
 
 /*
@@ -129,8 +129,8 @@
 	struct st5481_ctrl *ctrl = &adapter->ctrl;
 	struct ctrl_msg *ctrl_msg;
 	
-	if (urb->status < 0) {
-		if (urb->status != -ENOENT) {
+	if (unlikely(urb->status < 0)) {
+		if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) {
 			WARN("urb status %d",urb->status);
 		} else {
 			DBG(1,"urb killed");
@@ -239,7 +239,7 @@
  * initialization
  */
 
-int __devinit st5481_setup_usb(struct st5481_adapter *adapter)
+int st5481_setup_usb(struct st5481_adapter *adapter)
 {
 	struct usb_device *dev = adapter->usb_dev;
 	struct st5481_ctrl *ctrl = &adapter->ctrl;
@@ -341,7 +341,7 @@
 /*
  *  Initialize the adapter.
  */
-void __devinit st5481_start(struct st5481_adapter *adapter)
+void st5481_start(struct st5481_adapter *adapter)
 {
 	static const u8 init_cmd_table[]={
 		SET_DEFAULT,0,
@@ -381,7 +381,7 @@
 /*
  * Reset the adapter to default values.
  */
-void __devexit st5481_stop(struct st5481_adapter *adapter)
+void st5481_stop(struct st5481_adapter *adapter)
 {
 	DBG(8,"");
 
@@ -392,7 +392,7 @@
  * isochronous USB  helpers
  */
 
-static void __devinit
+static void
 fill_isoc_urb(struct urb *urb, struct usb_device *dev,
 	      unsigned int pipe, void *buf, int num_packets, 
 	      int packet_size, usb_complete_t complete,
@@ -417,7 +417,7 @@
 	}
 }
 
-int __devinit
+int
 st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, 
 			   unsigned int pipe, int num_packets,
 			   int packet_size, int buf_size,
@@ -481,8 +481,8 @@
 	struct sk_buff *skb;
 	int len, count, status;
 
-	if (urb->status < 0) {
-		if (urb->status != -ENOENT) {
+	if (unlikely(urb->status < 0)) {
+		if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) {
 			WARN("urb status %d",urb->status);
 		} else {
 			DBG(1,"urb killed");
@@ -529,10 +529,10 @@
 	urb->dev = in->adapter->usb_dev;
 	urb->actual_length = 0;
 
-	SUBMIT_URB(urb, GFP_KERNEL);
+	SUBMIT_URB(urb, GFP_ATOMIC);
 }
 
-int __devinit st5481_setup_in(struct st5481_in *in)
+int st5481_setup_in(struct st5481_in *in)
 {
 	struct usb_device *dev = in->adapter->usb_dev;
 	int retval;
diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/Makefile	Fri Mar 26 12:25:30 2004
@@ -55,8 +55,11 @@
 obj-$(CONFIG_USB_SERIAL)	+= serial/
 
 obj-$(CONFIG_USB_AUERSWALD)	+= misc/
+obj-$(CONFIG_USB_CYTHERM)	+= misc/
 obj-$(CONFIG_USB_EMI26)		+= misc/
+obj-$(CONFIG_USB_EMI62)		+= misc/
 obj-$(CONFIG_USB_LCD)		+= misc/
+obj-$(CONFIG_USB_LED)		+= misc/
 obj-$(CONFIG_USB_LEGOTOWER)	+= misc/
 obj-$(CONFIG_USB_RIO500)	+= misc/
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= misc/
diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/core/config.c	Fri Mar 26 12:25:30 2004
@@ -1,28 +1,62 @@
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#endif
+
 #include <linux/usb.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/device.h>
 #include <asm/byteorder.h>
 
 
 #define USB_MAXALTSETTING		128	/* Hard limit */
 #define USB_MAXENDPOINTS		30	/* Hard limit */
 
-/* these maximums are arbitrary */
-#define USB_MAXCONFIG			8
-#define USB_MAXINTERFACES		32
+#define USB_MAXCONFIG			8	/* Arbitrary limit */
+
 
-static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size)
+static int find_next_descriptor(unsigned char *buffer, int size,
+    int dt1, int dt2, int *num_skipped)
+{
+	struct usb_descriptor_header *h;
+	int n = 0;
+	unsigned char *buffer0 = buffer;
+
+	/* Find the next descriptor of type dt1 or dt2 */
+	while (size >= sizeof(struct usb_descriptor_header)) {
+		h = (struct usb_descriptor_header *) buffer;
+		if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2)
+			break;
+		buffer += h->bLength;
+		size -= h->bLength;
+		++n;
+	}
+
+	/* Store the number of descriptors skipped and return the
+	 * number of bytes skipped */
+	if (num_skipped)
+		*num_skipped = n;
+	return buffer - buffer0;
+}
+
+static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
+    int asnum, struct usb_host_endpoint *endpoint,
+    unsigned char *buffer, int size)
 {
 	unsigned char *buffer0 = buffer;
 	struct usb_descriptor_header *header;
-	unsigned char *begin;
-	int numskipped;
+	int n, i;
 
 	header = (struct usb_descriptor_header *)buffer;
 	if (header->bDescriptorType != USB_DT_ENDPOINT) {
-		warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X",
-			header->bDescriptorType, USB_DT_ENDPOINT);
+		dev_err(ddev, "config %d interface %d altsetting %d has an "
+		    "unexpected descriptor of type 0x%X, "
+		    "expecting endpoint type 0x%X\n",
+		    cfgno, inum, asnum,
+		    header->bDescriptorType, USB_DT_ENDPOINT);
 		return -EINVAL;
 	}
 
@@ -31,13 +65,17 @@
 	else if (header->bLength >= USB_DT_ENDPOINT_SIZE)
 		memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE);
 	else {
-		warn("invalid endpoint descriptor");
+		dev_err(ddev, "config %d interface %d altsetting %d has an "
+		    "invalid endpoint descriptor of length %d\n",
+		    cfgno, inum, asnum, header->bLength);
 		return -EINVAL;
 	}
 
-	if ((endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK) >= 16) {
-		warn("invalid endpoint address 0x%X",
-		    endpoint->desc.bEndpointAddress);
+	i = endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;
+	if (i >= 16 || i == 0) {
+		dev_err(ddev, "config %d interface %d altsetting %d has an "
+		    "invalid endpoint with address 0x%X\n",
+		    cfgno, inum, asnum, endpoint->desc.bEndpointAddress);
 		return -EINVAL;
 	}
 
@@ -46,30 +84,16 @@
 	buffer += header->bLength;
 	size -= header->bLength;
 
-	/* Skip over any Class Specific or Vendor Specific descriptors */
-	begin = buffer;
-	numskipped = 0;
-	while (size >= sizeof(struct usb_descriptor_header)) {
-		header = (struct usb_descriptor_header *)buffer;
-
-		/* If we find another "proper" descriptor then we're done  */
-		if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
-		    (header->bDescriptorType == USB_DT_INTERFACE))
-			break;
-
-		dbg("skipping descriptor 0x%X", header->bDescriptorType);
-		numskipped++;
-
-		buffer += header->bLength;
-		size -= header->bLength;
-	}
-	if (numskipped) {
-		dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
-		endpoint->extra = begin;
-		endpoint->extralen = buffer - begin;
-	}
-
-	return buffer - buffer0;
+	/* Skip over any Class Specific or Vendor Specific descriptors;
+	 * find the next endpoint or interface descriptor */
+	endpoint->extra = buffer;
+	i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
+	    USB_DT_INTERFACE, &n);
+	endpoint->extralen = i;
+	if (n > 0)
+		dev_dbg(ddev, "skipped %d class/vendor specific endpoint "
+		    "descriptors\n", n);
+	return buffer - buffer0 + i;
 }
 
 static void usb_free_intf(struct usb_interface *intf)
@@ -78,253 +102,235 @@
 
 	if (intf->altsetting) {
 		for (j = 0; j < intf->num_altsetting; j++) {
-			struct usb_host_interface *as = &intf->altsetting[j];
+			struct usb_host_interface *alt = &intf->altsetting[j];
 
-			kfree(as->endpoint);
+			kfree(alt->endpoint);
 		}
 		kfree(intf->altsetting);
 	}
 	kfree(intf);
 }
 
-static int usb_parse_interface(struct usb_host_config *config, unsigned char *buffer, int size)
+static int usb_parse_interface(struct device *ddev, int cfgno,
+    struct usb_host_config *config, unsigned char *buffer, int size)
 {
 	unsigned char *buffer0 = buffer;
 	struct usb_interface_descriptor	*d;
 	int inum, asnum;
 	struct usb_interface *interface;
-	struct usb_host_interface *ifp;
-	int len, numskipped;
-	struct usb_descriptor_header *header;
-	unsigned char *begin;
-	int i, retval;
+	struct usb_host_interface *alt;
+	int i, n;
+	int len, retval;
 
 	d = (struct usb_interface_descriptor *) buffer;
+	buffer += d->bLength;
+	size -= d->bLength;
+
 	if (d->bDescriptorType != USB_DT_INTERFACE) {
-		warn("unexpected descriptor 0x%X, expecting interface, 0x%X",
-			d->bDescriptorType, USB_DT_INTERFACE);
+		dev_err(ddev, "config %d has an unexpected descriptor of type "
+		    "0x%X, expecting interface type 0x%X\n",
+		    cfgno, d->bDescriptorType, USB_DT_INTERFACE);
 		return -EINVAL;
 	}
 
 	inum = d->bInterfaceNumber;
-	if (inum >= config->desc.bNumInterfaces) {
-
-		/* Skip to the next interface descriptor */
-		buffer += d->bLength;
-		size -= d->bLength;
-		while (size >= sizeof(struct usb_descriptor_header)) {
-			header = (struct usb_descriptor_header *) buffer;
-
-			if (header->bDescriptorType == USB_DT_INTERFACE)
-				break;
-			buffer += header->bLength;
-			size -= header->bLength;
-		}
-		return buffer - buffer0;
-	}
+	if (inum >= config->desc.bNumInterfaces)
+		goto skip_to_next_interface_descriptor;
 
 	interface = config->interface[inum];
 	asnum = d->bAlternateSetting;
 	if (asnum >= interface->num_altsetting) {
-		warn("invalid alternate setting %d for interface %d",
-		    asnum, inum);
+		dev_err(ddev, "config %d interface %d has an invalid "
+		    "alternate setting number: %d but max is %d\n",
+		    cfgno, inum, asnum, interface->num_altsetting - 1);
 		return -EINVAL;
 	}
 
-	ifp = &interface->altsetting[asnum];
-	if (ifp->desc.bLength) {
-		warn("duplicate descriptor for interface %d altsetting %d",
-		    inum, asnum);
+	alt = &interface->altsetting[asnum];
+	if (alt->desc.bLength) {
+		dev_err(ddev, "Duplicate descriptor for config %d "
+		    "interface %d altsetting %d\n", cfgno, inum, asnum);
 		return -EINVAL;
 	}
-	memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE);
-
-	buffer += d->bLength;
-	size -= d->bLength;
-
-	/* Skip over any Class Specific or Vendor Specific descriptors */
-	begin = buffer;
-	numskipped = 0;
-	while (size >= sizeof(struct usb_descriptor_header)) {
-		header = (struct usb_descriptor_header *)buffer;
-
-		/* If we find another "proper" descriptor then we're done  */
-		if ((header->bDescriptorType == USB_DT_INTERFACE) ||
-		    (header->bDescriptorType == USB_DT_ENDPOINT))
-			break;
-
-		dbg("skipping descriptor 0x%X", header->bDescriptorType);
-		numskipped++;
-
-		buffer += header->bLength;
-		size -= header->bLength;
-	}
-	if (numskipped) {
-		dbg("skipped %d class/vendor specific interface descriptors", numskipped);
-		ifp->extra = begin;
-		ifp->extralen = buffer - begin;
-	}
+	memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE);
 
-	if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
-		warn("too many endpoints for interface %d altsetting %d",
-		    inum, asnum);
+	/* Skip over any Class Specific or Vendor Specific descriptors;
+	 * find the first endpoint or interface descriptor */
+	alt->extra = buffer;
+	i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
+	    USB_DT_INTERFACE, &n);
+	alt->extralen = i;
+	if (n > 0)
+		dev_dbg(ddev, "skipped %d class/vendor specific "
+		    "interface descriptors\n", n);
+	buffer += i;
+	size -= i;
+
+	if (alt->desc.bNumEndpoints > USB_MAXENDPOINTS) {
+		dev_err(ddev, "too many endpoints for config %d interface %d "
+		    "altsetting %d: %d, maximum allowed: %d\n",
+		    cfgno, inum, asnum, alt->desc.bNumEndpoints,
+		    USB_MAXENDPOINTS);
 		return -EINVAL;
 	}
 
-	len = ifp->desc.bNumEndpoints * sizeof(struct usb_host_endpoint);
-	ifp->endpoint = kmalloc(len, GFP_KERNEL);
-	if (!ifp->endpoint) {
-		err("out of memory");
+	len = alt->desc.bNumEndpoints * sizeof(struct usb_host_endpoint);
+	alt->endpoint = kmalloc(len, GFP_KERNEL);
+	if (!alt->endpoint)
 		return -ENOMEM;
-	}
-	memset(ifp->endpoint, 0, len);
+	memset(alt->endpoint, 0, len);
 
-	for (i = 0; i < ifp->desc.bNumEndpoints; i++) {
+	for (i = 0; i < alt->desc.bNumEndpoints; i++) {
 		if (size < USB_DT_ENDPOINT_SIZE) {
-			warn("ran out of descriptors while parsing endpoints");
+			dev_err(ddev, "too few endpoint descriptors for "
+			    "config %d interface %d altsetting %d\n",
+			    cfgno, inum, asnum);
 			return -EINVAL;
 		}
 
-		retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
+		retval = usb_parse_endpoint(ddev, cfgno, inum, asnum,
+		    alt->endpoint + i, buffer, size);
 		if (retval < 0)
 			return retval;
 
 		buffer += retval;
 		size -= retval;
 	}
-
 	return buffer - buffer0;
+
+skip_to_next_interface_descriptor:
+	i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
+	    USB_DT_INTERFACE, NULL);
+	return buffer - buffer0 + i;
 }
 
-int usb_parse_configuration(struct usb_host_config *config, char *buffer, int size)
+int usb_parse_configuration(struct device *ddev, int cfgidx,
+    struct usb_host_config *config, unsigned char *buffer, int size)
 {
+	int cfgno;
 	int nintf, nintf_orig;
-	int i, j;
+	int i, j, n;
 	struct usb_interface *interface;
-	char *buffer2;
+	unsigned char *buffer2;
 	int size2;
 	struct usb_descriptor_header *header;
-	int numskipped, len;
-	char *begin;
-	int retval;
+	int len, retval;
 
 	memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
 	if (config->desc.bDescriptorType != USB_DT_CONFIG ||
 	    config->desc.bLength < USB_DT_CONFIG_SIZE) {
-		warn("invalid configuration descriptor");
+		dev_err(ddev, "invalid descriptor for config index %d: "
+		    "type = 0x%X, length = %d\n", cfgidx,
+		    config->desc.bDescriptorType, config->desc.bLength);
 		return -EINVAL;
 	}
 	config->desc.wTotalLength = size;
+	cfgno = config->desc.bConfigurationValue;
+
+	buffer += config->desc.bLength;
+	size -= config->desc.bLength;
 
 	nintf = nintf_orig = config->desc.bNumInterfaces;
 	if (nintf > USB_MAXINTERFACES) {
-		warn("too many interfaces (%d max %d)",
-		    nintf, USB_MAXINTERFACES);
+		dev_warn(ddev, "config %d has too many interfaces: %d, "
+		    "using maximum allowed: %d\n",
+		    cfgno, nintf, USB_MAXINTERFACES);
 		config->desc.bNumInterfaces = nintf = USB_MAXINTERFACES;
 	}
 
 	for (i = 0; i < nintf; ++i) {
 		interface = config->interface[i] =
 		    kmalloc(sizeof(struct usb_interface), GFP_KERNEL);
-		dbg("kmalloc IF %p, numif %i", interface, i);
-		if (!interface) {
-			err("out of memory");
+		if (!interface)
 			return -ENOMEM;
-		}
 		memset(interface, 0, sizeof(struct usb_interface));
 	}
 
 	/* Go through the descriptors, checking their length and counting the
 	 * number of altsettings for each interface */
-	buffer2 = buffer;
-	size2 = size;
-	j = 0;
-	while (size2 >= sizeof(struct usb_descriptor_header)) {
+	for ((buffer2 = buffer, size2 = size);
+	      size2 >= sizeof(struct usb_descriptor_header);
+	     (buffer2 += header->bLength, size2 -= header->bLength)) {
+
 		header = (struct usb_descriptor_header *) buffer2;
 		if ((header->bLength > size2) || (header->bLength < 2)) {
-			warn("invalid descriptor of length %d", header->bLength);
+			dev_err(ddev, "config %d has an invalid descriptor "
+			    "of length %d\n", cfgno, header->bLength);
 			return -EINVAL;
 		}
 
 		if (header->bDescriptorType == USB_DT_INTERFACE) {
 			struct usb_interface_descriptor *d;
 
-			if (header->bLength < USB_DT_INTERFACE_SIZE) {
-				warn("invalid interface descriptor");
+			d = (struct usb_interface_descriptor *) header;
+			if (d->bLength < USB_DT_INTERFACE_SIZE) {
+				dev_err(ddev, "config %d has an invalid "
+				    "interface descriptor of length %d\n",
+				    cfgno, d->bLength);
 				return -EINVAL;
 			}
-			d = (struct usb_interface_descriptor *) header;
+
 			i = d->bInterfaceNumber;
 			if (i >= nintf_orig) {
-				warn("invalid interface number (%d/%d)",
-				    i, nintf_orig);
+				dev_err(ddev, "config %d has an invalid "
+				    "interface number: %d but max is %d\n",
+				    cfgno, i, nintf_orig - 1);
 				return -EINVAL;
 			}
 			if (i < nintf)
 				++config->interface[i]->num_altsetting;
 
-		} else if ((header->bDescriptorType == USB_DT_DEVICE ||
-		    header->bDescriptorType == USB_DT_CONFIG) && j) {
-			warn("unexpected descriptor type 0x%X", header->bDescriptorType);
+		} else if (header->bDescriptorType == USB_DT_DEVICE ||
+			    header->bDescriptorType == USB_DT_CONFIG) {
+			dev_err(ddev, "config %d contains an unexpected "
+			    "descriptor of type 0x%X\n",
+			    cfgno, header->bDescriptorType);
 			return -EINVAL;
 		}
 
-		j = 1;
-		buffer2 += header->bLength;
-		size2 -= header->bLength;
-	}
+	}	/* for ((buffer2 = buffer, size2 = size); ...) */
 
 	/* Allocate the altsetting arrays */
-	for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+	for (i = 0; i < nintf; ++i) {
 		interface = config->interface[i];
 		if (interface->num_altsetting > USB_MAXALTSETTING) {
-			warn("too many alternate settings for interface %d (%d max %d)\n",
-			    i, interface->num_altsetting, USB_MAXALTSETTING);
+			dev_err(ddev, "too many alternate settings for "
+			    "config %d interface %d: %d, "
+			    "maximum allowed: %d\n",
+			    cfgno, i, interface->num_altsetting,
+			    USB_MAXALTSETTING);
 			return -EINVAL;
 		}
 		if (interface->num_altsetting == 0) {
-			warn("no alternate settings for interface %d", i);
+			dev_err(ddev, "config %d has no interface number "
+			    "%d\n", cfgno, i);
 			return -EINVAL;
 		}
 
-		len = sizeof(*interface->altsetting) * interface->num_altsetting;
+		len = sizeof(*interface->altsetting) *
+		    interface->num_altsetting;
 		interface->altsetting = kmalloc(len, GFP_KERNEL);
-		if (!interface->altsetting) {
-			err("couldn't kmalloc interface->altsetting");
+		if (!interface->altsetting)
 			return -ENOMEM;
-		}
 		memset(interface->altsetting, 0, len);
 	}
 
-	buffer += config->desc.bLength;
-	size -= config->desc.bLength;
-
-	/* Skip over any Class Specific or Vendor Specific descriptors */
-	begin = buffer;
-	numskipped = 0;
-	while (size >= sizeof(struct usb_descriptor_header)) {
-		header = (struct usb_descriptor_header *)buffer;
-
-		/* If we find another "proper" descriptor then we're done  */
-		if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
-		    (header->bDescriptorType == USB_DT_INTERFACE))
-			break;
-
-		dbg("skipping descriptor 0x%X", header->bDescriptorType);
-		numskipped++;
-
-		buffer += header->bLength;
-		size -= header->bLength;
-	}
-	if (numskipped) {
-		dbg("skipped %d class/vendor specific configuration descriptors", numskipped);
-		config->extra = begin;
-		config->extralen = buffer - begin;
-	}
+	/* Skip over any Class Specific or Vendor Specific descriptors;
+	 * find the first interface descriptor */
+	config->extra = buffer;
+	i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
+	    USB_DT_INTERFACE, &n);
+	config->extralen = i;
+	if (n > 0)
+		dev_dbg(ddev, "skipped %d class/vendor specific "
+		    "configuration descriptors\n", n);
+	buffer += i;
+	size -= i;
 
 	/* Parse all the interface/altsetting descriptors */
 	while (size >= sizeof(struct usb_descriptor_header)) {
-		retval = usb_parse_interface(config, buffer, size);
+		retval = usb_parse_interface(ddev, cfgno, config,
+		    buffer, size);
 		if (retval < 0)
 			return retval;
 
@@ -337,7 +343,8 @@
 		interface = config->interface[i];
 		for (j = 0; j < interface->num_altsetting; ++j) {
 			if (!interface->altsetting[j].desc.bLength) {
-				warn("missing altsetting %d for interface %d", j, i);
+				dev_err(ddev, "config %d interface %d has no "
+				    "altsetting %d\n", cfgno, i, j);
 				return -EINVAL;
 			}
 		}
@@ -380,81 +387,77 @@
 // (used by real hubs and virtual root hubs)
 int usb_get_configuration(struct usb_device *dev)
 {
+	struct device *ddev = &dev->dev;
 	int ncfg = dev->descriptor.bNumConfigurations;
-	int result;
+	int result = -ENOMEM;
 	unsigned int cfgno, length;
 	unsigned char *buffer;
 	unsigned char *bigbuffer;
  	struct usb_config_descriptor *desc;
 
 	if (ncfg > USB_MAXCONFIG) {
-		warn("too many configurations (%d max %d)",
-		    ncfg, USB_MAXCONFIG);
+		dev_warn(ddev, "too many configurations: %d, "
+		    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
 		dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
 	}
 
 	if (ncfg < 1) {
-		warn("no configurations");
+		dev_err(ddev, "no configurations\n");
 		return -EINVAL;
 	}
 
 	length = ncfg * sizeof(struct usb_host_config);
 	dev->config = kmalloc(length, GFP_KERNEL);
-	if (!dev->config) {
-		err("out of memory");
-		return -ENOMEM;
-	}
+	if (!dev->config)
+		goto err2;
 	memset(dev->config, 0, length);
 
 	length = ncfg * sizeof(char *);
 	dev->rawdescriptors = kmalloc(length, GFP_KERNEL);
-	if (!dev->rawdescriptors) {
-		err("out of memory");
-		return -ENOMEM;
-	}
+	if (!dev->rawdescriptors)
+		goto err2;
 	memset(dev->rawdescriptors, 0, length);
 
 	buffer = kmalloc(8, GFP_KERNEL);
-	if (!buffer) {
-		err("unable to allocate memory for configuration descriptors");
-		return -ENOMEM;
-	}
+	if (!buffer)
+		goto err2;
 	desc = (struct usb_config_descriptor *)buffer;
 
 	for (cfgno = 0; cfgno < ncfg; cfgno++) {
 		/* We grab the first 8 bytes so we know how long the whole */
-		/*  configuration is */
-		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
-		if (result < 8) {
-			if (result < 0)
-				err("unable to get descriptor");
-			else {
-				warn("config descriptor too short (expected %i, got %i)", 8, result);
-				result = -EINVAL;
-			}
+		/* configuration is */
+		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
+		    buffer, 8);
+		if (result < 0) {
+			dev_err(ddev, "unable to read config index %d "
+			    "descriptor\n", cfgno);
+			goto err;
+		} else if (result < 8) {
+			dev_err(ddev, "config index %d descriptor too short "
+			    "(expected %i, got %i)\n", cfgno, 8, result);
+			result = -EINVAL;
 			goto err;
 		}
+		length = max((int) le16_to_cpu(desc->wTotalLength),
+		    USB_DT_CONFIG_SIZE);
 
-  	  	/* Get the full buffer */
-		length = max((int) le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE);
-
+		/* Now that we know the length, get the whole thing */
 		bigbuffer = kmalloc(length, GFP_KERNEL);
 		if (!bigbuffer) {
-			err("unable to allocate memory for configuration descriptors");
 			result = -ENOMEM;
 			goto err;
 		}
-
-		/* Now that we know the length, get the whole thing */
-		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
+		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
+		    bigbuffer, length);
 		if (result < 0) {
-			err("couldn't get all of config descriptors");
+			dev_err(ddev, "unable to read config index %d "
+			    "descriptor\n", cfgno);
 			kfree(bigbuffer);
 			goto err;
 		}
-
 		if (result < length) {
-			err("config descriptor too short (expected %i, got %i)", length, result);
+			dev_err(ddev, "config index %d descriptor too short "
+			    "(expected %i, got %i)\n", cfgno, length, result);
 			result = -EINVAL;
 			kfree(bigbuffer);
 			goto err;
@@ -462,20 +465,23 @@
 
 		dev->rawdescriptors[cfgno] = bigbuffer;
 
-		result = usb_parse_configuration(&dev->config[cfgno], bigbuffer, length);
+		result = usb_parse_configuration(&dev->dev, cfgno,
+		    &dev->config[cfgno], bigbuffer, length);
 		if (result > 0)
-			dbg("descriptor data left");
+			dev_dbg(ddev, "config index %d descriptor has %d "
+			    "excess byte(s)\n", cfgno, result);
 		else if (result < 0) {
 			++cfgno;
 			goto err;
 		}
 	}
+	result = 0;
 
-	kfree(buffer);
-	return 0;
 err:
 	kfree(buffer);
 	dev->descriptor.bNumConfigurations = cfgno;
+err2:
+	if (result == -ENOMEM)
+		dev_err(ddev, "out of memory\n");
 	return result;
 }
-
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/core/devio.c	Fri Mar 26 12:25:30 2004
@@ -124,14 +124,25 @@
 		unsigned int length = le16_to_cpu(config->wTotalLength);
 
 		if (*ppos < pos + length) {
+
+			/* The descriptor may claim to be longer than it
+			 * really is.  Here is the actual allocated length. */
+			unsigned alloclen =
+				ps->dev->config[i].desc.wTotalLength;
+
 			len = length - (*ppos - pos);
 			if (len > nbytes)
 				len = nbytes;
 
-			if (copy_to_user(buf,
-			    ps->dev->rawdescriptors[i] + (*ppos - pos), len)) {
-				ret = -EFAULT;
-				goto err;
+			/* Simply don't write (skip over) unallocated parts */
+			if (alloclen > (*ppos - pos)) {
+				alloclen -= (*ppos - pos);
+				if (copy_to_user(buf,
+				    ps->dev->rawdescriptors[i] + (*ppos - pos),
+				    min(len, alloclen))) {
+					ret = -EFAULT;
+					goto err;
+				}
 			}
 
 			*ppos += len;
diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/core/hcd-pci.c	Fri Mar 26 12:25:30 2004
@@ -80,7 +80,8 @@
 		return -ENODEV;
 	
         if (!dev->irq) {
-        	err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
+        	dev_err (&dev->dev,
+			"Found HC with no IRQ.  Check BIOS/PCI %s setup!\n",
 			pci_name(dev));
    	        return -ENODEV;
         }
@@ -90,16 +91,17 @@
 		resource = pci_resource_start (dev, 0);
 		len = pci_resource_len (dev, 0);
 		if (!request_mem_region (resource, len, driver->description)) {
-			dbg ("controller already in use");
+			dev_dbg (&dev->dev, "controller already in use\n");
 			return -EBUSY;
 		}
 		base = ioremap_nocache (resource, len);
 		if (base == NULL) {
-			dbg ("error mapping memory");
+			dev_dbg (&dev->dev, "error mapping memory\n");
 			retval = -EFAULT;
 clean_1:
 			release_mem_region (resource, len);
-			err ("init %s fail, %d", pci_name(dev), retval);
+			dev_err (&dev->dev, "init %s fail, %d\n",
+				pci_name(dev), retval);
 			return retval;
 		}
 
@@ -116,7 +118,7 @@
 				break;
 		}
 		if (region == PCI_ROM_RESOURCE) {
-			dbg ("no i/o regions available");
+			dev_dbg (&dev->dev, "no i/o regions available\n");
 			return -EBUSY;
 		}
 		base = (void *) resource;
@@ -127,7 +129,7 @@
 
 	hcd = driver->hcd_alloc ();
 	if (hcd == NULL){
-		dbg ("hcd alloc fail");
+		dev_dbg (&dev->dev, "hcd alloc fail\n");
 		retval = -ENOMEM;
 clean_2:
 		if (driver->flags & HCD_MEMORY) {
@@ -135,7 +137,8 @@
 			goto clean_1;
 		} else {
 			release_region (resource, len);
-			err ("init %s fail, %d", pci_name(dev), retval);
+			dev_err (&dev->dev, "init %s fail, %d\n",
+				pci_name(dev), retval);
 			return retval;
 		}
 	}
@@ -193,13 +196,16 @@
 	hcd->self.op = &usb_hcd_operations;
 	hcd->self.hcpriv = (void *) hcd;
 	hcd->self.release = &hcd_pci_release;
+	init_timer (&hcd->rh_timer);
 
 	INIT_LIST_HEAD (&hcd->dev_list);
 
 	usb_register_bus (&hcd->self);
 
-	if ((retval = driver->start (hcd)) < 0)
+	if ((retval = driver->start (hcd)) < 0) {
+		dev_err (hcd->self.controller, "init error %d\n", retval);
 		usb_hcd_pci_remove (dev);
+	}
 
 	return retval;
 } 
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/core/hcd.c	Fri Mar 26 12:25:30 2004
@@ -42,6 +42,8 @@
 #include <asm/byteorder.h>
 
 #include <linux/usb.h>
+
+#include "usb.h"
 #include "hcd.h"
 
 
@@ -678,8 +680,10 @@
 	if (busnum < USB_MAXBUS) {
 		set_bit (busnum, busmap.busmap);
 		bus->busnum = busnum;
-	} else
-		warn ("too many buses");
+	} else {
+		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
+		return -E2BIG;
+	}
 
 	snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum);
 	bus->class_dev.class = &usb_host_class;
@@ -804,7 +808,7 @@
 			tmp = HS_USECS_ISO (bytecount);
 		return tmp;
 	default:
-		dbg ("bogus device speed!");
+		pr_debug ("%s: bogus device speed!\n", usbcore_name);
 		return -1;
 	}
 }
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/core/hub.c	Fri Mar 26 12:25:30 2004
@@ -212,8 +212,7 @@
 		spin_lock_irqsave (&hub->tt.lock, flags);
 
 		if (status)
-			err ("usb-%s-%s clear tt %d (%04x) error %d",
-				dev->bus->bus_name, dev->devpath,
+			dev_err (&dev->dev, "clear tt %d (%04x) error %d\n",
 				clear->tt, clear->devinfo, status);
 		kfree (clear);
 	}
@@ -244,8 +243,7 @@
 	 * there can be many TTs per hub).  even if they're uncommon.
 	 */
 	if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) {
-		err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s",
-			dev->bus->bus_name, tt->hub->devpath);
+		dev_err (&dev->dev, "can't save CLEAR_TT_BUFFER state\n");
 		/* FIXME recover somehow ... RESET_TT? */
 		return;
 	}
@@ -596,7 +594,7 @@
 
 	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
 	if (!hub) {
-		err("couldn't kmalloc hub struct");
+		dev_dbg (hubdev(dev), "couldn't kmalloc hub struct\n");
 		return -ENOMEM;
 	}
 
@@ -700,7 +698,7 @@
 		}
 	}
 
-	err("cannot disconnect hub %s", dev->devpath);
+	dev_err(&dev->dev, "cannot disconnect hub!\n");
 }
 
 static int hub_port_status(struct usb_device *dev, int port,
@@ -1145,7 +1143,7 @@
 			refrigerator(PF_IOTHREAD);
 	} while (!signal_pending(current));
 
-	dbg("hub_thread exiting");
+	pr_debug ("%s: khubd exiting\n", usbcore_name);
 	complete_and_exit(&khubd_exited, 0);
 }
 
@@ -1176,7 +1174,8 @@
 	pid_t pid;
 
 	if (usb_register(&hub_driver) < 0) {
-		err("Unable to register USB hub driver");
+		printk(KERN_ERR "%s: can't register hub driver\n",
+			usbcore_name);
 		return -1;
 	}
 
@@ -1189,7 +1188,7 @@
 
 	/* Fall through if kernel_thread failed */
 	usb_deregister(&hub_driver);
-	err("failed to start hub_thread");
+	printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
 
 	return -1;
 }
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/core/message.c	Fri Mar 26 12:25:30 2004
@@ -935,7 +935,8 @@
 
 	iface = usb_ifnum_to_if(dev, interface);
 	if (!iface) {
-		warn("selecting invalid interface %d", interface);
+		dev_dbg(&dev->dev, "selecting invalid interface %d\n",
+			interface);
 		return -EINVAL;
 	}
 
@@ -953,8 +954,9 @@
 	 * request if the interface only has one alternate setting.
 	 */
 	if (ret == -EPIPE && iface->num_altsetting == 1) {
-		dbg("manual set_interface for dev %d, iface %d, alt %d",
-			dev->devnum, interface, alternate);
+		dev_dbg(&dev->dev,
+			"manual set_interface for iface %d, alt %d\n",
+			interface, alternate);
 		manual = 1;
 	} else if (ret < 0)
 		return ret;
@@ -1233,18 +1235,20 @@
 	if (!dev->have_langid) {
 		err = usb_get_string(dev, 0, 0, tbuf, 4);
 		if (err < 0) {
-			err("error getting string descriptor 0 (error=%d)", err);
+			dev_err (&dev->dev,
+				"string descriptor 0 read error: %d\n",
+				err);
 			goto errout;
 		} else if (err < 4 || tbuf[0] < 4) {
-			err("string descriptor 0 too short");
+			dev_err (&dev->dev, "string descriptor 0 too short\n");
 			err = -EINVAL;
 			goto errout;
 		} else {
 			dev->have_langid = -1;
 			dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
 				/* always use the first langid listed */
-			dbg("USB device number %d default language ID 0x%x",
-				dev->devnum, dev->string_langid);
+			dev_dbg (&dev->dev, "default language 0x%04x\n",
+				dev->string_langid);
 		}
 	}
 
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/core/usb.c	Fri Mar 26 12:25:30 2004
@@ -58,6 +58,8 @@
 extern void usb_host_cleanup(void);
 
 
+const char *usbcore_name = "usbcore";
+
 int nousb;		/* Disable USB when built into kernel image */
 			/* Not honored on modular build */
 
@@ -158,11 +160,12 @@
 	retval = driver_register(&new_driver->driver);
 
 	if (!retval) {
-		info("registered new driver %s", new_driver->name);
+		pr_info("%s: registered new driver %s\n",
+			usbcore_name, new_driver->name);
 		usbfs_update_special();
 	} else {
-		err("problem %d when registering driver %s",
-			retval, new_driver->name);
+		printk(KERN_ERR "%s: error %d registering driver %s\n",
+			usbcore_name, retval, new_driver->name);
 	}
 
 	return retval;
@@ -181,7 +184,7 @@
  */
 void usb_deregister(struct usb_driver *driver)
 {
-	info("deregistering driver %s", driver->name);
+	pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
 
 	driver_unregister (&driver->driver);
 
@@ -587,11 +590,12 @@
 	int i = 0;
 	int length = 0;
 
-	dbg ("%s", __FUNCTION__);
-
 	if (!dev)
 		return -ENODEV;
 
+	/* driver is often null here; dev_dbg() would oops */
+	pr_debug ("usb %s: hotplug\n", dev->bus_id);
+
 	/* Must check driver_data here, as on remove driver is always NULL */
 	if ((dev->driver == &usb_generic_driver) || 
 	    (dev->driver_data == &usb_generic_driver_data))
@@ -601,11 +605,11 @@
 	usb_dev = interface_to_usbdev (intf);
 	
 	if (usb_dev->devnum < 0) {
-		dbg ("device already deleted ??");
+		pr_debug ("usb %s: already deleted?\n", dev->bus_id);
 		return -ENODEV;
 	}
 	if (!usb_dev->bus) {
-		dbg ("bus already removed?");
+		pr_debug ("usb %s: bus removed?\n", dev->bus_id);
 		return -ENODEV;
 	}
 
@@ -827,14 +831,14 @@
 	struct usb_device *ret_dev = NULL;
 	int child;
 
-	dbg("looking at vendor %d, product %d",
+	dev_dbg(&dev->dev, "check for vendor %04x, product %04x ...\n",
 	    dev->descriptor.idVendor,
 	    dev->descriptor.idProduct);
 
 	/* see if this device matches */
 	if ((dev->descriptor.idVendor == vendor_id) &&
 	    (dev->descriptor.idProduct == product_id)) {
-		dbg ("found the device!");
+		dev_dbg (&dev->dev, "matched this device!\n");
 		ret_dev = usb_get_dev(dev);
 		goto exit;
 	}
@@ -909,7 +913,8 @@
  * extra field of the interface and endpoint descriptor structs.
  */
 
-int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
+int __usb_get_extra_descriptor(char *buffer, unsigned size,
+	unsigned char type, void **ptr)
 {
 	struct usb_descriptor_header *header;
 
@@ -917,7 +922,11 @@
 		header = (struct usb_descriptor_header *)buffer;
 
 		if (header->bLength < 2) {
-			err("invalid descriptor length of %d", header->bLength);
+			printk(KERN_ERR
+				"%s: bogus descriptor, type %d length %d\n",
+				usbcore_name,
+				header->bDescriptorType, 
+				header->bLength);
 			return -1;
 		}
 
@@ -1568,7 +1577,7 @@
 static int __init usb_init(void)
 {
 	if (nousb) {
-		info("USB support disabled\n");
+		pr_info ("%s: USB support disabled\n", usbcore_name);
 		return 0;
 	}
 
diff -Nru a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
--- a/drivers/usb/core/usb.h	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/core/usb.h	Fri Mar 26 12:25:30 2004
@@ -17,3 +17,6 @@
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
+
+/* for labeling diagnostics */
+extern const char *usbcore_name;
diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
--- a/drivers/usb/gadget/Makefile	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/gadget/Makefile	Fri Mar 26 12:25:30 2004
@@ -8,7 +8,7 @@
 #
 # USB gadget drivers
 #
-g_zero-objs			:= zero.o usbstring.o config.o
+g_zero-objs			:= zero.o usbstring.o config.o epautoconf.o
 g_ether-objs			:= ether.o usbstring.o config.o
 g_serial-objs			:= serial.o usbstring.o
 gadgetfs-objs			:= inode.o usbstring.o
diff -Nru a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/epautoconf.c	Fri Mar 26 12:25:30 2004
@@ -0,0 +1,301 @@
+/*
+ * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
+ *
+ * Copyright (C) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include "gadget_chips.h"
+
+
+/* we must assign addresses for configurable endpoints (like net2280) */
+static __initdata unsigned epnum;
+
+// #define MANY_ENDPOINTS
+#ifdef MANY_ENDPOINTS
+/* more than 15 configurable endpoints */
+static __initdata unsigned in_epnum;
+#endif
+
+
+/*
+ * This should work with endpoints from controller drivers sharing the
+ * same endpoint naming convention.  By example:
+ *
+ *	- ep1, ep2, ... address is fixed, not direction or type
+ *	- ep1in, ep2out, ... address and direction are fixed, not type
+ *	- ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
+ *	- ep1in-bulk, ep2out-iso, ... all three are fixed
+ *	- ep-* ... no functionality restrictions
+ *
+ * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
+ * Less common restrictions are implied by gadget_is_*().
+ */
+static int __init
+ep_matches (
+	struct usb_gadget		*gadget,
+	struct usb_ep			*ep,
+	struct usb_endpoint_descriptor	*desc
+)
+{
+	u8		type;
+	const char	*tmp;
+	u16		max;
+
+	/* endpoint already claimed? */
+	if (0 != ep->driver_data)
+		return 0;
+		
+	/* only support ep0 for portable CONTROL traffic */
+	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	if (USB_ENDPOINT_XFER_CONTROL == type)
+		return 0;
+
+	/* some other naming convention */
+	if ('e' != ep->name[0])
+		return 0;
+
+	/* type-restriction:  "-iso", "-bulk", or "-int".
+	 * direction-restriction:  "in", "out".
+	 */
+	if ('-' != ep->name[2]) {
+		tmp = strrchr (ep->name, '-');
+		if (tmp) {
+			switch (type) {
+			case USB_ENDPOINT_XFER_INT:
+				/* bulk endpoints handle interrupt transfers,
+				 * except the toggle-quirky iso-synch kind
+				 */
+				if ('s' != tmp[2])	// == "-iso"
+					return 0;
+				/* for now, avoid PXA "interrupt-in";
+				 * it's documented as never using DATA1.
+				 */
+				if (gadget_is_pxa (gadget))
+					return 0;
+				break;
+			case USB_ENDPOINT_XFER_BULK:
+				if ('b' != tmp[1])	// != "-bulk"
+					return 0;
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				if ('s' != tmp[2])	// != "-iso"
+					return 0;
+			}
+		} else {
+			tmp = ep->name + strlen (ep->name);
+		}
+
+		/* direction-restriction:  "..in-..", "out-.." */
+		tmp--;
+		if (!isdigit (*tmp)) {
+			if (desc->bEndpointAddress & USB_DIR_IN) {
+				if ('n' != *tmp)
+					return 0;
+			} else {
+				if ('t' != *tmp)
+					return 0;
+			}
+		}
+	}
+
+	/* endpoint maxpacket size is an input parameter, except for bulk
+	 * where it's an output parameter representing the full speed limit.
+	 * the usb spec fixes high speed bulk maxpacket at 512 bytes.
+	 */
+	max = 0x7ff & le16_to_cpup (&desc->wMaxPacketSize);
+	switch (type) {
+	case USB_ENDPOINT_XFER_INT:
+		/* INT:  limit 64 bytes full speed, 1024 high speed */
+		if (!gadget->is_dualspeed && max > 64)
+			return 0;
+		/* FALLTHROUGH */
+
+	case USB_ENDPOINT_XFER_ISOC:
+		/* ISO:  limit 1023 bytes full speed, 1024 high speed */
+		if (ep->maxpacket < max)
+			return 0;
+		if (!gadget->is_dualspeed && max > 1023)
+			return 0;
+
+		/* BOTH:  "high bandwidth" works only at high speed */
+		if ((desc->wMaxPacketSize & __constant_cpu_to_le16(3<<11))) {
+			if (!gadget->is_dualspeed)
+				return 0;
+			/* configure your hardware with enough buffering!! */
+		}
+		break;
+	}
+
+	/* MATCH!! */
+
+	/* report address */
+	if (isdigit (ep->name [2])) {
+		u8	num = simple_strtol (&ep->name [2], NULL, 10);
+		desc->bEndpointAddress |= num;
+#ifdef	MANY_ENDPOINTS
+	} else if (desc->bEndpointAddress & USB_DIR_IN) {
+		if (++in_epnum > 15)
+			return 0;
+		desc->bEndpointAddress = USB_DIR_IN | in_epnum;
+#endif
+	} else {
+		if (++epnum > 15)
+			return 0;
+		desc->bEndpointAddress |= epnum;
+	}
+
+	/* report (variable) full speed bulk maxpacket */
+	if (USB_ENDPOINT_XFER_BULK == type)
+		desc->wMaxPacketSize = cpu_to_le16 (
+				min ((unsigned)64, ep->maxpacket));
+	return 1;
+}
+
+static struct usb_ep * __init
+find_ep (struct usb_gadget *gadget, const char *name)
+{
+	struct usb_ep	*ep;
+
+	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+		if (0 == strcmp (ep->name, name))
+			return ep;
+	}
+	return 0;
+}
+
+/**
+ * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *	initialized.  For periodic transfers, the maximum packet
+ *	size must also be initialized.  This is modified on success.
+ *
+ * By choosing an endpoint to use with the specified descriptor, this
+ * routine simplifies writing gadget drivers that work with multiple
+ * USB device controllers.  The endpoint would be passed later to
+ * usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration on your
+ * hardware.  This code may not make the best choices about how to use the
+ * USB controller, and it can't know all the restrictions that may apply.
+ * Some combinations of driver and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed.  To prevent
+ * the endpoint from being returned by a later autoconfig call, claim it
+ * by assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep * __init usb_ep_autoconfig (
+	struct usb_gadget		*gadget,
+	struct usb_endpoint_descriptor	*desc
+)
+{
+	struct usb_ep	*ep;
+	u8		type;
+
+	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+	/* First, apply chip-specific "best usage" knowledge.
+	 * This might make a good usb_gadget_ops hook ...
+	 */
+	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
+		/* ep-e, ep-f are PIO with only 64 byte fifos */
+		ep = find_ep (gadget, "ep-e");
+		if (ep && ep_matches (gadget, ep, desc))
+			return ep;
+		ep = find_ep (gadget, "ep-f");
+		if (ep && ep_matches (gadget, ep, desc))
+			return ep;
+
+	} else if (gadget_is_goku (gadget)) {
+		if (USB_ENDPOINT_XFER_INT == type) {
+			/* single buffering is enough */
+			ep = find_ep (gadget, "ep3-bulk");
+			if (ep && ep_matches (gadget, ep, desc))
+				return ep;
+		} else if (USB_ENDPOINT_XFER_BULK == type
+				&& (USB_DIR_IN & desc->bEndpointAddress)) {
+			/* DMA may be available */
+			ep = find_ep (gadget, "ep2-bulk");
+			if (ep && ep_matches (gadget, ep, desc))
+				return ep;
+		}
+
+	} else if (gadget_is_sh (gadget) && USB_ENDPOINT_XFER_INT == type) {
+		/* single buffering is enough; maybe 8 byte fifo is too */
+		ep = find_ep (gadget, "ep3in-bulk");
+		if (ep && ep_matches (gadget, ep, desc))
+			return ep;
+
+	} else if (gadget_is_mq11xx (gadget) && USB_ENDPOINT_XFER_INT == type) {
+		ep = find_ep (gadget, "ep1-bulk");
+		if (ep && ep_matches (gadget, ep, desc))
+			return ep;
+	}
+
+	/* Second, look at endpoints until an unclaimed one looks usable */ 
+	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+		if (ep_matches (gadget, ep, desc))
+			return ep;
+	}
+
+	/* Fail */
+	return 0;
+}
+
+/**
+ * usb_ep_autoconfig_reset - reset endpoint autoconfig state
+ * @gadget: device for which autoconfig state will be reset
+ *
+ * Use this for devices where one configuration may need to assign
+ * endpoint resources very differently from the next one.  It clears
+ * state such as ep->driver_data and the record of assigned endpoints
+ * used by usb_ep_autoconfig().
+ */
+void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget)
+{
+	struct usb_ep	*ep;
+
+	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+		ep->driver_data = 0;
+	}
+#ifdef	MANY_ENDPOINTS
+	in_epnum = 0;
+#endif
+	epnum = 0;
+}
+
diff -Nru a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
--- a/drivers/usb/gadget/usbstring.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/gadget/usbstring.c	Fri Mar 26 12:25:30 2004
@@ -12,6 +12,7 @@
 #include <linux/list.h>
 #include <linux/string.h>
 #include <linux/device.h>
+#include <linux/init.h>
 
 #include <linux/usb_ch9.h>
 #include <linux/usb_gadget.h>
diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
--- a/drivers/usb/gadget/zero.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/gadget/zero.c	Fri Mar 26 12:25:30 2004
@@ -89,10 +89,12 @@
 #include <linux/usb_ch9.h>
 #include <linux/usb_gadget.h>
 
+#include "gadget_chips.h"
+
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_VERSION		"Bastille Day 2003"
+#define DRIVER_VERSION		"St Patrick's Day 2004"
 
 static const char shortname [] = "zero";
 static const char longname [] = "Gadget Zero";
@@ -105,100 +107,12 @@
 /*
  * driver assumes self-powered hardware, and
  * has no way for users to trigger remote wakeup.
- */
-
-/*
- * hardware-specific configuration, controlled by which device
- * controller driver was configured.
- *
- * CHIP ... hardware identifier
- * DRIVER_VERSION_NUM ... alerts the host side driver to differences
- * EP_*_NAME ... which endpoints do we use for which purpose?
- * EP_*_NUM ... numbers for them (often limited by hardware)
- *
- * add other defines for other portability issues, like hardware that
- * for some reason doesn't handle full speed bulk maxpacket of 64.
- */
-
-/*
- * DRIVER_VERSION_NUM 0x0000 (?):  Martin Diehl's ezusb an21/fx code
- */
-
-/*
- * NetChip 2280, PCI based.
- *
- * This has half a dozen configurable endpoints, four with dedicated
- * DMA channels to manage their FIFOs.  It supports high speed.
- * Those endpoints can be arranged in any desired configuration.
- */
-#if defined(CONFIG_USB_GADGET_NET2280) || defined(CONFIG_USB_GADGET_DUMMY_HCD)
-#define CHIP			"net2280"
-#define DRIVER_VERSION_NUM	0x0101
-static const char EP_OUT_NAME [] = "ep-a";
-#define EP_OUT_NUM	2
-static const char EP_IN_NAME [] = "ep-b";
-#define EP_IN_NUM	2
-#endif
-
-/*
- * PXA-2xx UDC:  widely used in second gen Linux-capable PDAs.
  *
- * This has fifteen fixed-function full speed endpoints, and it
- * can support all USB transfer types.
- *
- * These supports three or four configurations, with fixed numbers.
- * The hardware interprets SET_INTERFACE, net effect is that you
- * can't use altsettings or reset the interfaces independently.
- * So stick to a single interface.
+ * this version autoconfigures as much as possible,
+ * which is reasonable for most "bulk-only" drivers.
  */
-#ifdef	CONFIG_USB_GADGET_PXA2XX
-#define CHIP			"pxa2xx"
-#define DRIVER_VERSION_NUM	0x0103
-static const char EP_OUT_NAME [] = "ep12out-bulk";
-#define EP_OUT_NUM	12
-static const char EP_IN_NAME [] = "ep11in-bulk";
-#define EP_IN_NUM	11
-#endif
-
-/*
- * SA-1100 UDC:  widely used in first gen Linux-capable PDAs.
- *
- * This has only two fixed function endpoints, which can only
- * be used for bulk (or interrupt) transfers.  (Plus control.)
- *
- * Since it can't flush its TX fifos without disabling the UDC,
- * the current configuration or altsettings can't change except
- * in special situations.  So this is a case of "choose it right
- * during enumeration" ...
- */
-#ifdef	CONFIG_USB_GADGET_SA1100
-#define CHIP			"sa1100"
-#define DRIVER_VERSION_NUM	0x0105
-static const char EP_OUT_NAME [] = "ep1out-bulk";
-#define EP_OUT_NUM	1
-static const char EP_IN_NAME [] = "ep2in-bulk";
-#define EP_IN_NUM	2
-#endif
-
-/*
- * Toshiba TC86C001 ("Goku-S") UDC
- *
- * This has three semi-configurable full speed bulk/interrupt endpoints.
- */
-#ifdef	CONFIG_USB_GADGET_GOKU
-#define CHIP			"goku"
-#define DRIVER_VERSION_NUM	0x0106
-static const char EP_OUT_NAME [] = "ep1-bulk";
-#define EP_OUT_NUM	1
-static const char EP_IN_NAME [] = "ep2-bulk";
-#define EP_IN_NUM	2
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-#ifndef EP_OUT_NUM
-#	error Configure some USB peripheral controller driver!
-#endif
+static const char *EP_IN_NAME;		/* source */
+static const char *EP_OUT_NAME;		/* sink */
 
 /*-------------------------------------------------------------------------*/
 
@@ -222,20 +136,19 @@
 	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
 
 #ifdef DEBUG
-#undef DEBUG
-#define DEBUG(dev,fmt,args...) \
+#define DBG(dev,fmt,args...) \
 	xprintk(dev , KERN_DEBUG , fmt , ## args)
 #else
-#define DEBUG(dev,fmt,args...) \
+#define DBG(dev,fmt,args...) \
 	do { } while (0)
 #endif /* DEBUG */
 
 #ifdef VERBOSE
-#define VDEBUG	DEBUG
+#define VDBG	DBG
 #else
-#define VDEBUG(dev,fmt,args...) \
+#define VDBG(dev,fmt,args...) \
 	do { } while (0)
-#endif /* DEBUG */
+#endif /* VERBOSE */
 
 #define ERROR(dev,fmt,args...) \
 	xprintk(dev , KERN_ERR , fmt , ## args)
@@ -305,7 +218,6 @@
 
 	.idVendor =		__constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
 	.idProduct =		__constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
-	.bcdDevice =		__constant_cpu_to_le16 (DRIVER_VERSION_NUM),
 	.iManufacturer =	STRING_MANUFACTURER,
 	.iProduct =		STRING_PRODUCT,
 	.iSerialNumber =	STRING_SERIAL,
@@ -362,24 +274,22 @@
 
 /* two full speed bulk endpoints; their use is config-dependent */
 
-static const struct usb_endpoint_descriptor
+static struct usb_endpoint_descriptor
 fs_source_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
-	.bEndpointAddress =	EP_IN_NUM | USB_DIR_IN,
+	.bEndpointAddress =	USB_DIR_IN,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
 };
 
-static const struct usb_endpoint_descriptor
+static struct usb_endpoint_descriptor
 fs_sink_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
-	.bEndpointAddress =	EP_OUT_NUM,
+	.bEndpointAddress =	USB_DIR_OUT,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
 };
 
 static const struct usb_descriptor_header *fs_source_sink_function [] = {
@@ -643,7 +553,7 @@
 	case -ECONNABORTED: 		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
-		VDEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+		VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
 				req->actual, req->length);
 		if (ep == dev->out_ep)
 			check_read_data (dev, ep, req);
@@ -656,7 +566,7 @@
 					 */
 	default:
 #if 1
-		DEBUG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+		DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
 				status, req->actual, req->length);
 #endif
 	case -EREMOTEIO:		/* short read */
@@ -747,7 +657,7 @@
 		break;
 	}
 	if (result == 0)
-		DEBUG (dev, "buflen %d\n", buflen);
+		DBG (dev, "buflen %d\n", buflen);
 
 	/* caller is responsible for cleanup on error */
 	return result;
@@ -858,14 +768,14 @@
 				req->complete = loopback_complete;
 				result = usb_ep_queue (ep, req, GFP_ATOMIC);
 				if (result)
-					DEBUG (dev, "%s queue req --> %d\n",
+					DBG (dev, "%s queue req --> %d\n",
 							ep->name, result);
 			} else
 				result = -ENOMEM;
 		}
 	}
 	if (result == 0)
-		DEBUG (dev, "qlen %d, buflen %d\n", qlen, buflen);
+		DBG (dev, "qlen %d, buflen %d\n", qlen, buflen);
 
 	/* caller is responsible for cleanup on error */
 	return result;
@@ -878,7 +788,7 @@
 	if (dev->config == 0)
 		return;
 
-	DEBUG (dev, "reset config\n");
+	DBG (dev, "reset config\n");
 
 	/* just disable endpoints, forcing completion of pending i/o.
 	 * all our completion handlers free their requests in this case.
@@ -913,13 +823,11 @@
 	if (number == dev->config)
 		return 0;
 
-#ifdef CONFIG_USB_GADGET_SA1100
-	if (dev->config) {
+	if (gadget_is_sa1100 (gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
 		INFO (dev, "can't change configurations\n");
 		return -ESPIPE;
 	}
-#endif
 	zero_reset_config (dev);
 
 	switch (number) {
@@ -963,7 +871,7 @@
 static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
 {
 	if (req->status || req->actual != req->length)
-		DEBUG ((struct zero_dev *) ep->driver_data,
+		DBG ((struct zero_dev *) ep->driver_data,
 				"setup complete --> %d, %d/%d\n",
 				req->status, req->actual, req->length);
 }
@@ -1111,7 +1019,7 @@
 
 	default:
 unknown:
-		VDEBUG (dev,
+		VDBG (dev,
 			"unknown control req%02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
@@ -1122,7 +1030,7 @@
 		req->length = value;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
-			DEBUG (dev, "ep_queue --> %d\n", value);
+			DBG (dev, "ep_queue --> %d\n", value);
 			req->status = 0;
 			zero_setup_complete (gadget->ep0, req);
 		}
@@ -1159,7 +1067,7 @@
 {
 	struct zero_dev		*dev = get_gadget_data (gadget);
 
-	DEBUG (dev, "unbind\n");
+	DBG (dev, "unbind\n");
 
 	/* we've already been disconnected ... no i/o is active */
 	if (dev->req)
@@ -1172,7 +1080,70 @@
 zero_bind (struct usb_gadget *gadget)
 {
 	struct zero_dev		*dev;
+	struct usb_ep		*ep;
 
+	/* Bulk-only drivers like this one SHOULD be able to
+	 * autoconfigure on any sane usb controller driver,
+	 * but there may also be important quirks to address.
+	 */
+	usb_ep_autoconfig_reset (gadget);
+	ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+	if (!ep) {
+autoconf_fail:
+		printk (KERN_ERR "%s: can't autoconfigure on %s\n",
+			shortname, gadget->name);
+		return -ENODEV;
+	}
+	EP_IN_NAME = ep->name;
+	ep->driver_data = ep;	/* claim */
+	
+	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+	if (!ep)
+		goto autoconf_fail;
+	EP_OUT_NAME = ep->name;
+	ep->driver_data = ep;	/* claim */
+
+
+	/*
+	 * DRIVER POLICY CHOICE:  you may want to do this differently.
+	 * One thing to avoid is reusing a bcdDevice revision code
+	 * with different host-visible configurations or behavior
+	 * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
+	 */
+	if (gadget_is_net2280 (gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
+	} else if (gadget_is_pxa (gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203);
+#if 0
+	} else if (gadget_is_sh(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);
+		/* SH has only one configuration; see "loopdefault" */
+		device_desc.bNumConfigurations = 1;
+		/* FIXME make 1 == default.bConfigurationValue */
+#endif
+	} else if (gadget_is_sa1100 (gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);
+	} else if (gadget_is_goku (gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206);
+	} else if (gadget_is_mq11xx (gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
+	} else if (gadget_is_omap (gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
+	} else {
+		/* gadget zero is so simple (for now, no altsettings) that
+		 * it SHOULD NOT have problems with bulk-capable hardware.
+		 * so warn about unrcognized controllers, don't panic.
+		 *
+		 * things like configuration and altsetting numbering
+		 * can need hardware-specific attention though.
+		 */
+		printk (KERN_WARNING "%s: controller '%s' not recognized\n",
+			shortname, gadget->name);
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
+	}
+
+
+	/* ok, we made sense of the hardware ... */
 	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
 	if (!dev)
 		return -ENOMEM;
@@ -1202,6 +1173,8 @@
 	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
 	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 #endif
+
+	usb_gadget_set_selfpowered (gadget);
 
 	gadget->ep0->driver_data = dev;
 
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/host/ehci-hcd.c	Fri Mar 26 12:25:30 2004
@@ -374,6 +374,10 @@
 	u32			hcc_params;
 	u8                      tempbyte;
 
+	init_timer (&ehci->watchdog);
+	ehci->watchdog.function = ehci_watchdog;
+	ehci->watchdog.data = (unsigned long) ehci;
+
 	/*
 	 * hw default: 1K periodic list heads, one per frame.
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -467,10 +471,6 @@
 	dbg_cmd (ehci, "init", temp);
 
 	/* set async sleep time = 10 us ... ? */
-
-	init_timer (&ehci->watchdog);
-	ehci->watchdog.function = ehci_watchdog;
-	ehci->watchdog.data = (unsigned long) ehci;
 
 	/* wire up the root hub */
 	bus = hcd_to_bus (hcd);
diff -Nru a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
--- a/drivers/usb/host/uhci-debug.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/host/uhci-debug.c	Fri Mar 26 12:25:30 2004
@@ -27,7 +27,7 @@
 		p = strchr(buf, '\n');
 		if (p)
 			*p = 0;
-		printk("%s\n", buf);
+		printk(KERN_DEBUG "%s\n", buf);
 		buf = p;
 		if (buf)
 			buf++;
@@ -328,21 +328,17 @@
 	//out += sprintf(out, "Inserttime=%lx ",urbp->inserttime);
 	//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
 
-	spin_lock(&urbp->urb->lock);
 	count = 0;
 	list_for_each(tmp, &urbp->td_list)
 		count++;
-	spin_unlock(&urbp->urb->lock);
 	out += sprintf(out, "TDs=%d ",count);
 
 	if (urbp->queued)
 		out += sprintf(out, "queued\n");
 	else {
-		spin_lock(&uhci->frame_list_lock);
 		count = 0;
 		list_for_each(tmp, &urbp->queue_list)
 			count++;
-		spin_unlock(&uhci->frame_list_lock);
 		out += sprintf(out, "queued URBs=%d\n", count);
 	}
 
@@ -352,12 +348,10 @@
 static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
 {
 	char *out = buf;
-	unsigned long flags;
 	struct list_head *head, *tmp;
 	int count;
 
 	out += sprintf(out, "Main list URBs:");
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
 	if (list_empty(&uhci->urb_list))
 		out += sprintf(out, " Empty\n");
 	else {
@@ -373,10 +367,8 @@
 			tmp = tmp->next;
 		}
 	}
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
 	out += sprintf(out, "Remove list URBs:");
-	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
 	if (list_empty(&uhci->urb_remove_list))
 		out += sprintf(out, " Empty\n");
 	else {
@@ -392,10 +384,8 @@
 			tmp = tmp->next;
 		}
 	}
-	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
 
 	out += sprintf(out, "Complete list URBs:");
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
 	if (list_empty(&uhci->complete_list))
 		out += sprintf(out, " Empty\n");
 	else {
@@ -411,7 +401,6 @@
 			tmp = tmp->next;
 		}
 	}
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
 
 	return out - buf;
 }
@@ -425,7 +414,7 @@
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
 
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	spin_lock_irqsave(&uhci->schedule_lock, flags);
 
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
@@ -508,11 +497,11 @@
 		}
 	}
 
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-
 	if (debug > 2)
 		out += uhci_show_lists(uhci, out, len - (out - buf));
 
+	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
+
 	return out - buf;
 }
 
@@ -623,4 +612,3 @@
 	.release =	uhci_proc_release,
 };
 #endif
-
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/host/uhci-hcd.c	Fri Mar 26 12:25:30 2004
@@ -117,26 +117,18 @@
  */
 static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 	uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); 
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
 {
-	spin_lock(&uhci->frame_list_lock);
 	uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
-	spin_unlock(&uhci->frame_list_lock);
 }
 
 static inline void uhci_moveto_complete(struct uhci_hcd *uhci, 
 					struct urb_priv *urbp)
 {
-	spin_lock(&uhci->complete_list_lock);
 	list_move_tail(&urbp->urb_list, &uhci->complete_list);
-	spin_unlock(&uhci->complete_list_lock);
 }
 
 static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
@@ -178,12 +170,8 @@
  */
 static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
 {
-	unsigned long flags;
-
 	framenum %= UHCI_NUMFRAMES;
 
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
 	td->frame = framenum;
 
 	/* Is there a TD already mapped there? */
@@ -204,18 +192,13 @@
 		uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
 		uhci->fl->frame_cpu[framenum] = td;
 	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
 {
-	unsigned long flags;
-
 	/* If it's not inserted, don't remove it */
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 	if (td->frame == -1 && list_empty(&td->fl_list))
-		goto out;
+		return;
 
 	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
 		if (list_empty(&td->fl_list)) {
@@ -240,9 +223,6 @@
 
 	list_del_init(&td->fl_list);
 	td->frame = -1;
-
-out:
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 /*
@@ -339,12 +319,11 @@
 
 /*
  * Append this urb's qh after the last qh in skelqh->list
- * MUST be called with uhci->frame_list_lock acquired
  *
  * Note that urb_priv.queue_list doesn't have a separate queue head;
  * it's a ring with every element "live".
  */
-static void _uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
+static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct list_head *tmp;
@@ -396,36 +375,20 @@
 	list_add_tail(&urbp->qh->list, &skelqh->list);
 }
 
-static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	_uhci_insert_qh(uhci, skelqh, urb);
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
 /*
  * Start removal of QH from schedule; it finishes next frame.
  * TDs should be unlinked before this is called.
  */
 static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-	unsigned long flags;
 	struct uhci_qh *pqh;
 
 	if (!qh)
 		return;
 
-	qh->urbp = NULL;
-
 	/*
 	 * Only go through the hoops if it's actually linked in
-	 * Queued QHs are removed in uhci_delete_queued_urb,
-	 * since (for queued URBs) the pqh is pointed to the next
-	 * QH in the queue, not the next endpoint's QH.
 	 */
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 	if (!list_empty(&qh->list)) {
 		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
 
@@ -450,11 +413,19 @@
 		/* continue the rest of the schedule */
 		qh->element = UHCI_PTR_TERM;
 
+		/* If our queue is nonempty, make the next URB the head */
+		if (!list_empty(&qh->urbp->queue_list)) {
+			struct urb_priv *nurbp;
+
+			nurbp = list_entry(qh->urbp->queue_list.next,
+					struct urb_priv, queue_list);
+			nurbp->queued = 0;
+			list_add_tail(&nurbp->qh->list, &qh->list);
+		}
 		list_del_init(&qh->list);
 	}
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 
-	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
+	qh->urbp = NULL;
 
 	/* Check to see if the remove list is empty. Set the IOC bit */
 	/* to force an interrupt so we can remove the QH */
@@ -462,8 +433,6 @@
 		uhci_set_next_interrupt(uhci);
 
 	list_add(&qh->remove_list, &uhci->qh_remove_list);
-
-	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
 }
 
 static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
@@ -497,13 +466,10 @@
 	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
 	struct list_head *tmp;
 	struct uhci_td *lltd;
-	unsigned long flags;
 
 	eurbp = eurb->hcpriv;
 	urbp = urb->hcpriv;
 
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
 	/* Find the first URB in the queue */
 	if (eurbp->queued) {
 		struct list_head *head = &eurbp->queue_list;
@@ -543,8 +509,6 @@
 	list_add_tail(&urbp->queue_list, &furbp->queue_list);
 
 	urbp->queued = 1;
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
@@ -554,14 +518,11 @@
 	struct urb_priv *purbp;
 	struct uhci_td *pltd;
 	unsigned int toggle;
-	unsigned long flags;
 
 	urbp = urb->hcpriv;
 
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
 	if (list_empty(&urbp->queue_list))
-		goto out;
+		return;
 
 	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
 
@@ -603,39 +564,9 @@
 				usb_pipeout(urb->pipe), toggle);
 	}
 
-	if (!urbp->queued) {
-		struct uhci_qh *pqh;
-
-		nurbp->queued = 0;
-
-		/*
-		 * Fixup the previous QH's queue to link to the new head
-		 * of this queue.
-		 */
-		pqh = list_entry(urbp->qh->list.prev, struct uhci_qh, list);
-
-		if (pqh->urbp) {
-			struct list_head *head, *tmp;
-
-			head = &pqh->urbp->queue_list;
-			tmp = head->next;
-			while (head != tmp) {
-				struct urb_priv *turbp =
-					list_entry(tmp, struct urb_priv, queue_list);
-
-				tmp = tmp->next;
-
-				turbp->qh->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
-			}
-		}
-
-		pqh->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
-
-		list_add_tail(&nurbp->qh->list, &urbp->qh->list);
-		list_del_init(&urbp->qh->list);
-	} else {
-		/* We're somewhere in the middle (or end). A bit trickier */
-		/*  than the head scenario */
+	if (urbp->queued) {
+		/* We're somewhere in the middle (or end).  The case where
+		 * we're at the head is handled in uhci_remove_qh(). */
 		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
 				queue_list);
 
@@ -649,9 +580,6 @@
 	}
 
 	list_del_init(&urbp->queue_list);
-
-out:
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
@@ -679,9 +607,6 @@
 	return urbp;
 }
 
-/*
- * MUST be called with urb->lock acquired
- */
 static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
@@ -691,9 +616,6 @@
 	list_add_tail(&td->list, &urbp->td_list);
 }
 
-/*
- * MUST be called with urb->lock acquired
- */
 static void uhci_remove_td_from_urb(struct uhci_td *td)
 {
 	if (list_empty(&td->list))
@@ -704,14 +626,10 @@
 	td->urb = NULL;
 }
 
-/*
- * MUST be called with urb->lock acquired
- */
 static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
 {
 	struct list_head *head, *tmp;
 	struct urb_priv *urbp;
-	unsigned long flags;
 
 	urbp = (struct urb_priv *)urb->hcpriv;
 	if (!urbp)
@@ -721,8 +639,6 @@
 		dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
 				"or uhci->remove_list!\n", urb);
 
-	spin_lock_irqsave(&uhci->td_remove_list_lock, flags);
-
 	/* Check to see if the remove list is empty. Set the IOC bit */
 	/* to force an interrupt so we can remove the TD's*/
 	if (list_empty(&uhci->td_remove_list))
@@ -740,42 +656,30 @@
 		list_add(&td->remove_list, &uhci->td_remove_list);
 	}
 
-	spin_unlock_irqrestore(&uhci->td_remove_list_lock, flags);
-
 	urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 }
 
 static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
 {
-	unsigned long flags;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
 	if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
 		urbp->fsbr = 1;
 		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
 			uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH;
 	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
 {
-	unsigned long flags;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
 	if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
 		urbp->fsbr = 0;
 		if (!--uhci->fsbr)
 			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
 	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
 /*
@@ -840,13 +744,16 @@
 		urb->setup_dma);
 
 	/*
-	 * If direction is "send", change the frame from SETUP (0x2D)
-	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
+	 * If direction is "send", change the packet ID from SETUP (0x2D)
+	 * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and
+	 * set Short Packet Detect (SPD) for all data packets.
 	 */
-	destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
-
-	if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+	if (usb_pipeout(urb->pipe))
+		destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
+	else {
+		destination ^= (USB_PID_SETUP ^ USB_PID_IN);
 		status |= TD_CTRL_SPD;
+	}
 
 	/*
 	 * Build the DATA TD's
@@ -923,50 +830,23 @@
 }
 
 /*
- * If control was short, then end status packet wasn't sent, so this
- * reorganize s so it's sent to finish the transfer.  The original QH is
- * removed from the skel and discarded; all TDs except the last (status)
- * are deleted; the last (status) TD is put on a new QH which is reinserted
- * into the skel.  Since the last TD and urb_priv are reused, the TD->link
- * and urb_priv maintain any queued QHs.
+ * If control-IN transfer was short, the status packet wasn't sent.
+ * This routine changes the element pointer in the QH to point at the
+ * status TD.  It's safe to do this even while the QH is live, because
+ * the hardware only updates the element pointer following a successful
+ * transfer.  The inactive TD for the short packet won't cause an update,
+ * so the pointer won't get overwritten.  The next time the controller
+ * sees this QH, it will send the status packet.
  */
 static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
 {
-	struct list_head *tmp, *head;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
 
 	urbp->short_control_packet = 1;
 
-	/* Create a new QH to avoid pointer overwriting problems */
-	uhci_remove_qh(uhci, urbp->qh);
-
-	/* Delete all of the TD's except for the status TD at the end */
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head && tmp->next != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
-		uhci_free_td(uhci, td);
-	}
-
-	urbp->qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!urbp->qh)
-		return -ENOMEM;
-
-	urbp->qh->urbp = urbp;
-
-	/* One TD, who cares about Breadth first? */
-	uhci_insert_tds_in_qh(urbp->qh, urb, UHCI_PTR_DEPTH);
-
-	/* Low-speed transfers get a different queue */
-	if (urb->dev->speed == USB_SPEED_LOW)
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
-	else
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
+	td = list_entry(urbp->td_list.prev, struct uhci_td, list);
+	urbp->qh->element = td->dma_handle;
 
 	return -EINPROGRESS;
 }
@@ -1101,17 +981,20 @@
 	status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
 	if (urb->dev->speed == USB_SPEED_LOW)
 		status |= TD_CTRL_LS;
-	if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+	if (usb_pipein(urb->pipe))
 		status |= TD_CTRL_SPD;
 
 	/*
 	 * Build the DATA TD's
 	 */
 	do {	/* Allow zero length packets */
-		int pktsze = len;
+		int pktsze = maxsze;
 
-		if (pktsze > maxsze)
-			pktsze = maxsze;
+		if (pktsze >= len) {
+			pktsze = len;
+			if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+				status &= ~TD_CTRL_SPD;
+		}
 
 		td = uhci_alloc_td(uhci, urb->dev);
 		if (!td)
@@ -1154,7 +1037,8 @@
 	}
 
 	/* Set the flag on the last packet */
-	td->status |= cpu_to_le32(TD_CTRL_IOC);
+	if (!(urb->transfer_flags & URB_NO_INTERRUPT))
+		td->status |= cpu_to_le32(TD_CTRL_IOC);
 
 	qh = uhci_alloc_qh(uhci, urb->dev);
 	if (!qh)
@@ -1409,9 +1293,6 @@
 	return ret;
 }
 
-/*
- * MUST be called with uhci->urb_list_lock acquired
- */
 static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
 {
 	struct list_head *tmp, *head;
@@ -1449,7 +1330,7 @@
 	struct urb *eurb;
 	int bustime;
 
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	spin_lock_irqsave(&uhci->schedule_lock, flags);
 
 	if (urb->status != -EINPROGRESS)	/* URB already unlinked! */
 		goto out;
@@ -1506,14 +1387,12 @@
 		ret = 0;
 
 out:
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
 	return ret;
 }
 
 /*
  * Return the result of a transfer
- *
- * MUST be called with urb_list_lock acquired
  */
 static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
 {
@@ -1549,7 +1428,6 @@
 	case PIPE_BULK:
 	case PIPE_ISOCHRONOUS:
 		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Spinlock needed ? */
 		if (urb->bandwidth)
 			usb_release_bandwidth(urb->dev, urb, 1);
 		uhci_unlink_generic(uhci, urb);
@@ -1557,15 +1435,12 @@
 	case PIPE_INTERRUPT:
 		/* Release bandwidth for Interrupt or Isoc. transfers */
 		/* Make sure we don't release if we have a queued URB */
-		spin_lock(&uhci->frame_list_lock);
-		/* Spinlock needed ? */
 		if (list_empty(&urbp->queue_list) && urb->bandwidth)
 			usb_release_bandwidth(urb->dev, urb, 0);
 		else
 			/* bandwidth was passed on to queued URB, */
 			/* so don't let usb_unlink_urb() release it */
 			urb->bandwidth = 0;
-		spin_unlock(&uhci->frame_list_lock);
 		uhci_unlink_generic(uhci, urb);
 		break;
 	default:
@@ -1581,9 +1456,6 @@
 	spin_unlock(&urb->lock);
 }
 
-/*
- * MUST be called with urb->lock acquired
- */
 static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
 {
 	struct list_head *head, *tmp;
@@ -1639,7 +1511,7 @@
 	unsigned long flags;
 	struct urb_priv *urbp;
 
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	spin_lock_irqsave(&uhci->schedule_lock, flags);
 	urbp = urb->hcpriv;
 	if (!urbp)			/* URB was never linked! */
 		goto done;
@@ -1647,16 +1519,13 @@
 
 	uhci_unlink_generic(uhci, urb);
 
-	spin_lock(&uhci->urb_remove_list_lock);
-
 	/* If we're the first, set the next interrupt bit */
 	if (list_empty(&uhci->urb_remove_list))
 		uhci_set_next_interrupt(uhci);
 	list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
 
-	spin_unlock(&uhci->urb_remove_list_lock);
 done:
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
 	return 0;
 }
 
@@ -1718,7 +1587,7 @@
 
 	INIT_LIST_HEAD(&list);
 
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	spin_lock_irqsave(&uhci->schedule_lock, flags);
 	head = &uhci->urb_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1734,12 +1603,15 @@
 			uhci_fsbr_timeout(uhci, u);
 
 		/* Check if the URB timed out */
-		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout))
+		if (u->timeout && u->status == -EINPROGRESS &&
+			time_after_eq(jiffies, up->inserttime + u->timeout)) {
+			u->status = -ETIMEDOUT;
 			list_move_tail(&up->urb_list, &list);
+		}
 
 		spin_unlock(&u->lock);
 	}
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
 
 	head = &list;
 	tmp = head->next;
@@ -1781,7 +1653,6 @@
 {
 	struct list_head *tmp, *head;
 
-	spin_lock(&uhci->qh_remove_list_lock);
 	head = &uhci->qh_remove_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1793,14 +1664,12 @@
 
 		uhci_free_qh(uhci, qh);
 	}
-	spin_unlock(&uhci->qh_remove_list_lock);
 }
 
 static void uhci_free_pending_tds(struct uhci_hcd *uhci)
 {
 	struct list_head *tmp, *head;
 
-	spin_lock(&uhci->td_remove_list_lock);
 	head = &uhci->td_remove_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1812,18 +1681,17 @@
 
 		uhci_free_td(uhci, td);
 	}
-	spin_unlock(&uhci->td_remove_list_lock);
 }
 
 static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
-	spin_lock(&urb->lock);
 	uhci_destroy_urb_priv(uhci, urb);
-	spin_unlock(&urb->lock);
 
+	spin_unlock(&uhci->schedule_lock);
 	usb_hcd_giveback_urb(hcd, urb, regs);
+	spin_lock(&uhci->schedule_lock);
 }
 
 static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs)
@@ -1831,7 +1699,6 @@
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	struct list_head *tmp, *head;
 
-	spin_lock(&uhci->complete_list_lock);
 	head = &uhci->complete_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1839,26 +1706,18 @@
 		struct urb *urb = urbp->urb;
 
 		list_del_init(&urbp->urb_list);
-		spin_unlock(&uhci->complete_list_lock);
-
 		uhci_finish_urb(hcd, urb, regs);
 
-		spin_lock(&uhci->complete_list_lock);
 		head = &uhci->complete_list;
 		tmp = head->next;
 	}
-	spin_unlock(&uhci->complete_list_lock);
 }
 
 static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
 {
-	spin_lock(&uhci->urb_remove_list_lock);
-	spin_lock(&uhci->complete_list_lock);
 
 	/* Splice the urb_remove_list onto the end of the complete_list */
 	list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
-	spin_unlock(&uhci->complete_list_lock);
-	spin_unlock(&uhci->urb_remove_list_lock);
 }
 
 static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
@@ -1895,16 +1754,15 @@
 	if (status & USBSTS_RD)
 		uhci->resume_detect = 1;
 
-	uhci_free_pending_qhs(uhci);
+	spin_lock(&uhci->schedule_lock);
 
+	uhci_free_pending_qhs(uhci);
 	uhci_free_pending_tds(uhci);
-
 	uhci_remove_pending_urbps(uhci);
 
 	uhci_clear_next_interrupt(uhci);
 
 	/* Walk the list of pending URB's to see which ones completed */
-	spin_lock(&uhci->urb_list_lock);
 	head = &uhci->urb_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1916,9 +1774,10 @@
 		/* Checks the status and does all of the magic necessary */
 		uhci_transfer_result(uhci, urb);
 	}
-	spin_unlock(&uhci->urb_list_lock);
-
 	uhci_finish_completion(hcd, regs);
+
+	spin_unlock(&uhci->schedule_lock);
+
 	return IRQ_HANDLED;
 }
 
@@ -2208,23 +2067,17 @@
 	uhci->fsbr = 0;
 	uhci->fsbrtimeout = 0;
 
-	spin_lock_init(&uhci->qh_remove_list_lock);
+	spin_lock_init(&uhci->schedule_lock);
 	INIT_LIST_HEAD(&uhci->qh_remove_list);
 
-	spin_lock_init(&uhci->td_remove_list_lock);
 	INIT_LIST_HEAD(&uhci->td_remove_list);
 
-	spin_lock_init(&uhci->urb_remove_list_lock);
 	INIT_LIST_HEAD(&uhci->urb_remove_list);
 
-	spin_lock_init(&uhci->urb_list_lock);
 	INIT_LIST_HEAD(&uhci->urb_list);
 
-	spin_lock_init(&uhci->complete_list_lock);
 	INIT_LIST_HEAD(&uhci->complete_list);
 
-	spin_lock_init(&uhci->frame_list_lock);
-
 	uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
 			&dma_handle, 0);
 	if (!uhci->fl) {
@@ -2416,7 +2269,6 @@
 static void uhci_stop(struct usb_hcd *hcd)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	unsigned long flags;
 
 	del_timer_sync(&uhci->stall_timer);
 
@@ -2424,16 +2276,18 @@
 	 * At this point, we're guaranteed that no new connects can be made
 	 * to this bus since there are no more parents
 	 */
-	local_irq_save(flags);
+	spin_lock_irq(&uhci->schedule_lock);
 	uhci_free_pending_qhs(uhci);
 	uhci_free_pending_tds(uhci);
 	uhci_remove_pending_urbps(uhci);
+	spin_unlock_irq(&uhci->schedule_lock);
 
 	reset_hc(uhci);
 
+	spin_lock_irq(&uhci->schedule_lock);
 	uhci_free_pending_qhs(uhci);
 	uhci_free_pending_tds(uhci);
-	local_irq_restore(flags);
+	spin_unlock_irq(&uhci->schedule_lock);
 	
 	release_uhci(uhci);
 }
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/host/uhci-hcd.h	Fri Mar 26 12:25:30 2004
@@ -342,8 +342,8 @@
 	struct uhci_td *term_td;	/* Terminating TD, see UHCI bug */
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
 
-	spinlock_t frame_list_lock;
-	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
+	spinlock_t schedule_lock;
+	struct uhci_frame_list *fl;		/* P: uhci->schedule_lock */
 	int fsbr;				/* Full-speed bandwidth reclamation */
 	unsigned long fsbrtimeout;		/* FSBR delay */
 
@@ -353,24 +353,19 @@
 	unsigned int saved_framenumber;		/* Save during PM suspend */
 
 	/* Main list of URB's currently controlled by this HC */
-	spinlock_t urb_list_lock;
-	struct list_head urb_list;		/* P: uhci->urb_list_lock */
+	struct list_head urb_list;		/* P: uhci->schedule_lock */
 
 	/* List of QH's that are done, but waiting to be unlinked (race) */
-	spinlock_t qh_remove_list_lock;
-	struct list_head qh_remove_list;	/* P: uhci->qh_remove_list_lock */
+	struct list_head qh_remove_list;	/* P: uhci->schedule_lock */
 
 	/* List of TD's that are done, but waiting to be freed (race) */
-	spinlock_t td_remove_list_lock;
-	struct list_head td_remove_list;	/* P: uhci->td_remove_list_lock */
+	struct list_head td_remove_list;	/* P: uhci->schedule_lock */
 
 	/* List of asynchronously unlinked URB's */
-	spinlock_t urb_remove_list_lock;
-	struct list_head urb_remove_list;	/* P: uhci->urb_remove_list_lock */
+	struct list_head urb_remove_list;	/* P: uhci->schedule_lock */
 
 	/* List of URB's awaiting completion callback */
-	spinlock_t complete_list_lock;
-	struct list_head complete_list;		/* P: uhci->complete_list_lock */
+	struct list_head complete_list;		/* P: uhci->schedule_lock */
 
 	int rh_numports;
 
@@ -401,26 +396,15 @@
 /*
  * Locking in uhci.c
  *
- * spinlocks are used extensively to protect the many lists and data
- * structures we have. It's not that pretty, but it's necessary. We
- * need to be done with all of the locks (except complete_list_lock) when
- * we call urb->complete. I've tried to make it simple enough so I don't
- * have to spend hours racking my brain trying to figure out if the
- * locking is safe.
+ * Almost everything relating to the hardware schedule and processing
+ * of URBs is protected by uhci->schedule_lock.  urb->status is protected
+ * by urb->lock; that's the one exception.
  *
- * Here's the safe locking order to prevent deadlocks:
+ * To prevent deadlocks, never lock uhci->schedule_lock while holding
+ * urb->lock.  The safe order of locking is:
  *
- * #1 uhci->urb_list_lock
+ * #1 uhci->schedule_lock
  * #2 urb->lock
- * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, 
- *   uhci->qh_remove_list_lock
- * #4 uhci->complete_list_lock
- *
- * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
- * at the lowest level FIRST and NEVER grab locks at the same level at the
- * same time.
- * 
- * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock
  */
 
 #endif
diff -Nru a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
--- a/drivers/usb/input/ati_remote.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/input/ati_remote.c	Fri Mar 26 12:25:30 2004
@@ -99,7 +99,7 @@
 #define DATA_BUFSIZE      63    /* size of URB data buffers */
 #define ATI_INPUTNUM      1     /* Which input device to register as */
 
-unsigned long channel_mask = 0;
+static unsigned long channel_mask = 0;
 module_param(channel_mask, ulong, 444);
 MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
 
@@ -139,6 +139,8 @@
  */
 #define FILTER_TIME (HZ >> 4)
 
+static DECLARE_MUTEX(disconnect_sem);
+
 struct ati_remote {
 	struct input_dev idev;		
 	struct usb_device *udev;
@@ -286,12 +288,12 @@
 static void ati_remote_dump(unsigned char *data, unsigned int len)
 {
 	if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
-		warn("Weird byte 0x%02x\n", data[0]);
+		warn("Weird byte 0x%02x", data[0]);
 	else if (len == 4)
-		warn("Weird key %02x %02x %02x %02x\n", 
+		warn("Weird key %02x %02x %02x %02x", 
 		     data[0], data[1], data[2], data[3]);
 	else
-		warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
+		warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
 		     len, data[0], data[1], data[2], data[3], data[4], data[5]);
 }
 
@@ -301,9 +303,12 @@
 static int ati_remote_open(struct input_dev *inputdev)
 {
 	struct ati_remote *ati_remote = inputdev->private;
+	int retval = 0;
+
+	down(&disconnect_sem);
 
 	if (ati_remote->open++)
-		return 0;
+		goto exit;
 
 	/* On first open, submit the read urb which was set up previously. */
 	ati_remote->irq_urb->dev = ati_remote->udev;
@@ -311,10 +316,12 @@
 		dev_err(&ati_remote->interface->dev, 
 			"%s: usb_submit_urb failed!\n", __FUNCTION__);
 		ati_remote->open--;
-		return -EIO;
+		retval = -EIO;
 	}
 
-	return 0;
+exit:
+	up(&disconnect_sem);
+	return retval;
 }
 
 /*
@@ -354,8 +361,7 @@
 	
 	ati_remote->send_flags |= SEND_FLAG_COMPLETE;
 	wmb();
-	if (waitqueue_active(&ati_remote->wait))
-		wake_up(&ati_remote->wait);
+	wake_up(&ati_remote->wait);
 }
 
 /*
@@ -377,18 +383,16 @@
 	ati_remote->out_urb->dev = ati_remote->udev;
 	ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
 
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&ati_remote->wait, &wait);
-
-	retval = usb_submit_urb(ati_remote->out_urb, GFP_KERNEL);
+	retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
 	if (retval) {
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&ati_remote->wait, &wait);
 		dev_dbg(&ati_remote->interface->dev, 
 			 "sendpacket: usb_submit_urb failed: %d\n", retval);
 		return retval;
 	}
 
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&ati_remote->wait, &wait);
+
 	while (timeout && (ati_remote->out_urb->status == -EINPROGRESS) 
 	       && !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) {
 		timeout = schedule_timeout(timeout);
@@ -594,11 +598,7 @@
 	if (ati_remote->out_urb)
 		usb_unlink_urb(ati_remote->out_urb);
 
-	if (ati_remote->irq_urb)
-		usb_free_urb(ati_remote->irq_urb);
-	
-	if (ati_remote->out_urb)
-		usb_free_urb(ati_remote->out_urb);
+	input_unregister_device(&ati_remote->idev);
 
 	if (ati_remote->inbuf)
 		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
@@ -608,6 +608,12 @@
 		usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, 
 				ati_remote->inbuf, ati_remote->outbuf_dma);
 	
+	if (ati_remote->irq_urb)
+		usb_free_urb(ati_remote->irq_urb);
+	
+	if (ati_remote->out_urb)
+		usb_free_urb(ati_remote->out_urb);
+
 	kfree(ati_remote);
 }
 
@@ -779,14 +785,14 @@
 
 	usb_set_intfdata(interface, ati_remote);
 	ati_remote->present = 1;	
-	kfree(buf);
-	return 0;
 	
 error:
 	if (buf)
 		kfree(buf);
 
-	ati_remote_delete(ati_remote);
+	if (retval)
+		ati_remote_delete(ati_remote);
+
 	return retval;
 }
 
@@ -796,7 +802,9 @@
 static void ati_remote_disconnect(struct usb_interface *interface)
 {
 	struct ati_remote *ati_remote;
-	
+
+	down(&disconnect_sem);
+
 	ati_remote = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 	if (!ati_remote) {
@@ -804,14 +812,14 @@
 		return;
 	}
 	
-	input_unregister_device(&ati_remote->idev);
-
 	/* Mark device as unplugged */
 	ati_remote->present = 0;
 
 	/* If device is still open, ati_remote_close will call delete. */
 	if (!ati_remote->open)
 		ati_remote_delete(ati_remote);
+
+	up(&disconnect_sem);
 }
 
 /*
diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/input/hiddev.c	Fri Mar 26 12:25:30 2004
@@ -403,8 +403,8 @@
 	struct hiddev_collection_info cinfo;
 	struct hiddev_report_info rinfo;
 	struct hiddev_field_info finfo;
-	struct hiddev_usage_ref_multi uref_multi;
-	struct hiddev_usage_ref *uref = &uref_multi.uref;
+	struct hiddev_usage_ref_multi *uref_multi=NULL;
+	struct hiddev_usage_ref *uref;
 	struct hiddev_devinfo dinfo;
 	struct hid_report *report;
 	struct hid_field *field;
@@ -576,26 +576,31 @@
 		return 0;
 
 	case HIDIOCGUCODE:
-		if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
-			return -EFAULT;
+		uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+		if (!uref_multi)
+			return -ENOMEM;
+		uref = &uref_multi->uref;
+		if (copy_from_user(uref, (void *) arg, sizeof(*uref))) 
+			goto fault;
 
 		rinfo.report_type = uref->report_type;
 		rinfo.report_id = uref->report_id;
 		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-			return -EINVAL;
+			goto inval;
 
 		if (uref->field_index >= report->maxfield)
-			return -EINVAL;
+			goto inval;
 
 		field = report->field[uref->field_index];
 		if (uref->usage_index >= field->maxusage)
-			return -EINVAL;
+			goto inval;
 
 		uref->usage_code = field->usage[uref->usage_index].hid;
 
 		if (copy_to_user((void *) arg, uref, sizeof(*uref)))
-			return -EFAULT;
+			goto fault;
 
+		kfree(uref_multi);
 		return 0;
 
 	case HIDIOCGUSAGE:
@@ -603,42 +608,46 @@
 	case HIDIOCGUSAGES:
 	case HIDIOCSUSAGES:
 	case HIDIOCGCOLLECTIONINDEX:
+		uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+		if (!uref_multi)
+			return -ENOMEM;
+		uref = &uref_multi->uref;
 		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-			if (copy_from_user(&uref_multi, (void *) arg, 
+			if (copy_from_user(uref_multi, (void *) arg, 
 					   sizeof(uref_multi)))
-				return -EFAULT;
+				goto fault;
 		} else {
 			if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
-				return -EFAULT;
+				goto fault;
 		}
 
 		if (cmd != HIDIOCGUSAGE && 
 		    cmd != HIDIOCGUSAGES &&
 		    uref->report_type == HID_REPORT_TYPE_INPUT)
-			return -EINVAL;
+			goto inval;
 
 		if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
 			field = hiddev_lookup_usage(hid, uref);
 			if (field == NULL)
-				return -EINVAL;
+				goto inval;
 		} else {
 			rinfo.report_type = uref->report_type;
 			rinfo.report_id = uref->report_id;
 			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-				return -EINVAL;
+				goto inval;
 
 			if (uref->field_index >= report->maxfield)
-				return -EINVAL;
+				goto inval;
 
 			field = report->field[uref->field_index];
 			if (uref->usage_index >= field->maxusage)
-				return -EINVAL;
+				goto inval;
 
 			if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-				if (uref_multi.num_values >= HID_MAX_USAGES || 
+				if (uref_multi->num_values >= HID_MAX_USAGES || 
 				    uref->usage_index >= field->maxusage || 
-				   (uref->usage_index + uref_multi.num_values) >= field->maxusage)
-					return -EINVAL;
+				   (uref->usage_index + uref_multi->num_values) >= field->maxusage)
+					goto inval;
 			}
 		}
 
@@ -646,31 +655,40 @@
 			case HIDIOCGUSAGE:
 				uref->value = field->value[uref->usage_index];
 				if (copy_to_user((void *) arg, uref, sizeof(*uref)))
-					return -EFAULT;
-				return 0;
+					goto fault;
+				goto goodreturn;
 
 			case HIDIOCSUSAGE:
 				field->value[uref->usage_index] = uref->value;
-				return 0;
+				goto goodreturn;
 
 			case HIDIOCGCOLLECTIONINDEX:
+				kfree(uref_multi);
 				return field->usage[uref->usage_index].collection_index;
 			case HIDIOCGUSAGES:
-				for (i = 0; i < uref_multi.num_values; i++)
-					uref_multi.values[i] = 
+				for (i = 0; i < uref_multi->num_values; i++)
+					uref_multi->values[i] = 
 					    field->value[uref->usage_index + i];
-				if (copy_to_user((void *) arg, &uref_multi, 
-						 sizeof(uref_multi)))
-					return -EFAULT;
-				return 0;
+				if (copy_to_user((void *) arg, uref_multi, 
+						 sizeof(*uref_multi)))
+					goto fault;
+				goto goodreturn;
 			case HIDIOCSUSAGES:
-				for (i = 0; i < uref_multi.num_values; i++)
+				for (i = 0; i < uref_multi->num_values; i++)
 					field->value[uref->usage_index + i] = 
-				  	    uref_multi.values[i];
-				return 0;
+				  	    uref_multi->values[i];
+				goto goodreturn;
 		}
 
+goodreturn:
+		kfree(uref_multi);
 		return 0;
+fault:
+		kfree(uref_multi);
+		return -EFAULT;
+inval:		
+		kfree(uref_multi);
+		return -EINVAL;
 
 	case HIDIOCGCOLLECTIONINFO:
 		if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo)))
diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
--- a/drivers/usb/media/vicam.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/media/vicam.c	Fri Mar 26 12:25:30 2004
@@ -1269,6 +1269,8 @@
 
 /**
  *	vicam_probe
+ *	@intf: the interface
+ *	@id: the device id
  *
  *	Called by the usb core when a new device is connected that it thinks
  *	this driver might be interested in.
diff -Nru a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
--- a/drivers/usb/media/w9968cf.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/media/w9968cf.c	Fri Mar 26 12:25:30 2004
@@ -905,8 +905,7 @@
 	spin_unlock(&cam->urb_lock);
 
 	/* Wake up the user process */
-	if (waitqueue_active(&cam->wait_queue))
-		wake_up_interruptible(&cam->wait_queue);
+	wake_up_interruptible(&cam->wait_queue);
 }
 
 
@@ -2690,6 +2689,7 @@
 			up(&cam->dev_sem);
 			return -EWOULDBLOCK;
 		}
+retry:
 		up(&cam->dev_sem);
 		err = wait_event_interruptible(cam->open, cam->disconnected ||
 		                               (cam->users == 0));
@@ -2698,6 +2698,9 @@
 		if (cam->disconnected)
 			return -ENODEV;
 		down(&cam->dev_sem);
+		/*recheck - there may be several waiters */
+		if (cam->users)
+			goto retry;
 	}
 
 	DBG(5, "Opening '%s', /dev/video%d ...",
@@ -2758,8 +2761,7 @@
 	cam->users--;
 	w9968cf_deallocate_memory(cam);
 
-	if (waitqueue_active(&cam->open))
-		wake_up_interruptible(&cam->open);
+	wake_up_interruptible(&cam->open);
 
 	DBG(5, "Video device closed.")
 	up(&cam->dev_sem);
diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
--- a/drivers/usb/misc/Kconfig	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/misc/Kconfig	Fri Mar 26 12:25:30 2004
@@ -108,6 +108,19 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called usbled.
 
+config USB_CYTHERM
+	tristate "Cypress USB thermometer driver support"
+	depends on USB
+	help
+	  Say Y here if you want to connect a Cypress USB thermometer
+	  device to your computer's USB port. This device is also known
+	  as the Cypress USB Starter kit or demo board. The Elektor
+	  magazine published a modified version of this device in issue 
+	  #291.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cytherm.
+
 config USB_SPEEDTOUCH
 	tristate "Alcatel Speedtouch USB support"
 	depends on USB && ATM
diff -Nru a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
--- a/drivers/usb/misc/Makefile	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/misc/Makefile	Fri Mar 26 12:25:30 2004
@@ -4,8 +4,9 @@
 #
 
 obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
-obj-$(CONFIG_USB_EMI62)		+= emi62.o
+obj-$(CONFIG_USB_CYTHERM)	+= cytherm.o
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
+obj-$(CONFIG_USB_EMI62)		+= emi62.o
 obj-$(CONFIG_USB_LCD)		+= usblcd.o
 obj-$(CONFIG_USB_LED)		+= usbled.o
 obj-$(CONFIG_USB_LEGOTOWER)	+= legousbtower.o
diff -Nru a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/misc/cytherm.c	Fri Mar 26 12:25:30 2004
@@ -0,0 +1,433 @@
+/* -*- linux-c -*-
+ * Cypress USB Thermometer driver 
+ * 
+ * Copyright (c) 2004 Erik Rigtorp <erkki@linux.nu> <erik@rigtorp.com>
+ * 
+ * This driver works with Elektor magazine USB Interface as published in 
+ * issue #291. It should also work with the original starter kit/demo board
+ * from Cypress.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Erik Rigtorp"
+#define DRIVER_DESC "Cypress USB Thermometer driver"
+
+#define USB_SKEL_VENDOR_ID	0x04b4
+#define USB_SKEL_PRODUCT_ID	0x0002
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE (usb, id_table);
+
+/* Structure to hold all of our device specific stuff */
+struct usb_cytherm {
+	struct usb_device    *udev;	 /* save off the usb device pointer */
+	struct usb_interface *interface; /* the interface for this device */
+	int brightness;
+};
+
+
+/* local function prototypes */
+static int cytherm_probe(struct usb_interface *interface, 
+			 const struct usb_device_id *id);
+static void cytherm_disconnect(struct usb_interface *interface);
+int vendor_command(struct usb_device *dev, unsigned char request, 
+		   unsigned char value, unsigned char index,
+		   void *buf, int size);
+
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver cytherm_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"cytherm",
+	.probe =	cytherm_probe,
+	.disconnect =	cytherm_disconnect,
+	.id_table =	id_table,
+};
+
+/* Vendor requests */
+/* They all operate on one byte at a time */
+#define PING       0x00
+#define READ_ROM   0x01 /* Reads form ROM, value = address */
+#define READ_RAM   0x02 /* Reads form RAM, value = address */
+#define WRITE_RAM  0x03 /* Write to RAM, value = address, index = data */
+#define READ_PORT  0x04 /* Reads from port, value = address */
+#define WRITE_PORT 0x05 /* Write to port, value = address, index = data */ 
+
+
+/* Send a vendor command to device */
+int vendor_command(struct usb_device *dev, unsigned char request, 
+		   unsigned char value, unsigned char index,
+		   void *buf, int size)
+{
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			       request, 
+			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+			       value, 
+			       index, buf, size,
+			       HZ * USB_CTRL_GET_TIMEOUT);
+}
+
+
+
+#define BRIGHTNESS 0x2c     /* RAM location for brightness value */
+#define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */
+
+static ssize_t show_brightness(struct device *dev, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);    
+	struct usb_cytherm *cytherm = usb_get_intfdata(intf);     
+
+	return sprintf(buf, "%i", cytherm->brightness);
+}
+
+static ssize_t set_brightness(struct device *dev, const char *buf, 
+			      size_t count)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_cytherm *cytherm = usb_get_intfdata(intf);
+
+	unsigned char *buffer;
+	int retval;
+   
+	buffer = kmalloc(8, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(&cytherm->udev->dev, "out of memory\n");
+		return 0;
+	}
+
+	cytherm->brightness = simple_strtoul(buf, NULL, 10);
+   
+	if (cytherm->brightness > 0xFF)
+		cytherm->brightness = 0xFF;
+	else if (cytherm->brightness < 0)
+		cytherm->brightness = 0;
+   
+	/* Set brightness */
+	retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS, 
+				cytherm->brightness, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+	/* Inform µC that we have changed the brightness setting */
+	retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM,
+				0x01, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+   
+	kfree(buffer);
+   
+	return count;
+}
+
+static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, 
+		   show_brightness, set_brightness);
+
+
+#define TEMP 0x33 /* RAM location for temperature */
+#define SIGN 0x34 /* RAM location for temperature sign */
+
+static ssize_t show_temp(struct device *dev, char *buf)
+{
+
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_cytherm *cytherm = usb_get_intfdata(intf);
+
+	int retval;
+	unsigned char *buffer;
+
+	int temp, sign;
+   
+	buffer = kmalloc(8, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(&cytherm->udev->dev, "out of memory\n");
+		return 0;
+	}
+
+	/* read temperature */
+	retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+	temp = buffer[1];
+   
+	/* read sign */
+	retval = vendor_command(cytherm->udev, READ_RAM, SIGN, 0, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+	sign = buffer[1];
+
+	kfree(buffer);
+   
+	return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1,
+		       5*(temp - ((temp >> 1) << 1)));
+}
+
+
+static ssize_t set_temp(struct device *dev, const char *buf, size_t count)
+{
+	return count;
+}
+
+static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp);
+
+
+#define BUTTON 0x7a
+
+static ssize_t show_button(struct device *dev, char *buf)
+{
+
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_cytherm *cytherm = usb_get_intfdata(intf);
+
+	int retval;
+	unsigned char *buffer;
+
+	buffer = kmalloc(8, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(&cytherm->udev->dev, "out of memory\n");
+		return 0;
+	}
+
+	/* check button */
+	retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+   
+	retval = buffer[1];
+
+	kfree(buffer);
+
+	if (retval)
+		return sprintf(buf, "1");
+	else
+		return sprintf(buf, "0");
+}
+
+
+static ssize_t set_button(struct device *dev, const char *buf, size_t count)
+{
+	return count;
+}
+
+static DEVICE_ATTR(button, S_IRUGO, show_button, set_button);
+
+
+static ssize_t show_port0(struct device *dev, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_cytherm *cytherm = usb_get_intfdata(intf);
+
+	int retval;
+	unsigned char *buffer;
+
+	buffer = kmalloc(8, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(&cytherm->udev->dev, "out of memory\n");
+		return 0;
+	}
+
+	retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+
+	retval = buffer[1];
+
+	kfree(buffer);
+
+	return sprintf(buf, "%d", retval);
+}
+
+
+static ssize_t set_port0(struct device *dev, const char *buf, size_t count)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_cytherm *cytherm = usb_get_intfdata(intf);
+
+	unsigned char *buffer;
+	int retval;
+	int tmp;
+   
+	buffer = kmalloc(8, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(&cytherm->udev->dev, "out of memory\n");
+		return 0;
+	}
+
+	tmp = simple_strtoul(buf, NULL, 10);
+   
+	if (tmp > 0xFF)
+		tmp = 0xFF;
+	else if (tmp < 0)
+		tmp = 0;
+   
+	retval = vendor_command(cytherm->udev, WRITE_PORT, 0,
+				tmp, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+
+	kfree(buffer);
+
+	return count;
+}
+
+static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0);
+
+static ssize_t show_port1(struct device *dev, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_cytherm *cytherm = usb_get_intfdata(intf);
+
+	int retval;
+	unsigned char *buffer;
+
+	buffer = kmalloc(8, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(&cytherm->udev->dev, "out of memory\n");
+		return 0;
+	}
+
+	retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+   
+	retval = buffer[1];
+
+	kfree(buffer);
+
+	return sprintf(buf, "%d", retval);
+}
+
+
+static ssize_t set_port1(struct device *dev, const char *buf, size_t count)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_cytherm *cytherm = usb_get_intfdata(intf);
+
+	unsigned char *buffer;
+	int retval;
+	int tmp;
+   
+	buffer = kmalloc(8, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(&cytherm->udev->dev, "out of memory\n");
+		return 0;
+	}
+
+	tmp = simple_strtoul(buf, NULL, 10);
+   
+	if (tmp > 0xFF)
+		tmp = 0xFF;
+	else if (tmp < 0)
+		tmp = 0;
+   
+	retval = vendor_command(cytherm->udev, WRITE_PORT, 1,
+				tmp, buffer, 8);
+	if (retval)
+		dev_dbg(&led->udev->dev, "retval = %d\n", retval);
+
+	kfree(buffer);
+
+	return count;
+}
+
+static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1);
+
+
+
+static int cytherm_probe(struct usb_interface *interface, 
+			 const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_cytherm *dev = NULL;
+	int retval = -ENOMEM;
+
+	dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
+	if (dev == NULL) {
+		dev_err (&interface->dev, "Out of memory\n");
+		goto error;
+	}
+	memset (dev, 0x00, sizeof (*dev));
+
+	dev->udev = usb_get_dev(udev);
+
+	usb_set_intfdata (interface, dev);
+
+	dev->brightness = 0xFF;
+
+	device_create_file(&interface->dev, &dev_attr_brightness);   
+	device_create_file(&interface->dev, &dev_attr_temp);
+	device_create_file(&interface->dev, &dev_attr_button);
+	device_create_file(&interface->dev, &dev_attr_port0);
+	device_create_file(&interface->dev, &dev_attr_port1);
+
+	dev_info (&interface->dev, 
+		  "Cypress thermometer device now attached\n");
+	return 0;
+
+ error:
+	kfree(dev);
+	return retval;
+}
+
+static void cytherm_disconnect(struct usb_interface *interface)
+{
+	struct usb_cytherm *dev;
+
+	dev = usb_get_intfdata (interface);
+	usb_set_intfdata (interface, NULL);
+
+	device_remove_file(&interface->dev, &dev_attr_brightness);
+	device_remove_file(&interface->dev, &dev_attr_temp);
+	device_remove_file(&interface->dev, &dev_attr_button);
+	device_remove_file(&interface->dev, &dev_attr_port0);
+	device_remove_file(&interface->dev, &dev_attr_port1);
+
+	usb_put_dev(dev->udev);
+
+	kfree(dev);
+
+	dev_info(&interface->dev, "Cypress thermometer now disconnected\n");
+}
+
+
+static int __init usb_cytherm_init(void)
+{
+	int result;
+
+	result = usb_register(&cytherm_driver);
+	if (result) 
+	{	
+		err("usb_register failed. Error number %d", result);
+		return result;
+	}
+
+	info(DRIVER_VERSION ":" DRIVER_DESC);
+	return 0;
+}
+
+static void __exit usb_cytherm_exit(void)
+{
+	usb_deregister(&cytherm_driver);
+}
+
+
+module_init (usb_cytherm_init);
+module_exit (usb_cytherm_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
--- a/drivers/usb/net/Kconfig	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/net/Kconfig	Fri Mar 26 12:25:30 2004
@@ -69,7 +69,7 @@
 
 config USB_PEGASUS
 	tristate "USB Pegasus/Pegasus-II based ethernet device support"
-	depends on USB && NET_ETHERNET
+	depends on USB && NET
 	select MII
 	---help---
 	  Say Y here if you know you have Pegasus or Pegasus-II based adapter.
diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
--- a/drivers/usb/net/rtl8150.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/net/rtl8150.c	Fri Mar 26 12:25:30 2004
@@ -20,7 +20,7 @@
 #include <asm/uaccess.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v0.5.7 (2002/12/31)"
+#define DRIVER_VERSION "v0.6.1 (2004/03/13)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
 
@@ -43,6 +43,8 @@
 #define	ANAR			0x0144
 #define	ANLP			0x0146
 #define	AER			0x0148
+#define CSCR			0x014C  /* This one has the link status */
+#define CSCR_LINK_STATUS	(1 << 3)
 
 #define	IDR_EEPROM		0x1202
 
@@ -58,6 +60,60 @@
 #define	RTL8150_REQ_GET_REGS	0x05
 #define	RTL8150_REQ_SET_REGS	0x05
 
+
+/* Transmit status register errors */
+#define TSR_ECOL		(1<<5)
+#define TSR_LCOL		(1<<4)
+#define TSR_LOSS_CRS		(1<<3)
+#define TSR_JBR			(1<<2)
+#define TSR_ERRORS		(TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR)
+/* Receive status register errors */
+#define RSR_CRC			(1<<2)
+#define RSR_FAE			(1<<1)
+#define RSR_ERRORS		(RSR_CRC | RSR_FAE)
+
+/* Media status register definitions */
+#define MSR_DUPLEX		(1<<4)
+#define MSR_SPEED		(1<<3)
+#define MSR_LINK		(1<<2)
+
+/* Interrupt pipe data */
+#define INT_TSR			0x00
+#define INT_RSR			0x01
+#define INT_MSR			0x02
+#define INT_WAKSR		0x03
+#define INT_TXOK_CNT		0x04
+#define INT_RXLOST_CNT		0x05
+#define INT_CRERR_CNT		0x06
+#define INT_COL_CNT		0x07
+
+/* Transmit status register errors */
+#define TSR_ECOL		(1<<5)
+#define TSR_LCOL		(1<<4)
+#define TSR_LOSS_CRS		(1<<3)
+#define TSR_JBR			(1<<2)
+#define TSR_ERRORS		(TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR)
+/* Receive status register errors */
+#define RSR_CRC			(1<<2)
+#define RSR_FAE			(1<<1)
+#define RSR_ERRORS		(RSR_CRC | RSR_FAE)
+
+/* Media status register definitions */
+#define MSR_DUPLEX		(1<<4)
+#define MSR_SPEED		(1<<3)
+#define MSR_LINK		(1<<2)
+
+/* Interrupt pipe data */
+#define INT_TSR			0x00
+#define INT_RSR			0x01
+#define INT_MSR			0x02
+#define INT_WAKSR		0x03
+#define INT_TXOK_CNT		0x04
+#define INT_RXLOST_CNT		0x05
+#define INT_CRERR_CNT		0x06
+#define INT_COL_CNT		0x07
+
+
 #define	RTL8150_MTU		1540
 #define	RTL8150_TX_TIMEOUT	(HZ)
 #define	RX_SKB_POOL_SIZE	4
@@ -71,9 +127,13 @@
 /* Define these values to match your device */
 #define VENDOR_ID_REALTEK		0x0bda
 #define	VENDOR_ID_MELCO			0x0411
+#define VENDOR_ID_MICRONET		0x3980
+#define	VENDOR_ID_LONGSHINE		0x07b8
 
 #define PRODUCT_ID_RTL8150		0x8150
 #define	PRODUCT_ID_LUAKTX		0x0012
+#define	PRODUCT_ID_LCS8138TX		0x401a
+#define PRODUCT_ID_SP128AR		0x0003
 
 #undef	EEPROM_WRITE
 
@@ -81,6 +141,8 @@
 static struct usb_device_id rtl8150_table[] = {
 	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
 	{USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
+	{USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
+	{USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
 	{}
 };
 
@@ -368,6 +430,9 @@
 
 	if (!dev->rx_skb)
 		goto resched;
+	/* protect against short packets (tell me why we got some?!?) */
+	if (urb->actual_length < 4)
+		goto goon;
 
 	res = urb->actual_length;
 	rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4));
@@ -454,6 +519,7 @@
 void intr_callback(struct urb *urb, struct pt_regs *regs)
 {
 	rtl8150_t *dev;
+	__u8 *d;
 	int status;
 
 	dev = urb->context;
@@ -472,7 +538,28 @@
 		goto resubmit;
 	}
 
-	/* FIXME if this doesn't do anything, don't submit the urb! */
+	d = urb->transfer_buffer;
+	if (d[0] & TSR_ERRORS) {
+		dev->stats.tx_errors++;
+		if (d[INT_TSR] & (TSR_ECOL | TSR_JBR))
+			dev->stats.tx_aborted_errors++;
+		if (d[INT_TSR] & TSR_LCOL)
+			dev->stats.tx_window_errors++;
+		if (d[INT_TSR] & TSR_LOSS_CRS)
+			dev->stats.tx_carrier_errors++;
+	}
+	/* Report link status changes to the network stack */
+	if ((d[INT_MSR] & MSR_LINK) == 0) {
+		if (netif_carrier_ok(dev->netdev)) {
+			netif_carrier_off(dev->netdev);
+			dbg("%s: LINK LOST\n", __func__);
+		}
+	} else {
+		if (!netif_carrier_ok(dev->netdev)) {
+			netif_carrier_on(dev->netdev);
+			dbg("%s: LINK CAME BACK\n", __func__);
+		}
+	}
 
 resubmit:
 	status = usb_submit_urb (urb, SLAB_ATOMIC);
@@ -482,6 +569,7 @@
 				dev->udev->devpath, status);
 }
 
+
 /*
 **
 **	network related part of the code
@@ -538,7 +626,7 @@
 		warn("%s - device reset failed", __FUNCTION__);
 	}
 	/* RCR bit7=1 attach Rx info at the end;  =0 HW CRC (which is broken) */
-	rcr = 0x9e;	/* bit7=1 attach Rx info at the end */
+	rcr = 0x9e;
 	dev->rx_creg = cpu_to_le16(rcr);
 	tcr = 0xd8;
 	cr = 0x0c;
@@ -626,6 +714,19 @@
 	return 0;
 }
 
+
+static void set_carrier(struct net_device *netdev)
+{
+	rtl8150_t *dev = netdev->priv;
+	short tmp;
+
+	get_registers(dev, CSCR, 2, &tmp);
+	if (tmp & CSCR_LINK_STATUS)
+		netif_carrier_on(netdev);
+	else
+		netif_carrier_off(netdev);
+}
+
 static int rtl8150_open(struct net_device *netdev)
 {
 	rtl8150_t *dev;
@@ -653,6 +754,7 @@
 		warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
 	netif_start_queue(netdev);
 	enable_net_traffic(dev);
+	set_carrier(netdev);
 
 	return res;
 }
@@ -674,7 +776,7 @@
 	return res;
 }
 
-static int rtl8150_ethtool_ioctl(struct net_device *netdev, void __user *uaddr)
+static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
 {
 	rtl8150_t *dev;
 	int cmd;
@@ -759,7 +861,7 @@
 
 	switch (cmd) {
 	case SIOCETHTOOL:
-		res = rtl8150_ethtool_ioctl(netdev, (void __user *)rq->ifr_data);
+		res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data);
 		break;
 	case SIOCDEVPRIVATE:
 		data[0] = dev->phy;
@@ -774,6 +876,7 @@
 	default:
 		res = -EOPNOTSUPP;
 	}
+
 	return res;
 }
 
@@ -796,7 +899,6 @@
 		kfree(dev);
 		return -ENOMEM;
 	}
-
 	netdev = alloc_etherdev(0);
 	if (!netdev) {
 		kfree(dev->intr_buff);
@@ -837,7 +939,6 @@
 	info("%s: rtl8150 is detected", netdev->name);
 	
 	usb_set_intfdata(intf, dev);
-
 	SET_NETDEV_DEV(netdev, &intf->dev);
 	if (register_netdev(netdev) != 0) {
 		err("couldn't register the device");
diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/serial/ftdi_sio.c	Fri Mar 26 12:25:30 2004
@@ -436,6 +436,7 @@
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_889_PID, 0x400, 0xffff) },
 	{ }						/* Terminating entry */
 };
 
@@ -789,8 +790,14 @@
 static int set_rts(struct usb_serial_port *port, int high_or_low)
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
-	char buf[1];
+	char *buf;
 	unsigned ftdi_high_or_low;
+	int rv;
+	
+	buf = kmalloc(1, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+	
 	if (high_or_low) {
 		ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH;
 		priv->last_dtr_rts |= TIOCM_RTS;
@@ -798,20 +805,29 @@
 		ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW;
 		priv->last_dtr_rts &= ~TIOCM_RTS;
 	}
-	return(usb_control_msg(port->serial->dev,
+	rv = usb_control_msg(port->serial->dev,
 			       usb_sndctrlpipe(port->serial->dev, 0),
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
 			       ftdi_high_or_low, 0, 
-			       buf, 0, WDR_TIMEOUT));
+			       buf, 0, WDR_TIMEOUT);
+
+	kfree(buf);
+	return rv;
 }
 
 
 static int set_dtr(struct usb_serial_port *port, int high_or_low)
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
-	char buf[1];
+	char *buf;
 	unsigned ftdi_high_or_low;
+	int rv;
+	
+	buf = kmalloc(1, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
 	if (high_or_low) {
 		ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH;
 		priv->last_dtr_rts |= TIOCM_DTR;
@@ -819,12 +835,15 @@
 		ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW;
 		priv->last_dtr_rts &= ~TIOCM_DTR;
 	}
-	return(usb_control_msg(port->serial->dev,
+	rv = usb_control_msg(port->serial->dev,
 			       usb_sndctrlpipe(port->serial->dev, 0),
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
 			       ftdi_high_or_low, 0, 
-			       buf, 0, WDR_TIMEOUT));
+			       buf, 0, WDR_TIMEOUT);
+
+	kfree(buf);
+	return rv;
 }
 
 
@@ -833,21 +852,29 @@
 
 static int change_speed(struct usb_serial_port *port)
 {
-	char buf[1];
+	char *buf;
         __u16 urb_value;
 	__u16 urb_index;
 	__u32 urb_index_value;
+	int rv;
+
+	buf = kmalloc(1, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
 
 	urb_index_value = get_ftdi_divisor(port);
 	urb_value = (__u16)urb_index_value;
 	urb_index = (__u16)(urb_index_value >> 16);
 	
-	return (usb_control_msg(port->serial->dev,
+	rv = usb_control_msg(port->serial->dev,
 			    usb_sndctrlpipe(port->serial->dev, 0),
 			    FTDI_SIO_SET_BAUDRATE_REQUEST,
 			    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
 			    urb_value, urb_index,
-			    buf, 0, 100) < 0);
+			    buf, 0, 100);
+
+	kfree(buf);
+	return rv;
 }
 
 
diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
--- a/drivers/usb/serial/ftdi_sio.h	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/serial/ftdi_sio.h	Fri Mar 26 12:25:30 2004
@@ -162,6 +162,11 @@
 #define PROTEGO_SPECIAL_3	0xFC72	/* special/unknown device */
 #define PROTEGO_SPECIAL_4	0xFC73	/* special/unknown device */ 
 
+/* 
+ * Gude Analog- und Digitalsysteme GmbH
+ */
+#define FTDI_GUDEADS_889_PID    0xe889  /* USB RS323 OptoBridge */ 
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
--- a/drivers/usb/serial/io_ti.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/serial/io_ti.c	Fri Mar 26 12:25:30 2004
@@ -274,7 +274,7 @@
 /**
  * TIReadDownloadMemory - Read edgeport memory from TI chip
  * @dev: usb device pointer
- * @address: Device CPU address at which to read
+ * @start_address: Device CPU address at which to read
  * @length: Length of above data
  * @address_type: Can read both XDATA and I2C
  * @buffer: pointer to input data buffer
diff -Nru a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
--- a/drivers/usb/serial/kobil_sct.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/serial/kobil_sct.c	Fri Mar 26 12:25:30 2004
@@ -262,7 +262,7 @@
 	// allocate memory for transfer buffer
 	transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
 	if (! transfer_buffer) {
-		return -1;
+		return -ENOMEM;
 	} else {
 		memset(transfer_buffer, 0, transfer_buffer_length);
 	}
@@ -274,7 +274,7 @@
 		if (!port->write_urb) {
 			dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number);
 			kfree(transfer_buffer);
-			return -1;
+			return -ENOMEM;
 		}
 	}
 
@@ -282,7 +282,9 @@
 	port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
 	if (! port->write_urb->transfer_buffer) {
 		kfree(transfer_buffer);
-		return -1;
+		usb_free_urb(port->write_urb);
+		port->write_urb = NULL;
+		return -ENOMEM;
 	} 
 
 	// get hardware version
diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/storage/unusual_devs.h	Fri Mar 26 12:25:30 2004
@@ -160,7 +160,7 @@
 UNUSUAL_DEV(  0x04da, 0x0901, 0x0100, 0x0200,
 		"Panasonic",
 		"LS-120 Camera",
-		US_SC_UFI, US_PR_CBI, NULL, 0),
+		US_SC_UFI, US_PR_DEVICE, NULL, 0),
 
 /* From Yukihiro Nakai, via zaitcev@yahoo.com.
  * This is needed for CB instead of CBI */
@@ -384,7 +384,7 @@
 UNUSUAL_DEV(  0x05dc, 0xb002, 0x0000, 0x0113,
 		"Lexar",
 		"USB CF Reader",
-		US_SC_SCSI, US_PR_BULK, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
 /* Reported by Carlos Villegas <cav@uniscope.co.jp>
@@ -392,15 +392,15 @@
  * That is the only reason this entry is needed.
  */
 UNUSUAL_DEV(  0x05e3, 0x0700, 0x0000, 0xffff,
-		"SIIG",
-		"CompactFlash Card Reader",
+		"Genesys Logic",
+		"USB to IDE Card Reader",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
 /* Submitted Alexander Oltu <alexander@all-2.com> */
 UNUSUAL_DEV(  0x05e3, 0x0701, 0x0000, 0xffff, 
-		"", 
-		"USB TO IDE",
+		"Genesys Logic", 
+		"USB to IDE Optical",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_MODE_XLATE ), 
 
@@ -411,16 +411,9 @@
  *
  * ST818 slim drives (rev 0.02) don't need special care.
 */
-UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0x0001,
-		"EagleTec",
-		"External Hard Disk",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_INQUIRY ),
-
-/* Reported by Henning Schild <henning@wh9.tu-dresden.de> */
-UNUSUAL_DEV(  0x05e3, 0x0702, 0x0113, 0x0113,
-		"EagleTec",
-		"External Hard Disk",
+UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0xffff,
+		"Genesys Logic",
+		"USB to IDE Disk",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
--- a/drivers/usb/usb-skeleton.c	Fri Mar 26 12:25:30 2004
+++ b/drivers/usb/usb-skeleton.c	Fri Mar 26 12:25:30 2004
@@ -516,7 +516,7 @@
 	dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL);
 	if (dev == NULL) {
 		err ("Out of memory");
-		goto error;
+		return -ENOMEM;
 	}
 	memset (dev, 0x00, sizeof (*dev));
 
diff -Nru a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
--- a/include/linux/usb_gadget.h	Fri Mar 26 12:25:30 2004
+++ b/include/linux/usb_gadget.h	Fri Mar 26 12:25:30 2004
@@ -731,6 +731,15 @@
 int usb_gadget_config_buf(const struct usb_config_descriptor *config,
 	void *buf, unsigned buflen, const struct usb_descriptor_header **desc);
 
+/*-------------------------------------------------------------------------*/
+
+/* utility wrapping a simple endpoint selection policy */
+
+extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *,
+			struct usb_endpoint_descriptor *) __init;
+
+extern void usb_ep_autoconfig_reset (struct usb_gadget *) __init;
+
 #endif  /* __KERNEL__ */
 
 #endif	/* __LINUX_USB_GADGET_H */
