From 3668d7cddd694a5deb60436ee0d528c54187b0b2 Mon Sep 17 00:00:00 2001
From: David Brownell <david-b@pacbell.net>
Date: Tue, 9 Apr 2002 00:16:42 -0700
Subject: [PATCH] [PATCH] USB physical paths id

This provides something that gets discussed regularly: stable
device IDs.  Straightforward; most of it was already present:

    - Moves "bus_name" out of HCD framework into usb_bus.
      This accounts for _by far the bulk_ of this patch, since
      every use of that original field needed to change.

    - Make Vojtech's usb_make_path() use bus_name instead
      of unstable bus numbers ... and usb_device->devpath
      instead of recomputing that same info.  Combine two
      stable IDs, and the result is still stable.  And since both
      are precomputed, usb_make_path() turns into only an
      error check wrapped around snprintf() ... so I inlined it.

    - Minor tweak to usb_device->devpath construction.  It
      still uses "/" for the root hub (better suggestions?) but
      Vojtech wanted "." for separators, so I changed that.

    - The older HCDs (uhci.c etc) initialize usb_bus.bus_name,
      as well as the sharable HCD framework

    - HCD framework no longer uses "bus" member.

These IDs are currently exposed in "input" hotplugging, and
my next patch addresses that for USB network devices.
---
 drivers/usb/core/hcd.c      | 39 +++++++++++++----------------
 drivers/usb/core/hcd.h      |  2 --
 drivers/usb/core/hub.c      | 16 ++++++------
 drivers/usb/core/usb.c      | 50 -------------------------------------
 drivers/usb/host/ehci-dbg.c |  2 +-
 drivers/usb/host/ehci-hcd.c | 21 ++++++++--------
 drivers/usb/host/ehci-hub.c |  8 +++---
 drivers/usb/host/ehci-q.c   |  2 +-
 drivers/usb/host/ohci-dbg.c |  6 ++---
 drivers/usb/host/ohci-hcd.c | 42 +++++++++++++++----------------
 drivers/usb/host/ohci-hub.c |  4 +--
 drivers/usb/host/uhci.c     |  1 +
 drivers/usb/host/usb-ohci.c |  1 +
 drivers/usb/host/usb-uhci.c |  1 +
 include/linux/usb.h         | 33 +++++++++++++++++++++++-
 15 files changed, 103 insertions(+), 125 deletions(-)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 110c76926d6e..8f2caebe87a3 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -310,7 +310,7 @@ static int rh_string (
 
 	// serial number
 	} else if (id == 1) {
-		strcpy (buf, hcd->bus_name);
+		strcpy (buf, hcd->self.bus_name);
 
 	// product description
 	} else if (id == 2) {
@@ -406,7 +406,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 	case DeviceOutRequest | USB_REQ_SET_ADDRESS:
 		// wValue == urb->dev->devaddr
 		dbg ("%s root hub device address %d",
-			hcd->bus_name, wValue);
+			hcd->self.bus_name, wValue);
 		break;
 
 	/* INTERFACE REQUESTS (no defined feature/status flags) */
@@ -520,7 +520,7 @@ static void rh_report_status (unsigned long ptr)
 					&& rh_status_urb (hcd, urb) != 0) {
 				/* another driver snuck in? */
 				dbg ("%s, can't resubmit roothub status urb?",
-					hcd->bus_name);
+					hcd->self.bus_name);
 				spin_unlock_irqrestore (&hcd_data_lock, flags);
 				BUG ();
 			}
@@ -1051,8 +1051,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
 	usb_init_bus (&hcd->self);
 	hcd->self.op = &hcd_operations;
 	hcd->self.hcpriv = (void *) hcd;
-	hcd->bus = &hcd->self;
-	hcd->bus_name = dev->slot_name;
+	hcd->self.bus_name = dev->slot_name;
 	hcd->product_desc = dev->name;
 
 	INIT_LIST_HEAD (&hcd->dev_list);
@@ -1089,16 +1088,15 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
 	hcd = pci_get_drvdata(dev);
 	if (!hcd)
 		return;
-	info ("remove: %s, state %x", hcd->bus_name, hcd->state);
+	info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
 
 	if (in_interrupt ()) BUG ();
 
-	hub = hcd->bus->root_hub;
+	hub = hcd->self.root_hub;
 	hcd->state = USB_STATE_QUIESCING;
 
-	dbg ("%s: roothub graceful disconnect", hcd->bus_name);
+	dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
 	usb_disconnect (&hub);
-	// usb_disconnect (&hcd->bus->root_hub);
 
 	hcd->driver->stop (hcd);
 	hcd->state = USB_STATE_HALT;
@@ -1113,10 +1111,9 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
 			pci_resource_len (dev, hcd->region));
 	}
 
-	usb_deregister_bus (hcd->bus);
+	usb_deregister_bus (&hcd->self);
 	if (atomic_read (&hcd->self.refcnt) != 1)
-		err ("usb_hcd_pci_remove %s, count != 1", hcd->bus_name);
-	hcd->bus = NULL;
+		err ("usb_hcd_pci_remove %s, count != 1", hcd->self.bus_name);
 
 	hcd->driver->hcd_free (hcd);
 }
@@ -1164,7 +1161,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	info ("suspend %s to state %d", hcd->bus_name, state);
+	info ("suspend %s to state %d", hcd->self.bus_name, state);
 
 	pci_save_state (dev, hcd->pci_state);
 
@@ -1193,12 +1190,12 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	info ("resume %s", hcd->bus_name);
+	info ("resume %s", hcd->self.bus_name);
 
 	/* guard against multiple resumes (APM bug?) */
 	atomic_inc (&hcd->resume_count);
 	if (atomic_read (&hcd->resume_count) != 1) {
-		err ("concurrent PCI resumes for %s", hcd->bus_name);
+		err ("concurrent PCI resumes for %s", hcd->self.bus_name);
 		retval = 0;
 		goto done;
 	}
@@ -1215,7 +1212,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
 
 	retval = hcd->driver->resume (hcd);
 	if (!HCD_IS_RUNNING (hcd->state)) {
-		dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
+		dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval);
 		hc_died (hcd);
 // FIXME:  recover, reset etc.
 	} else {
@@ -1290,7 +1287,7 @@ static void hc_died (struct usb_hcd *hcd)
 		list_for_each (urblist, &dev->urb_list) {
 			urb = list_entry (urblist, struct urb, urb_list);
 			dbg ("shutdown %s urb %p pipe %x, current status %d",
-				hcd->bus_name, urb, urb->pipe, urb->status);
+				hcd->self.bus_name, urb, urb->pipe, urb->status);
 			if (urb->status == -EINPROGRESS)
 				urb->status = -ESHUTDOWN;
 		}
@@ -1534,7 +1531,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
 	 * since we report some queuing/setup errors ourselves
 	 */
 	urb = usb_get_urb (urb);
-	if (urb->dev == hcd->bus->root_hub)
+	if (urb->dev == hcd->self.root_hub)
 		status = rh_urb_enqueue (hcd, urb);
 	else
 		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
@@ -1686,7 +1683,7 @@ if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
 			&& HCD_IS_RUNNING (hcd->state)
 			&& !retval) {
 		dbg ("%s: wait for giveback urb %p",
-			hcd->bus_name, urb);
+			hcd->self.bus_name, urb);
 		wait_for_completion (&splice.done);
 	} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
 		return -EINPROGRESS;
@@ -1698,7 +1695,7 @@ if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
 bye:
 	if (retval)
 		dbg ("%s: hcd_unlink_urb fail %d",
-		    hcd ? hcd->bus_name : "(no bus?)",
+		    hcd ? hcd->self.bus_name : "(no bus?)",
 		    retval);
 	return retval;
 }
@@ -1731,7 +1728,7 @@ static int hcd_free_dev (struct usb_device *udev)
 	/* device driver problem with refcounts? */
 	if (!list_empty (&dev->urb_list)) {
 		dbg ("free busy dev, %s devnum %d (bug!)",
-			hcd->bus_name, udev->devnum);
+			hcd->self.bus_name, udev->devnum);
 		return -EINVAL;
 	}
 
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 221145e0bbd9..30422107d18b 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -35,10 +35,8 @@ struct usb_hcd {	/* usb_bus.hcpriv points to this */
 	/*
 	 * housekeeping
 	 */
-	struct usb_bus		*bus;		/* FIXME only use "self" */
 	struct usb_bus		self;		/* hcd is-a bus */
 
-	const char		*bus_name;
 	const char		*product_desc;	/* product/vendor string */
 	const char		*description;	/* "ehci-hcd" etc */
 
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d77130aa0263..40291fcf2d7d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -765,23 +765,23 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
 		 * 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.
+		 * hubs are often labeled with these port numbers.
 		 *
-		 * Initial size: "/NN" times five hubs + NUL = 16 bytes max
+		 * 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 */
+		if (pdev->devpath [0] != '/')	/* parent not root */
 			len = snprintf (dev->devpath, sizeof dev->devpath,
-				"%s/%d", pdev->devpath, port + 1);
-		else	/* root == "/", root port 2 == "/2" */
+				"%s.%d", pdev->devpath, port + 1);
+		else	/* root == "/", root port 2 == "2", port 3 that hub "/2.3" */
 			len = snprintf (dev->devpath, sizeof dev->devpath,
-				"/%d", port + 1);
+				"%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);
+		info("new USB device %s-%s, assigned address %d",
+			dev->bus->bus_name, dev->devpath, dev->devnum);
 
 		/* put the device in the global device tree */
 		dev->dev.parent = &dev->parent->dev;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index ee0a5adb0b14..bb88b24e43ee 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -2407,56 +2407,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
 	return err;
 }
 
-/**
- * usb_make_path - returns device path in the hub tree
- * @dev: the device whose path is being constructed
- * @buf: where to put the string
- * @size: how big is "buf"?
- * Context: !in_interrupt ()
- *
- * Returns length of the string (>= 0) or out of memory status (< 0).
- *
- * NOTE:  prefer to use use dev->devpath directly.
- */
-int usb_make_path(struct usb_device *dev, char *buf, size_t size)
-{
-	struct usb_device *pdev = dev->parent;
-	char *tmp;
-	char *port;
-	int i;
-
-	if (!(port = kmalloc(size, GFP_KERNEL)))
-		return -ENOMEM;
-	if (!(tmp = kmalloc(size, GFP_KERNEL))) {
-		kfree(port);
-		return -ENOMEM;
-	}
-
-	*port = 0;
-	while (pdev) {
-		for (i = 0; i < pdev->maxchild; i++)
-			if (pdev->children[i] == dev)
-				break;
-
-		if (pdev->children[i] != dev) {
-			kfree(port);
-			kfree(tmp);
-			return -ENODEV;
-		}
-
-		strcpy(tmp, port);
-		snprintf(port, size, strlen(port) ? "%d.%s" : "%d", i + 1, tmp);
-
-		dev = pdev;
-		pdev = dev->parent;
-	}
-
-	snprintf(buf, size, "usb%d:%s", dev->bus->busnum, port);
-	kfree(port);
-	kfree(tmp);
-	return strlen(buf);
-}
-
 /*
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 442bbe39a3c9..06b570373d14 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -55,7 +55,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 			strcat(buf, tmp);
 		}
 		dbg ("%s: %s portroute %s", 
-			ehci->hcd.bus_name, label,
+			ehci->hcd.self.bus_name, label,
 			buf);
 	}
 }
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f7f9bf6a9022..eec9ef205937 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -248,7 +248,7 @@ static int ehci_start (struct usb_hcd *hcd)
 	ehci->tasklet.data = (unsigned long) ehci;
 
 	/* wire up the root hub */
-	hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus);
+	hcd->self.root_hub = udev = usb_alloc_dev (NULL, &hcd->self);
 	if (!udev) {
 done2:
 		ehci_mem_cleanup (ehci);
@@ -288,8 +288,7 @@ static int ehci_start (struct usb_hcd *hcd)
 		while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
 			udelay (100);
 		ehci_reset (ehci);
-		// usb_disconnect (udev); 
-		hcd->bus->root_hub = 0;
+		hcd->self.root_hub = 0;
 		usb_free_dev (udev); 
 		retval = -ENODEV;
 		goto done2;
@@ -304,7 +303,7 @@ static void ehci_stop (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 
-	dbg ("%s: stop", hcd->bus_name);
+	dbg ("%s: stop", hcd->self.bus_name);
 
 	if (hcd->state == USB_STATE_RUNNING)
 		ehci_ready (ehci);
@@ -339,7 +338,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
 	int			ports;
 	int			i;
 
-	dbg ("%s: suspend to %d", hcd->bus_name, state);
+	dbg ("%s: suspend to %d", hcd->self.bus_name, state);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -356,7 +355,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_OWNER) != 0)
 			continue;
