Commit bc7e061c authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[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.
parent fb0dfb43
...@@ -738,7 +738,7 @@ EXPORT_SYMBOL (usb_deregister_bus); ...@@ -738,7 +738,7 @@ EXPORT_SYMBOL (usb_deregister_bus);
* *
* The USB host controller calls this function to register the root hub * The USB host controller calls this function to register the root hub
* properly with the USB subsystem. It sets up the device properly in * 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). * 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) int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)
...@@ -746,14 +746,14 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev ...@@ -746,14 +746,14 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
const int devnum = 1; const int devnum = 1;
int retval; 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->devnum = devnum;
usb_dev->bus->devnum_next = devnum + 1; 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); 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) if (retval)
dev_err (parent_dev, "can't register root hub for %s, %d\n", dev_err (parent_dev, "can't register root hub for %s, %d\n",
usb_dev->dev.bus_id, retval); usb_dev->dev.bus_id, retval);
......
...@@ -241,7 +241,9 @@ extern void usb_hc_died (struct usb_hcd *hcd); ...@@ -241,7 +241,9 @@ extern void usb_hc_died (struct usb_hcd *hcd);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Enumeration is only for the hub driver, or HCD virtual root hubs */ /* 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_choose_address(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **); extern void usb_disconnect(struct usb_device **);
......
...@@ -930,11 +930,9 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -930,11 +930,9 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
down(&usb_address0_sem); down(&usb_address0_sem);
for (i = 0; i < HUB_PROBE_TRIES; i++) { for (i = 0; i < HUB_PROBE_TRIES; i++) {
struct usb_device *pdev;
int len;
/* Allocate a new device struct */ /* Allocate a new device struct */
dev = usb_alloc_dev(hub, hub->bus); dev = usb_alloc_dev(hub, hub->bus, port);
if (!dev) { if (!dev) {
dev_err (&hubstate->intf->dev, dev_err (&hubstate->intf->dev,
"couldn't allocate usb_device\n"); "couldn't allocate usb_device\n");
...@@ -962,38 +960,18 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -962,38 +960,18 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
dev->ttport = port + 1; dev->ttport = port + 1;
} }
/* Save readable and stable topology id, distinguishing dev_info (&dev->dev,
* devices by location for diagnostics, tools, etc. The "new %s speed USB device using address %d\n",
* string is a path along hub ports, from the root. Each ({ char *speed; switch (dev->speed) {
* device's id will be stable until USB is re-cabled, and case USB_SPEED_LOW: speed = "low"; break;
* hubs are often labeled with these port numbers. case USB_SPEED_FULL: speed = "full"; break;
* case USB_SPEED_HIGH: speed = "high"; break;
* Initial size: ".NN" times five hubs + NUL = 16 bytes max default: speed = "?"; break;
* (quite rare, since most hubs have 4-6 ports). }; speed;}),
*/ dev->devnum);
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;
/* Run it through the hoops (find a driver, etc) */ /* 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; hub->children[port] = dev;
goto done; goto done;
} }
......
...@@ -678,17 +678,19 @@ static void usb_release_dev(struct device *dev) ...@@ -678,17 +678,19 @@ static void usb_release_dev(struct device *dev)
} }
/** /**
* usb_alloc_dev - allocate a usb device structure (usbcore-internal) * usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected * @parent: hub to which device is connected; null to allocate a root hub
* @bus: bus used to access the device * @bus: bus used to access the device
* @port: zero based index of port; ignored for root hubs
* Context: !in_interrupt () * Context: !in_interrupt ()
* *
* Only hub drivers (including virtual root hub drivers for host * Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this. * 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; struct usb_device *dev;
...@@ -705,11 +707,42 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus) ...@@ -705,11 +707,42 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
} }
device_initialize(&dev->dev); 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->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED; 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->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->bus = bus;
dev->parent = parent; dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist); INIT_LIST_HEAD(&dev->filelist);
...@@ -1011,33 +1044,13 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index) ...@@ -1011,33 +1044,13 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index)
*/ */
#define NEW_DEVICE_RETRYS 2 #define NEW_DEVICE_RETRYS 2
#define SET_ADDRESS_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 err = -EINVAL;
int i; int i;
int j; int j;
int config; 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 ... /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices. * it's fixed size except for full speed devices.
*/ */
......
...@@ -473,7 +473,7 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -473,7 +473,7 @@ static int ehci_start (struct usb_hcd *hcd)
/* wire up the root hub */ /* wire up the root hub */
bus = hcd_to_bus (hcd); 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) { if (!udev) {
done2: done2:
ehci_mem_cleanup (ehci); ehci_mem_cleanup (ehci);
......
...@@ -559,7 +559,7 @@ static int rh_connect_rh (hci_t * hci) ...@@ -559,7 +559,7 @@ static int rh_connect_rh (hci_t * hci)
struct usb_device *usb_dev; struct usb_device *usb_dev;
hci->rh.devnum = 0; hci->rh.devnum = 0;
usb_dev = usb_alloc_dev (NULL, hci->bus); usb_dev = usb_alloc_dev (NULL, hci->bus, 0);
if (!usb_dev) if (!usb_dev)
return -ENOMEM; return -ENOMEM;
......
...@@ -536,7 +536,7 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -536,7 +536,7 @@ static int hc_start (struct ohci_hcd *ohci)
/* connect the virtual root hub */ /* connect the virtual root hub */
bus = hcd_to_bus (&ohci->hcd); 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; ohci->hcd.state = USB_STATE_RUNNING;
if (!udev) { if (!udev) {
disable (ohci); disable (ohci);
......
...@@ -2315,7 +2315,7 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2315,7 +2315,7 @@ static int uhci_start(struct usb_hcd *hcd)
uhci->rh_numports = port; 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) { if (!udev) {
err("unable to allocate root hub"); err("unable to allocate root hub");
goto err_alloc_root_hub; goto err_alloc_root_hub;
......
...@@ -274,7 +274,6 @@ struct usb_device { ...@@ -274,7 +274,6 @@ struct usb_device {
}; };
#define to_usb_device(d) container_of(d, struct usb_device, dev) #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 struct usb_device *usb_get_dev(struct usb_device *dev);
extern void usb_put_dev(struct usb_device *dev); extern void usb_put_dev(struct usb_device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment