ChangeSet 1.1500.2.173, 2004/02/09 12:16:07-08:00, david-b@pacbell.net

[PATCH] USB: re-factor enumeration/reset paths

This patch starts dis-entangling some of the enumeration logic by
moving initialization code into the usb_alloc_dev() constructor.
Some call signatures changed; a usbcore-internal declaration was
moved in <linux/usb.h> to a more appropriate location.

With the driver model init now more centralized, it's safer to
use driver model calls (including dev_info) a lot earlier, so
the "new device at address N" message now does that.  It also
reports the device speed, which may not be evident otherwise.


 drivers/usb/core/hcd.c         |   10 +++---
 drivers/usb/core/hcd.h         |    4 +-
 drivers/usb/core/hub.c         |   44 ++++++---------------------
 drivers/usb/core/usb.c         |   65 ++++++++++++++++++++++++-----------------
 drivers/usb/host/ehci-hcd.c    |    2 -
 drivers/usb/host/hc_sl811_rh.c |    2 -
 drivers/usb/host/ohci-hcd.c    |    2 -
 drivers/usb/host/uhci-hcd.c    |    2 -
 include/linux/usb.h            |    1 
 9 files changed, 62 insertions(+), 70 deletions(-)


diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Mon Feb  9 14:36:43 2004
+++ b/drivers/usb/core/hcd.c	Mon Feb  9 14:36:43 2004
@@ -738,7 +738,7 @@
  *
  * The USB host controller calls this function to register the root hub
  * properly with the USB subsystem.  It sets up the device properly in
- * the driverfs tree, and then calls usb_new_device() to register the
+ * the device model tree, and then calls usb_new_device() to register the
  * usb device.  It also assigns the root hub's USB address (always 1).
  */
 int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)
@@ -746,14 +746,14 @@
 	const int devnum = 1;
 	int retval;
 
-	sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum);
-	usb_dev->state = USB_STATE_DEFAULT;
-
 	usb_dev->devnum = devnum;
 	usb_dev->bus->devnum_next = devnum + 1;
+	memset (&usb_dev->bus->devmap.devicemap, 0,
+			sizeof usb_dev->bus->devmap.devicemap);
 	set_bit (devnum, usb_dev->bus->devmap.devicemap);
+	usb_dev->state = USB_STATE_ADDRESS;
 
-	retval = usb_new_device (usb_dev, parent_dev);
+	retval = usb_new_device (usb_dev);
 	if (retval)
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
 				usb_dev->dev.bus_id, retval);
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h	Mon Feb  9 14:36:43 2004
+++ b/drivers/usb/core/hcd.h	Mon Feb  9 14:36:43 2004
@@ -241,7 +241,9 @@
 /* -------------------------------------------------------------------------- */
 
 /* Enumeration is only for the hub driver, or HCD virtual root hubs */
