From bc7e061c860f4bb766c3b013c4c554cb01d87290 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 8 Feb 2004 20:16:07 -0800 Subject: [PATCH] [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 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 --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 8ee641df6b9cd..e76cb4c1cf4d0 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -738,7 +738,7 @@ EXPORT_SYMBOL (usb_deregister_bus); * * 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 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev 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 --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 1d0ea74d01483..725a92f29092f 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -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 */ -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 --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6c2976d245625..e9db8522acd7e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -930,11 +930,9 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, 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 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, 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 --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 378d51ce23743..07ddb791beed2 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -678,17 +678,19 @@ static void usb_release_dev(struct device *dev) } /** - * 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 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus) } 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,33 +1044,13 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index) */ #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 --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5c58a16c7693f..0db191fb8ea03 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -473,7 +473,7 @@ static int ehci_start (struct usb_hcd *hcd) /* 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 --git a/drivers/usb/host/hc_sl811_rh.c b/drivers/usb/host/hc_sl811_rh.c index 42ec077b72bff..a4dd4628ed669 100644 --- a/drivers/usb/host/hc_sl811_rh.c +++ b/drivers/usb/host/hc_sl811_rh.c @@ -559,7 +559,7 @@ static int rh_connect_rh (hci_t * hci) 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 --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index cc2c9c259197b..53c86a42d4bae 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -536,7 +536,7 @@ static int hc_start (struct ohci_hcd *ohci) /* 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 --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 652f85120d759..0678fdf8d7b1a 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -2315,7 +2315,7 @@ static int uhci_start(struct usb_hcd *hcd) 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 --git a/include/linux/usb.h b/include/linux/usb.h index c16b0125baa0a..45caca344ca32 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -274,7 +274,6 @@ struct usb_device { }; #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); -- 2.53.0