--- linux/include/linux/usb.h-dist	Tue Dec 18 14:30:22 2001
+++ linux/include/linux/usb.h	Tue Dec 18 19:05:20 2001
@@ -1028,6 +1028,21 @@
 #define NS_TO_US(ns)	((ns + 500L) / 1000L)
 			/* convert & round nanoseconds to microseconds */
 
+/*
+ * As of USB 2.0, full/low speed devices are segregated into trees.
+ * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
+ * The other type grows from high speed hubs when they connect to
+ * full/low speed devices using "Transaction Translators" (TTs).
+ *
+ * TTs should only be known to the hub driver, and high speed bus
+ * drivers (only EHCI for now).  They affect periodic scheduling and
+ * sometimes control/bulk error recovery.
+ */
+struct usb_tt {
+	struct usb_device	*hub;	/* upstream highspeed hub */
+	int			multi;	/* true means one TT per port */
+};
+
 
 /* -------------------------------------------------------------------------- */
 
@@ -1056,7 +1071,8 @@
 #define USB_MAXCHILDREN		(16)
 
 struct usb_device {
-	int devnum;			/* Device number on USB bus */
+	int		devnum;		/* Address on USB bus */
+	char		devpath [16];	/* Use in messages: /port/port/... */
 
 	enum {
 		USB_SPEED_UNKNOWN = 0,			/* enumerating */
@@ -1064,8 +1080,8 @@
 		USB_SPEED_HIGH				/* usb 2.0 */
 	} speed;
 
-	struct usb_device *tt;		/* usb1.1 device on usb2.0 bus */
-	int ttport;			/* device/hub port on that tt */
+	struct usb_tt	*tt; 		/* low/full speed dev, highspeed hub */
+	int		ttport;		/* device port on that tt hub */
 
 	atomic_t refcnt;		/* Reference count */
 	struct semaphore serialize;
--- linux/drivers/usb-dist/hub.h	Tue Dec 18 14:30:30 2001
+++ linux/drivers/usb/hub.h	Tue Dec 18 19:05:36 2001
@@ -1,6 +1,13 @@
 #ifndef __LINUX_HUB_H
 #define __LINUX_HUB_H
 
+/*
+ * Hub protocol and driver data structures.
+ *
+ * Some of these are known to the "virtual root hub" code
+ * in host controller drivers.
+ */
+
 #include <linux/list.h>
 
 /*
@@ -11,6 +18,15 @@
 #define USB_RT_PORT	(USB_TYPE_CLASS | USB_RECIP_OTHER)
 
 /*
+ * Hub class requests
+ * See USB 2.0 spec Table 11-16
+ */
+#define HUB_CLEAR_TT_BUFFER	8
+#define HUB_RESET_TT		9
+#define HUB_GET_TT_STATE	10
+#define HUB_STOP_TT		11
+
+/*
  * Hub Class feature numbers
  * See USB 2.0 spec Table 11-17
  */
@@ -55,7 +71,7 @@
 #define USB_PORT_STAT_SUSPEND		0x0004
 #define USB_PORT_STAT_OVERCURRENT	0x0008
 #define USB_PORT_STAT_RESET		0x0010
-/* bits 5 for 7 are reserved */
+/* bits 5 to 7 are reserved */
 #define USB_PORT_STAT_POWER		0x0100
 #define USB_PORT_STAT_LOW_SPEED		0x0200
 #define USB_PORT_STAT_HIGH_SPEED        0x0400
@@ -120,22 +136,21 @@
 struct usb_device;
 
 struct usb_hub {
-	struct usb_device *dev;
-
-	struct urb *urb;		/* Interrupt polling pipe */
-
-	char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */
-					/* and add 7 bits to round up to byte boundary */
-	int error;
-	int nerrors;
+	struct usb_device	*dev;		/* the "real" device */
+	struct urb		*urb;		/* for interrupt polling pipe */
 
-	struct list_head hub_list;
+	/* buffer for urb ... 1 bit each for hub and children, rounded up */
+	char			buffer[(USB_MAXCHILDREN + 1 + 7) / 8];
 
-	struct list_head event_list;
+	int			error;		/* last reported error */
+	int			nerrors;	/* track consecutive errors */
 
-	struct usb_hub_descriptor *descriptor;
+	struct list_head	hub_list;	/* all hubs */
+	struct list_head	event_list;	/* hubs w/data or errs ready */
 
-	struct semaphore khubd_sem;
+	struct usb_hub_descriptor *descriptor;	/* class descriptor */
+	struct semaphore	khubd_sem;
+	struct usb_tt		tt;		/* Transaction Translator */
 };
 
 #endif /* __LINUX_HUB_H */
--- linux/drivers/usb-dist/hub.c	Tue Dec 18 14:30:30 2001
+++ linux/drivers/usb/hub.c	Tue Dec 18 17:07:31 2001
@@ -35,7 +35,7 @@
 static DECLARE_MUTEX(usb_address0_sem);
 
 static LIST_HEAD(hub_event_list);	/* List of hubs needing servicing */
-static LIST_HEAD(hub_list);		/* List containing all of the hubs (for cleanup) */
+static LIST_HEAD(hub_list);		/* List of all hubs (for cleanup) */
 
 static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 static int khubd_pid = 0;			/* PID of khubd */
@@ -110,22 +110,30 @@
 		data, sizeof(struct usb_hub_status), HZ);
 }
 