-dbg ("%s: suspend port %d", hcd->bus_name, i);
+dbg ("%s: suspend port %d", hcd->self.bus_name, i);
 		temp |= PORT_SUSPEND;
 		writel (temp, &ehci->regs->port_status [i]);
 	}
@@ -380,7 +379,7 @@ static int ehci_resume (struct usb_hcd *hcd)
 	int			ports;
 	int			i;
 
-	dbg ("%s: resume", hcd->bus_name);
+	dbg ("%s: resume", hcd->self.bus_name);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -400,7 +399,7 @@ static int ehci_resume (struct usb_hcd *hcd)
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_SUSPEND) != 0)
 			continue;
-dbg ("%s: resume port %d", hcd->bus_name, i);
+dbg ("%s: resume port %d", hcd->self.bus_name, i);
 		temp |= PORT_RESUME;
 		writel (temp, &ehci->regs->port_status [i]);
 		readl (&ehci->regs->command);	/* unblock posted writes */
@@ -472,7 +471,7 @@ static void ehci_irq (struct usb_hcd *hcd)
 
 	/* PCI errors [4.15.2.4] */
 	if (unlikely ((status & STS_FATAL) != 0)) {
-		err ("%s: fatal error, state %x", hcd->bus_name, hcd->state);
+		err ("%s: fatal error, state %x", hcd->self.bus_name, hcd->state);
 		ehci_reset (ehci);
 		// generic layer kills/unlinks all urbs
 		// then tasklet cleans up the rest
@@ -547,7 +546,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 	unsigned long		flags;
 
 	dbg ("%s urb_dequeue %p qh state %d",
-		hcd->bus_name, urb, qh->qh_state);
+		hcd->self.bus_name, urb, qh->qh_state);
 
 	switch (usb_pipetype (urb->pipe)) {
 	case PIPE_CONTROL:
@@ -608,7 +607,7 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
 
 	/* ASSERT:  nobody can be submitting urbs for this any more */
 
-	dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum);
+	dbg ("%s: free_config devnum %d", hcd->self.bus_name, udev->devnum);
 
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < 32; i++) {
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 81343ece97c5..4b2b080663f8 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -41,14 +41,14 @@ static int check_reset_complete (
 	/* if reset finished and it's still not enabled -- handoff */
 	if (!(port_status & PORT_PE)) {
 		dbg ("%s port %d full speed, give to companion, 0x%x",
-			ehci->hcd.bus_name, index + 1, port_status);
+			ehci->hcd.self.bus_name, index + 1, port_status);
 
 		// what happens if HCS_N_CC(params) == 0 ?
 		port_status |= PORT_OWNER;
 		writel (port_status, &ehci->regs->port_status [index]);
 
 	} else
-		dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1);
+		dbg ("%s port %d high speed", ehci->hcd.self.bus_name, index + 1);
 
 	return port_status;
 }
@@ -306,11 +306,11 @@ static int ehci_hub_control (
 			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
 					&& PORT_USB11 (temp)) {
 				dbg ("%s port %d low speed, give to companion",
-					hcd->bus_name, wIndex + 1);
+					hcd->self.bus_name, wIndex + 1);
 				temp |= PORT_OWNER;
 			} else {
 				vdbg ("%s port %d reset",
-					hcd->bus_name, wIndex + 1);
+					hcd->self.bus_name, wIndex + 1);
 				temp |= PORT_RESET;
 				temp &= ~PORT_PE;
 
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index ba90524d0eaa..41f1f12d709a 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -733,7 +733,7 @@ submit_async (
 		epnum |= 0x10;
 
 	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
-		ehci->hcd.bus_name, urb, urb->transfer_buffer_length,
+		ehci->hcd.self.bus_name, urb, urb->transfer_buffer_length,
 		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
 		qtd, dev ? dev->ep [epnum] : (void *)~0);
 
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index cbc1a2dd0ad4..c3e795621907 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -89,7 +89,7 @@ void ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
 			continue;
 		printed = 1;
 		printk (KERN_DEBUG "%s, ohci %s frame %2d:",
-				label, ohci->hcd.bus_name, i);
+				label, ohci->hcd.self.bus_name, i);
 		while (*ed_p != 0 && j--) {
 			struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
 			printk (" %p/%08x;", ed, ed->hwINFO);
@@ -99,7 +99,7 @@ void ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
 	}
 	if (!printed)
 		printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n",
-				label, ohci->hcd.bus_name);
+				label, ohci->hcd.self.bus_name);
 }
 #endif
 
@@ -229,7 +229,7 @@ static void ohci_dump_roothub (struct ohci_hcd *controller, int verbose)
 
 static void ohci_dump (struct ohci_hcd *controller, int verbose)
 {
-	dbg ("OHCI controller %s state", controller->hcd.bus_name);
+	dbg ("OHCI controller %s state", controller->hcd.self.bus_name);
 
 	// dumps some of the state we know about
 	ohci_dump_status (controller);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 0f42039193f7..88a4b024da01 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -379,7 +379,7 @@ static int hc_reset (struct ohci_hcd *ohci)
 	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
 
 	dbg ("USB HC reset_hc %s: ctrl = 0x%x ;",
-		ohci->hcd.bus_name,
+		ohci->hcd.self.bus_name,
 		readl (&ohci->regs->control));
 
   	/* Reset USB (needed by some controllers) */
@@ -449,7 +449,7 @@ static int hc_start (struct ohci_hcd *ohci)
 	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
  
 	/* connect the virtual root hub */
-	ohci->hcd.bus->root_hub = udev = usb_alloc_dev (NULL, ohci->hcd.bus);
+	ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self);
 	ohci->hcd.state = USB_STATE_READY;
 	if (!udev) {
 	    ohci->disabled = 1;
@@ -491,7 +491,7 @@ static void ohci_irq (struct usb_hcd *hcd)
 
 	if (ints & OHCI_INTR_UE) {
 		ohci->disabled++;
-		err ("OHCI Unrecoverable Error, %s disabled", hcd->bus_name);
+		err ("OHCI Unrecoverable Error, %s disabled", hcd->self.bus_name);
 		// e.g. due to PCI Master/Target Abort
 
 #ifdef	DEBUG
@@ -530,7 +530,7 @@ static void ohci_stop (struct usb_hcd *hcd)
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
 	dbg ("%s: stop %s controller%s",
-		hcd->bus_name,
+		hcd->self.bus_name,
 		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
 		ohci->disabled ? " (disabled)" : ""
 		);
@@ -571,7 +571,7 @@ ohci_start (struct usb_hcd *hcd)
 				&& hcd->pdev->device == 0x740c) {
 			ohci->flags = OHCI_QUIRK_AMD756;
 			info ("%s: AMD756 erratum 4 workaround",
-				hcd->bus_name);
+				hcd->self.bus_name);
 		}
 
 		/* Apple's OHCI driver has a lot of bizarre workarounds
@@ -581,7 +581,7 @@ ohci_start (struct usb_hcd *hcd)
 		else if (hcd->pdev->vendor == 0x1045
 				&& hcd->pdev->device == 0xc861) {
 			info ("%s: WARNING: OPTi workarounds unavailable",
-				hcd->bus_name);
+				hcd->self.bus_name);
 		}
 	}
 #else
@@ -601,7 +601,7 @@ ohci_start (struct usb_hcd *hcd)
 	}
 
 	if (hc_start (ohci) < 0) {
-		err ("can't start %s", ohci->hcd.bus_name);
+		err ("can't start %s", ohci->hcd.self.bus_name);
 		ohci_stop (hcd);
 		return -EBUSY;
 	}
@@ -623,13 +623,13 @@ static int ohci_suspend (struct usb_hcd *hcd, u32 state)
 	u16			cmd;
 
 	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
-		dbg ("can't suspend %s (state is %s)", hcd->bus_name,
+		dbg ("can't suspend %s (state is %s)", hcd->self.bus_name,
 			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
 		return -EIO;
 	}
 
 	/* act as if usb suspend can always be used */