-extern int usb_new_device(struct usb_device *dev, struct device *parent);
+extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
+					struct usb_bus *, unsigned port);
+extern int usb_new_device(struct usb_device *dev);
 extern void usb_choose_address(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
 
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Mon Feb  9 14:36:43 2004
+++ b/drivers/usb/core/hub.c	Mon Feb  9 14:36:43 2004
@@ -930,11 +930,9 @@
 	down(&usb_address0_sem);
 
 	for (i = 0; i < HUB_PROBE_TRIES; i++) {
-		struct usb_device *pdev;
-		int	len;
 
 		/* Allocate a new device struct */
-		dev = usb_alloc_dev(hub, hub->bus);
+		dev = usb_alloc_dev(hub, hub->bus, port);
 		if (!dev) {
 			dev_err (&hubstate->intf->dev,
 				"couldn't allocate usb_device\n");
@@ -962,38 +960,18 @@
 			dev->ttport = port + 1;
 		}
 
-		/* 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 labeled 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 [0] != '0')	/* parent not root? */
-			len = snprintf (dev->devpath, sizeof dev->devpath,
-				"%s.%d", pdev->devpath, port + 1);
-		/* root == "0", root port 2 == "2", port 3 that hub "2.3" */
-		else
-			len = snprintf (dev->devpath, sizeof dev->devpath,
-				"%d", port + 1);
-		if (len == sizeof dev->devpath)
-			dev_err (&hubstate->intf->dev,
-				"devpath size! usb/%03d/%03d path %s\n",
-				dev->bus->busnum, dev->devnum, dev->devpath);
-		dev_info (&hubstate->intf->dev,
-			"new USB device on port %d, assigned address %d\n",
-			port + 1, dev->devnum);
-
-		/* put the device in the global device tree. the hub port
-		 * is the "bus_id"; hubs show in hierarchy like bridges
-		 */
-		dev->dev.parent = dev->parent->dev.parent->parent;
+		dev_info (&dev->dev,
+			"new %s speed USB device using address %d\n",
+			({ char *speed; switch (dev->speed) {
+			case USB_SPEED_LOW:	speed = "low";	break;
+			case USB_SPEED_FULL:	speed = "full";	break;
+			case USB_SPEED_HIGH:	speed = "high";	break;
+			default: 		speed = "?";	break;
+			}; speed;}),
+			dev->devnum);
 
 		/* Run it through the hoops (find a driver, etc) */
-		if (!usb_new_device(dev, &hub->dev)) {
+		if (usb_new_device(dev) == 0) {
 			hub->children[port] = dev;
 			goto done;
 		}
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Mon Feb  9 14:36:43 2004
+++ b/drivers/usb/core/usb.c	Mon Feb  9 14:36:43 2004
@@ -678,17 +678,19 @@
 }
 
 /**
- * usb_alloc_dev - allocate a usb device structure (usbcore-internal)
- * @parent: hub to which device is connected
+ * usb_alloc_dev - usb device constructor (usbcore-internal)
+ * @parent: hub to which device is connected; null to allocate a root hub
  * @bus: bus used to access the device
+ * @port: zero based index of port; ignored for root hubs
  * Context: !in_interrupt ()
  *
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
  *
- * This call is synchronous, and may not be used in an interrupt context.
+ * This call may not be used in a non-sleeping context.
  */
-struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
+struct usb_device *
+usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port)
 {
 	struct usb_device *dev;
 
@@ -705,11 +707,42 @@
 	}
 
 	device_initialize(&dev->dev);
+	dev->dev.bus = &usb_bus_type;
+	dev->dev.dma_mask = bus->controller->dma_mask;
+	dev->dev.driver_data = &usb_generic_driver_data;
+	dev->dev.driver = &usb_generic_driver;
 	dev->dev.release = usb_release_dev;
 	dev->state = USB_STATE_ATTACHED;
 
-	if (!parent)
+	/* Save readable and stable topology id, distinguishing devices
+	 * by location for diagnostics, tools, driver model, etc.  The
+	 * string is a path along hub ports, from the root.  Each device's
+	 * dev->devpath will be stable until USB is re-cabled, and hubs
+	 * are often labeled with these port numbers.  The bus_id isn't
+	 * as stable:  bus->busnum changes easily from modprobe order,
+	 * cardbus or pci hotplugging, and so on.
+	 */
+	if (unlikely (!parent)) {
 		dev->devpath [0] = '0';
+
+		dev->dev.parent = bus->controller;
+		sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+	} else {
+		/* match any labeling on the hubs; it's one-based */
+		if (parent->devpath [0] == '0')
+			snprintf (dev->devpath, sizeof dev->devpath,
+				"%d", port + 1);
+		else
+			snprintf (dev->devpath, sizeof dev->devpath,
+				"%s.%d", parent->devpath, port + 1);
+
+		dev->dev.parent = &parent->dev;
+		sprintf (&dev->dev.bus_id[0], "%d-%s",
+			bus->busnum, dev->devpath);
+
+		/* hub driver sets up TT records */
+	}
+
 	dev->bus = bus;
 	dev->parent = parent;
 	INIT_LIST_HEAD(&dev->filelist);
@@ -1011,32 +1044,12 @@
  */
 #define NEW_DEVICE_RETRYS	2
 #define SET_ADDRESS_RETRYS	2
-int usb_new_device(struct usb_device *dev, struct device *parent)
+int usb_new_device(struct usb_device *dev)
 {
 	int err = -EINVAL;
 	int i;
 	int j;
 	int config;
-
-	/*
-	 * Set the driver for the usb device to point to the "generic" driver.
-	 * This prevents the main usb device from being sent to the usb bus
-	 * probe function.  Yes, it's a hack, but a nice one :)
-	 *
-	 * Do it asap, so more driver model stuff (like the device.h message
-	 * utilities) can be used in hcd submit/unlink code paths.
-	 */
-	usb_generic_driver.bus = &usb_bus_type;
-	dev->dev.parent = parent;
-	dev->dev.driver = &usb_generic_driver;
-	dev->dev.bus = &usb_bus_type;
-	dev->dev.driver_data = &usb_generic_driver_data;
-	if (dev->dev.bus_id[0] == 0)
-		sprintf (&dev->dev.bus_id[0], "%d-%s",
-			 dev->bus->busnum, dev->devpath);
-
-	/* dma masks come from the controller; readonly, except to hcd */
-	dev->dev.dma_mask = parent->dma_mask;
 
 	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 	 * it's fixed size except for full speed devices.
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Mon Feb  9 14:36:43 2004
+++ b/drivers/usb/host/ehci-hcd.c	Mon Feb  9 14:36:43 2004
@@ -473,7 +473,7 @@
 
 	/* wire up the root hub */
 	bus = hcd_to_bus (hcd);
-	bus->root_hub = udev = usb_alloc_dev (NULL, bus);
+	bus->root_hub = udev = usb_alloc_dev (NULL, bus, 0);
 	if (!udev) {
 done2:
 		ehci_mem_cleanup (ehci);
diff -Nru a/drivers/usb/host/hc_sl811_rh.c b/drivers/usb/host/hc_sl811_rh.c
--- a/drivers/usb/host/hc_sl811_rh.c	Mon Feb  9 14:36:43 2004
+++ b/drivers/usb/host/hc_sl811_rh.c	Mon Feb  9 14:36:43 2004
@@ -559,7 +559,7 @@
 	struct usb_device *usb_dev;
 
 	hci->rh.devnum = 0;
-	usb_dev = usb_alloc_dev (NULL, hci->bus);
+	usb_dev = usb_alloc_dev (NULL, hci->bus, 0);
 	if (!usb_dev)
 		return -ENOMEM;
 
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Mon Feb  9 14:36:43 2004
+++ b/drivers/usb/host/ohci-hcd.c	Mon Feb  9 14:36:43 2004
@@ -536,7 +536,7 @@
  
 	/* connect the virtual root hub */
 	bus = hcd_to_bus (&ohci->hcd);
-	bus->root_hub = udev = usb_alloc_dev (NULL, bus);
+	bus->root_hub = udev = usb_alloc_dev (NULL, bus, 0);
 	ohci->hcd.state = USB_STATE_RUNNING;
 	if (!udev) {
 		disable (ohci);
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Mon Feb  9 14:36:43 2004
+++ b/drivers/usb/host/uhci-hcd.c	Mon Feb  9 14:36:43 2004
@@ -2315,7 +2315,7 @@
 
 	uhci->rh_numports = port;
 
-	hcd->self.root_hub = udev = usb_alloc_dev(NULL, &hcd->self);
+	hcd->self.root_hub = udev = usb_alloc_dev(NULL, &hcd->self, 0);
 	if (!udev) {
 		err("unable to allocate root hub");
 		goto err_alloc_root_hub;
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Mon Feb  9 14:36:43 2004
+++ b/include/linux/usb.h	Mon Feb  9 14:36:43 2004
@@ -274,7 +274,6 @@
 };
 #define	to_usb_device(d) container_of(d, struct usb_device, dev)
 
-extern struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *);
 extern struct usb_device *usb_get_dev(struct usb_device *dev);
 extern void usb_put_dev(struct usb_device *dev);
 