+/* completion function, fires on port status changes and various faults */
 static void hub_irq(struct urb *urb)
 {
 	struct usb_hub *hub = (struct usb_hub *)urb->context;
 	unsigned long flags;
 
-	/* Cause a hub reset after 10 consecutive errors */
-	if (urb->status) {
-		if (urb->status == -ENOENT)
-			return;
-
-		dbg("nonzero status in irq %d", urb->status);
+	switch (urb->status) {
+	case -ENOENT:		/* synchronous unlink */
+	case -ECONNRESET:	/* async unlink */
+	case -ESHUTDOWN:	/* hardware going away */
+		return;
 
+	default:		/* presumably an error */
+		/* Cause a hub reset after 10 consecutive errors */
+		dbg("hub '%s' status %d for interrupt transfer",
+			urb->dev->devpath, urb->status);
 		if ((++hub->nerrors < 10) || hub->error)
 			return;
-
 		hub->error = urb->status;
+		/* FALL THROUGH */
+	
+	/* let khubd handle things */
+	case 0:			/* we got data:  port status changed */
+		break;
 	}
 
 	hub->nerrors = 0;
@@ -152,7 +160,8 @@
 	wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
 }
 
-static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
+static int usb_hub_configure(struct usb_hub *hub,
+	struct usb_endpoint_descriptor *endpoint)
 {
 	struct usb_device *dev = hub->dev;
 	struct usb_hub_status hubstatus;
@@ -162,22 +171,30 @@
 
 	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
 	if (!hub->descriptor) {
-		err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor));
+		err("Unable to kmalloc %Zd bytes for hub descriptor",
+			sizeof(*hub->descriptor));
 		return -1;
 	}
 
-	/* Request the entire hub descriptor. */
-	ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor));
-		/* <hub->descriptor> is large enough for a hub with 127 ports;
-		 * the hub can/will return fewer bytes here. */
+	/* Request the entire hub descriptor.
+	 * hub->descriptor can handle USB_MAXCHILDREN ports,
+	 * but the hub can/will return fewer bytes here.
+	 */
+	ret = usb_get_hub_descriptor(dev, hub->descriptor,
+			sizeof(*hub->descriptor));
 	if (ret < 0) {
 		err("Unable to get hub descriptor (err = %d)", ret);
 		kfree(hub->descriptor);
 		return -1;
+	} else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
+		err("Hub is too big! %d children", hub->descriptor->bNbrPorts);
+		kfree(hub->descriptor);
+		return -1;
 	}
 
 	dev->maxchild = hub->descriptor->bNbrPorts;
-	info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s");
+	info("%d port%s detected", dev->maxchild,
+		(dev->maxchild == 1) ? "" : "s");
 
 	le16_to_cpus(&hub->descriptor->wHubCharacteristics);
 
@@ -217,9 +234,12 @@
 			break;
 		case 1:
 			dbg("Single TT");
+			hub->tt.hub = dev;
 			break;
 		case 2:
-			dbg("Multiple TT");
+			dbg("TT per port");
+			hub->tt.hub = dev;
+			hub->tt.multi = 1;
 			break;
 		default:
 			dbg("Unrecognized hub protocol %d",
@@ -244,13 +264,18 @@
 	}
 
 	dbg("Port indicators are %s supported", 
-	    (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not");
+	    (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND)
+	    	? "" : "not");
 
-	dbg("power on to power good time: %dms", hub->descriptor->bPwrOn2PwrGood * 2);
-	dbg("hub controller current requirement: %dmA", hub->descriptor->bHubContrCurrent);
+	dbg("power on to power good time: %dms",
+		hub->descriptor->bPwrOn2PwrGood * 2);
+	dbg("hub controller current requirement: %dmA",
+		hub->descriptor->bHubContrCurrent);
 
 	for (i = 0; i < dev->maxchild; i++)
-		portstr[i] = hub->descriptor->DeviceRemovable[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R';
+		portstr[i] = hub->descriptor->DeviceRemovable
+			    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
+			? 'F' : 'R';
 	portstr[dev->maxchild] = 0;
 
 	dbg("port removable status: %s", portstr);
@@ -265,7 +290,8 @@
 	le16_to_cpus(&hubstatus.wHubStatus);
 
 	dbg("local power source is %s",
-		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
+		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER)
+		? "lost (inactive)" : "good");
 
 	dbg("%sover-current condition exists",
 		(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
@@ -337,14 +363,15 @@
 	}
 
 	/* If it's not an interrupt endpoint, we'd better punt! */
-	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
-		err("Device #%d is hub class, but has endpoint other than interrupt?",
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			!= USB_ENDPOINT_XFER_INT) {
+		err("Device #%d is hub class, but endpoint is not interrupt?",
 			dev->devnum);
 		return NULL;
 	}
 
 	/* We found a hub */
-	info("USB hub found");
+	info("USB hub found at %s", dev->devpath);
 
 	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
 	if (!hub) {
@@ -367,7 +394,7 @@
 	if (usb_hub_configure(hub, endpoint) >= 0)
 		return hub;
 
-	err("hub configuration failed for device #%d", dev->devnum);
+	err("hub configuration failed for device at %s", dev->devpath);
 
 	/* free hub, but first clean up its list. */
 	spin_lock_irqsave(&hub_event_lock, flags);
@@ -436,7 +463,8 @@
 				if (hub->children[i] == NULL)
 					info->port[i] = 0;
 				else
-					info->port[i] = hub->children[i]->devnum;
+					info->port[i] =
+						hub->children[i]->devnum;
 			}
 		}
 		spin_unlock_irqrestore(&hub_event_lock, flags);
@@ -493,7 +521,7 @@
 		}
 	}
 
-	err("cannot disconnect hub %d", dev->devnum);
+	err("cannot disconnect hub %s", dev->devpath);
 }
 
 #define HUB_RESET_TRIES		5
@@ -510,14 +538,17 @@
 	struct usb_port_status portsts;
 	unsigned short portchange, portstatus;
 
-	for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) {
+	for (delay_time = 0;
+			delay_time < HUB_RESET_TIMEOUT;
+			delay_time += delay) {
 		/* wait to give the device a chance to reset */
 		wait_ms(delay);
 
 		/* read and decode port status */
 		ret = usb_get_port_status(hub, port + 1, &portsts);
 		if (ret < 0) {
-			err("get_port_status(%d) failed (err = %d)", port + 1, ret);
+			err("get_port_status(%d) failed (err = %d)",
+				port + 1, ret);
 			return -1;
 		}
 
@@ -546,8 +577,8 @@
 		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
 			delay = HUB_LONG_RESET_TIME;
 
-		dbg("port %d of hub %d not reset yet, waiting %dms", port + 1,
-			hub->devnum, delay);
+		dbg("port %d of hub %s not reset yet, waiting %dms", port + 1,
+			hub->devpath, delay);
 	}
 
 	return -1;
@@ -566,17 +597,18 @@
 		/* return on disconnect or reset */
 		status = usb_hub_port_wait_reset(hub, port, dev, delay);
 		if (status != -1) {
-			usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
+			usb_clear_port_feature(hub,
+				port + 1, USB_PORT_FEAT_C_RESET);
 			return status;
 		}
 
-		dbg("port %d of hub %d not enabled, trying reset again...",
-			port + 1, hub->devnum);
+		dbg("port %d of hub %s not enabled, trying reset again...",
+			port + 1, hub->devpath);
 		delay = HUB_LONG_RESET_TIME;
 	}
 
-	err("Cannot enable port %i of hub %d, disabling port.",
-		port + 1, hub->devnum);
+	err("Cannot enable port %i of hub %s, disabling port.",
+		port + 1, hub->devpath);
 	err("Maybe the USB cable is bad?");
 
 	return -1;
@@ -588,23 +620,24 @@
 
 	ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
 	if (ret)
-		err("cannot disable port %d of hub %d (err = %d)",
-			port + 1, hub->devnum, ret);
+		err("cannot disable port %d of hub %s (err = %d)",
+			port + 1, hub->devpath, ret);
 }
 
-static void usb_hub_port_connect_change(struct usb_device *hub, int port,
+static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
 					struct usb_port_status *portsts)
 {
+	struct usb_device *hub = hubstate->dev;
 	struct usb_device *dev;
 	unsigned short portstatus, portchange;
 	unsigned int delay = HUB_SHORT_RESET_TIME;
 	int i;
-	char *portstr, *tempstr;
 
 	portstatus = le16_to_cpu(portsts->wPortStatus);
 	portchange = le16_to_cpu(portsts->wPortChange);
-	dbg("port %d, portstatus %x, change %x, %s",
-		port + 1, portstatus, portchange, portspeed (portstatus));
+	dbg("hub %s port %d, portstatus %x, change %x, %s",
+		hub->devpath, port + 1,
+		portstatus, portchange, portspeed (portstatus));
 
 	/* Clear the connection change status */
 	usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
@@ -630,11 +663,9 @@
 
 	down(&usb_address0_sem);
 
-	tempstr = kmalloc(1024, GFP_KERNEL);
-	portstr = kmalloc(1024, GFP_KERNEL);
-
 	for (i = 0; i < HUB_PROBE_TRIES; i++) {
-		struct usb_device *pdev, *cdev;
+		struct usb_device *pdev;
+		int	len;
 
 		/* Allocate a new device struct */
 		dev = usb_alloc_dev(hub, hub->bus);
@@ -645,41 +676,46 @@
 
 		hub->children[port] = dev;
 
-		/* Reset the device */
+		/* Reset the device, and detect its speed */
 		if (usb_hub_port_reset(hub, port, dev, delay)) {
 			usb_free_dev(dev);
 			break;
 		}
 
-		/* Find a new device ID for it */
+		/* Find a new address for it */
 		usb_connect(dev);
 
-		/* Create a readable topology string */
-		cdev = dev;
-		pdev = dev->parent;
-		if (portstr && tempstr) {
-			portstr[0] = 0;
-			while (pdev) {
-				int port;
-
-				for (port = 0; port < pdev->maxchild; port++)
-					if (pdev->children[port] == cdev)
-						break;
-
-				strcpy(tempstr, portstr);
-				if (!strlen(tempstr))
-					sprintf(portstr, "%d", port + 1);
-				else
-					sprintf(portstr, "%d/%s", port + 1, tempstr);
+		/* Set up TT records, if needed  */
+		if (hub->tt) {
+			dev->tt = hub->tt;
+			dev->ttport = hub->ttport;
+		} else if (dev->speed != USB_SPEED_HIGH
+				&& hub->speed == USB_SPEED_HIGH) {
+			dev->tt = &hubstate->tt;
+			dev->ttport = port + 1;
+		}
 
-				cdev = pdev;
-				pdev = pdev->parent;
-			}
-			info("USB new device connect on bus%d/%s, assigned device number %d",
-				dev->bus->busnum, portstr, dev->devnum);
-		} else
-			info("USB new device connect on bus%d, assigned device number %d",
-				dev->bus->busnum, dev->devnum);
+		/* Save readable and stable topology id, distinguishing
+		 * devices by location for diagnostics, tools, etc.  The
+		 * string is a path along hub ports, from the root.  Each
+		 * device's id will be stable until USB is re-cabled, and
+		 * hubs are often labled with these port numbers.
+		 *
+		 * Initial size: "/NN" times five hubs + NUL = 16 bytes max
+		 * (quite rare, since most hubs have 4-6 ports).
+		 */
+		pdev = dev->parent;
+		if (pdev->devpath [1] != '\0')	/* parent not root */
+			len = snprintf (dev->devpath, sizeof dev->devpath,
+				"%s/%d", pdev->devpath, port + 1);
+		else	/* root == "/", root port 2 == "/2" */
+			len = snprintf (dev->devpath, sizeof dev->devpath,
+				"/%d", port + 1);
+		if (len == sizeof dev->devpath)
+			warn ("devpath size! usb/%03d/%03d path %s",
+				dev->bus->busnum, dev->devnum, dev->devpath);
+		info("new USB device on bus %d path %s, assigned address %d",
+			dev->bus->busnum, dev->devpath, dev->devnum);
 
 		/* Run it through the hoops (find a driver, etc) */
 		if (!usb_new_device(dev))
@@ -696,10 +732,6 @@
 	usb_hub_port_disable(hub, port);
 done:
 	up(&usb_address0_sem);
-	if (portstr)
-		kfree(portstr);
-	if (tempstr)
-		kfree(tempstr);
 }
 
 static void usb_hub_events(void)
@@ -737,10 +769,12 @@
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
-			dbg("resetting hub %d for error %d", dev->devnum, hub->error);
+			dbg("resetting hub %s for error %d",
+				dev->devpath, hub->error);
 
 			if (usb_hub_reset(hub)) {
-				err("error resetting hub %d - disconnecting", dev->devnum);
+				err("error resetting hub %s - disconnecting",
+					dev->devpath);
 				up(&hub->khubd_sem);
 				usb_hub_disconnect(dev);
 				continue;
@@ -756,7 +790,8 @@
 
 			ret = usb_get_port_status(dev, i + 1, &portsts);
 			if (ret < 0) {
-				err("get_port_status failed (err = %d)", ret);
+				err("hub %s get_port_status failed (err = %d)",
+					dev->devpath, ret);
 				continue;
 			}
 
@@ -764,55 +799,68 @@
 			portchange = le16_to_cpu(portsts.wPortChange);
 
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
-				dbg("port %d connection change", i + 1);
-
-				usb_hub_port_connect_change(dev, i, &portsts);
+				dbg("hub %s port %d connection change",
+					dev->devpath, i + 1);
+				usb_hub_port_connect_change(hub, i, &portsts);
 			} else if (portchange & USB_PORT_STAT_C_ENABLE) {
-				dbg("port %d enable change, status %x", i + 1, portstatus);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
+				dbg("hub %s port %d enable change, status %x",
+					dev->devpath, i + 1, portstatus);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_ENABLE);
 
 				/*
-				 * EM interference sometimes causes bad shielded USB devices to 
-				 * be shutdown by the hub, this hack enables them again.
+				 * EM interference sometimes causes badly
+				 * shielded USB devices to be shutdown by
+				 * the hub, this hack enables them again.
 				 * Works at least with mouse driver. 
 				 */
-				if (!(portstatus & USB_PORT_STAT_ENABLE) && 
-				    (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) {
-					err("already running port %i disabled by hub (EMI?), re-enabling...",
-						i + 1);
-					usb_hub_port_connect_change(dev, i, &portsts);
+				if (!(portstatus & USB_PORT_STAT_ENABLE)
+				    && (portstatus & USB_PORT_STAT_CONNECTION)
+				    && (dev->children[i])) {
+					err("already running hub %s port %i "
+					    "disabled by hub (EMI?), "
+					    "re-enabling...",
+						dev->devpath, i + 1);
+					usb_hub_port_connect_change(hub,
+						i, &portsts);
 				}
 			}
 
 			if (portchange & USB_PORT_STAT_C_SUSPEND) {
-				dbg("port %d suspend change", i + 1);
-				usb_clear_port_feature(dev, i + 1,  USB_PORT_FEAT_C_SUSPEND);
+				dbg("hub %s port %d suspend change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1,  USB_PORT_FEAT_C_SUSPEND);
 			}
 			
 			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
-				err("port %d over-current change", i + 1);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+				err("hub %s port %d over-current change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
 				usb_hub_power_on(hub);
 			}
 
 			if (portchange & USB_PORT_STAT_C_RESET) {
-				dbg("port %d reset change", i + 1);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
+				dbg("hub %s port %d reset change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_RESET);
 			}
 		} /* end for i */
 
 		/* deal with hub status changes */
 		if (usb_get_hub_status(dev, &hubsts) < 0)
-			err("get_hub_status failed");
+			err("get_hub_status %s failed", dev->devpath);
 		else {
 			hubstatus = le16_to_cpup(&hubsts.wHubStatus);
 			hubchange = le16_to_cpup(&hubsts.wHubChange);
 			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
-				dbg("hub power change");
+				dbg("hub %s power change", dev->devpath);
 				usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
-				dbg("hub overcurrent change");
+				dbg("hub %s overcurrent change", dev->devpath);
 				wait_ms(500);	/* Cool down */
 				usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
                         	usb_hub_power_on(hub);
@@ -851,6 +899,8 @@
 }
 
 static struct usb_device_id hub_id_table [] = {
+    { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS,
+      bDeviceClass: USB_CLASS_HUB},
     { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
       bInterfaceClass: USB_CLASS_HUB},
     { }						/* Terminating entry */
@@ -989,9 +1039,13 @@
 		ret = usb_get_device_descriptor(dev);
 		if (ret < sizeof(dev->descriptor)) {
 			if (ret < 0)
-				err("unable to get device descriptor (error=%d)", ret);
+				err("unable to get device %s descriptor "
+					"(error=%d)", dev->devpath, ret);
 			else
-				err("USB device descriptor short read (expected %Zi, got %i)", sizeof(dev->descriptor), ret);
+				err("USB device %s descriptor short read "
+					"(expected %Zi, got %i)",
+					dev->devpath,
+					sizeof(dev->descriptor), ret);
         
 			clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
 			dev->devnum = -1;
@@ -1015,17 +1069,22 @@
 
 	ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
 	if (ret < 0) {
-		err("failed to set active configuration (error=%d)", ret);
+		err("failed to set dev %s active configuration (error=%d)",
+			dev->devpath, ret);
 		return ret;
 	}
 
 	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
 		struct usb_interface *intf = &dev->actconfig->interface[i];
-		struct usb_interface_descriptor *as = &intf->altsetting[intf->act_altsetting];
+		struct usb_interface_descriptor *as;
 
-		ret = usb_set_interface(dev, as->bInterfaceNumber, as->bAlternateSetting);
+		as = &intf->altsetting[intf->act_altsetting];
+		ret = usb_set_interface(dev, as->bInterfaceNumber,
+			as->bAlternateSetting);
 		if (ret < 0) {
-			err("failed to set active alternate setting for interface %d (error=%d)", i, ret);
+			err("failed to set active alternate setting "
+				"for dev %s interface %d (error=%d)",
+				dev->devpath, i, ret);
 			return ret;
 		}
 	}
--- linux/drivers/usb-dist/usb.c	Tue Dec 18 14:30:30 2001
+++ linux/drivers/usb/usb.c	Tue Dec 18 17:07:31 2001
@@ -1013,6 +1013,8 @@
 
 	usb_bus_get(bus);
 
+	if (!parent)
+		dev->devpath [0] = '/';
 	dev->bus = bus;
 	dev->parent = parent;
 	atomic_set(&dev->refcnt, 1);