-	dbg ("%s: suspend to %d", hcd->bus_name, state);
+	dbg ("%s: suspend to %d", hcd->self.bus_name, state);
 	ohci->sleeping = 1;
 
 	/* First stop processing */
@@ -664,16 +664,16 @@ static int ohci_suspend (struct usb_hcd *hcd, u32 state)
 
 	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
 		case OHCI_USB_RESET:
-			dbg ("%s suspend->reset ?", hcd->bus_name);
+			dbg ("%s suspend->reset ?", hcd->self.bus_name);
 			break;
 		case OHCI_USB_RESUME:
-			dbg ("%s suspend->resume ?", hcd->bus_name);
+			dbg ("%s suspend->resume ?", hcd->self.bus_name);
 			break;
 		case OHCI_USB_OPER:
-			dbg ("%s suspend->operational ?", hcd->bus_name);
+			dbg ("%s suspend->operational ?", hcd->self.bus_name);
 			break;
 		case OHCI_USB_SUSPEND:
-			dbg ("%s suspended", hcd->bus_name);
+			dbg ("%s suspended", hcd->self.bus_name);
 			break;
 	}
 
@@ -711,8 +711,8 @@ static int hc_restart (struct ohci_hcd *ohci)
 
 	ohci->disabled = 1;
 	ohci->sleeping = 0;
-	if (ohci->hcd.bus->root_hub)
-		usb_disconnect (&ohci->hcd.bus->root_hub);
+	if (ohci->hcd.self.root_hub)
+		usb_disconnect (&ohci->hcd.self.root_hub);
 	
 	/* empty the interrupt branches */
 	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load [i] = 0;
@@ -728,10 +728,10 @@ static int hc_restart (struct ohci_hcd *ohci)
 	ohci->ed_bulktail    = NULL;
 
 	if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
-		err ("can't restart %s, %d", ohci->hcd.bus_name, temp);
+		err ("can't restart %s, %d", ohci->hcd.self.bus_name, temp);
 		return temp;
 	} else
-		dbg ("restart %s completed", ohci->hcd.bus_name);
+		dbg ("restart %s completed", ohci->hcd.self.bus_name);
 	return 0;
 }
 
@@ -767,13 +767,13 @@ static int ohci_resume (struct usb_hcd *hcd)
 	switch (temp) {
 
 	case OHCI_USB_RESET:	// lost power
-		info ("USB restart: %s", hcd->bus_name);
+		info ("USB restart: %s", hcd->self.bus_name);
 		retval = hc_restart (ohci);
 		break;
 
 	case OHCI_USB_SUSPEND:	// host wakeup
 	case OHCI_USB_RESUME:	// remote wakeup
-		info ("USB continue: %s from %s wakeup", hcd->bus_name,
+		info ("USB continue: %s from %s wakeup", hcd->self.bus_name,
 			 (temp == OHCI_USB_SUSPEND)
 				? "host" : "remote");
 		ohci->hc_control = OHCI_USB_RESUME;
@@ -786,7 +786,7 @@ static int ohci_resume (struct usb_hcd *hcd)
 		temp = readl (&ohci->regs->control);
 		temp = ohci->hc_control & OHCI_CTRL_HCFS;
 		if (temp != OHCI_USB_RESUME) {
-			err ("controller %s won't resume", hcd->bus_name);
+			err ("controller %s won't resume", hcd->self.bus_name);
 			ohci->disabled = 1;
 			retval = -EIO;
 			break;
@@ -836,7 +836,7 @@ dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
 		break;
 
 	default:
-		warn ("odd PCI resume for %s", hcd->bus_name);
+		warn ("odd PCI resume for %s", hcd->self.bus_name);
 	}
 	return retval;
 }
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index ab6e751557fc..2aed53548bb5 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -41,7 +41,7 @@ static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
 #define dbg_port(hc,label,num,value) \
 	dbg ("%s: %s roothub.portstatus [%d] " \
 		"= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s", \
-		hc->hcd.bus_name, label, num, temp, \
+		hc->hcd.self.bus_name, label, num, temp, \
 		(temp & RH_PS_PRSC) ? " PRSC" : "", \
 		(temp & RH_PS_OCIC) ? " OCIC" : "", \
 		(temp & RH_PS_PSSC) ? " PSSC" : "", \
@@ -71,7 +71,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 
 	ports = roothub_a (ohci) & RH_A_NDP; 
 	if (ports > MAX_ROOT_PORTS) {
-		err ("%s: bogus NDP=%d", hcd->bus_name, ports);
+		err ("%s: bogus NDP=%d", hcd->self.bus_name, ports);
 		err ("rereads as NDP=%d",
 			readl (&ohci->regs->roothub.a) & RH_A_NDP);
 		/* retry later; "should not happen" */
diff --git a/drivers/usb/host/uhci.c b/drivers/usb/host/uhci.c
index 68c3e99043fd..7954f30e6c2f 100644
--- a/drivers/usb/host/uhci.c
+++ b/drivers/usb/host/uhci.c
@@ -2799,6 +2799,7 @@ static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io
 
 	uhci->bus = bus;
 	bus->hcpriv = uhci;
+	bus->bus_name = dev->slot_name;
 
 	usb_register_bus(uhci->bus);
 
diff --git a/drivers/usb/host/usb-ohci.c b/drivers/usb/host/usb-ohci.c
index 9baf1b62b985..433eaabbcd22 100644
--- a/drivers/usb/host/usb-ohci.c
+++ b/drivers/usb/host/usb-ohci.c
@@ -2400,6 +2400,7 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
 		return NULL;
 	}
 	ohci->bus->hcpriv = (void *) ohci;
+	ohci->bus->bus_name = dev->slot_name;
 
 	return ohci;
 } 
diff --git a/drivers/usb/host/usb-uhci.c b/drivers/usb/host/usb-uhci.c
index 23d148434719..55fea63c1715 100644
--- a/drivers/usb/host/usb-uhci.c
+++ b/drivers/usb/host/usb-uhci.c
@@ -2977,6 +2977,7 @@ _static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_
 
 	s->bus = bus;
 	bus->hcpriv = s;
+	bus->bus_name = dev->slot_name;
 
 	/* UHCI specs says devices must have 2 ports, but goes on to say */
 	/* they may have more but give no way to determine how many they */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 9849c917c9ac..f06fafb62ee1 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -890,7 +890,6 @@ extern int usb_string(struct usb_device *dev, int index,
 	char *buf, size_t size);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
-extern int usb_make_path(struct usb_device *dev, char *buf, size_t size);
 
 /*
  * timeouts, in seconds, used for sending/receiving control messages
@@ -917,6 +916,7 @@ struct usb_operations;
  */
 struct usb_bus {
 	int busnum;			/* Bus number (in order of reg) */
+	char *bus_name;			/* stable id (PCI slot_name etc) */
 
 #ifdef DEVNUM_ROUND_ROBIN
 	int devnum_next;                /* Next open device number in round-robin allocation */
@@ -1087,6 +1087,37 @@ const struct usb_device_id *usb_match_id(struct usb_device *dev,
 					 struct usb_interface *interface,
 					 const struct usb_device_id *id);
 
+/**
+ * usb_make_path - returns stable device path in the usb tree
+ * @dev: the device whose path is being constructed
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ *
+ * Returns length of the string (> 0) or negative if size was too small.
+ *
+ * This identifier is intended to be "stable", reflecting physical paths in
+ * hardware such as physical bus addresses for host controllers or ports on
+ * USB hubs.  That makes it stay the same until systems are physically
+ * reconfigured, by re-cabling a tree of USB devices or by moving USB host
+ * controllers.  Adding and removing devices, including virtual root hubs
+ * in host controller driver modules, does not change these path identifers;
+ * neither does rebooting or re-enumerating.  These are more useful identifiers
+ * than changeable ("unstable") ones like bus numbers or device addresses.
+ * 
+ * With a partial exception for devices connected to USB 2.0 root hubs, these
+ * identifiers are also predictable:  so long as the device tree isn't changed,
+ * plugging any USB device into a given hub port always gives it the same path.
+ * Because of the use of "companion" controllers, devices connected to ports on
+ * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
+ * high speed, and a different one if they are full or low speed.
+ */
+static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)
+{
+	int actual;
+	actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath);
+	return (actual >= size) ? -1 : actual;
+}
+
 /* -------------------------------------------------------------------------- */
 
 /*
-- 
2.30.9