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

[PATCH] USB: usbcore sets up root hubs earlier

Make the HCD initialization sequence more sane ... notably, setting up
root hubs before HCDs are asked to do their one-time init.  Among other
things, that lets the HCDs do custom root hub init along with all the
other one-time initialization done in the (now misnamed) reset() method.

This also copies the controller wakeup flags into the root hub; it's
done a bit later than would be ideal, but that'll be necessary until
the PCI code initializes them correctly.  (The PCI patch breaks on PPC
due to how it sequences PCI initialization.)
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 1c05ad44
...@@ -823,18 +823,17 @@ static void usb_deregister_bus (struct usb_bus *bus) ...@@ -823,18 +823,17 @@ static void usb_deregister_bus (struct usb_bus *bus)
/** /**
* register_root_hub - called by usb_add_hcd() to register a root hub * register_root_hub - called by usb_add_hcd() to register a root hub
* @usb_dev: the usb root hub device to be registered.
* @hcd: host controller for this root hub * @hcd: host controller for this root hub
* *
* This function registers the root hub with the USB subsystem. It sets up * This function registers the root hub with the USB subsystem. It sets up
* the device properly in the device tree and stores the root_hub pointer * the device properly in the device tree and then calls usb_new_device()
* in the bus structure, then calls usb_new_device() to register the usb * to register the usb device. It also assigns the root hub's USB address
* device. It also assigns the root hub's USB address (always 1). * (always 1).
*/ */
static int register_root_hub (struct usb_device *usb_dev, static int register_root_hub(struct usb_hcd *hcd)
struct usb_hcd *hcd)
{ {
struct device *parent_dev = hcd->self.controller; struct device *parent_dev = hcd->self.controller;
struct usb_device *usb_dev = hcd->self.root_hub;
const int devnum = 1; const int devnum = 1;
int retval; int retval;
...@@ -846,12 +845,10 @@ static int register_root_hub (struct usb_device *usb_dev, ...@@ -846,12 +845,10 @@ static int register_root_hub (struct usb_device *usb_dev,
usb_set_device_state(usb_dev, USB_STATE_ADDRESS); usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
mutex_lock(&usb_bus_list_lock); mutex_lock(&usb_bus_list_lock);
usb_dev->bus->root_hub = usb_dev;
usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
if (retval != sizeof usb_dev->descriptor) { if (retval != sizeof usb_dev->descriptor) {
usb_dev->bus->root_hub = NULL;
mutex_unlock(&usb_bus_list_lock); mutex_unlock(&usb_bus_list_lock);
dev_dbg (parent_dev, "can't read %s device descriptor %d\n", dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
usb_dev->dev.bus_id, retval); usb_dev->dev.bus_id, retval);
...@@ -860,7 +857,6 @@ static int register_root_hub (struct usb_device *usb_dev, ...@@ -860,7 +857,6 @@ static int register_root_hub (struct usb_device *usb_dev,
retval = usb_new_device (usb_dev); retval = usb_new_device (usb_dev);
if (retval) { if (retval) {
usb_dev->bus->root_hub = NULL;
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);
} }
...@@ -1772,12 +1768,10 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -1772,12 +1768,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* till now HC has been in an indeterminate state ... */ /* HC is in reset state, but accessible. Now do the one-time init,
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { * bottom up so that hcds can customize the root hubs before khubd
dev_err(hcd->self.controller, "can't reset\n"); * starts talking to them. (Note, bus id is assigned early too.)
return retval; */
}
if ((retval = hcd_buffer_create(hcd)) != 0) { if ((retval = hcd_buffer_create(hcd)) != 0) {
dev_dbg(hcd->self.controller, "pool alloc failed\n"); dev_dbg(hcd->self.controller, "pool alloc failed\n");
return retval; return retval;
...@@ -1786,6 +1780,42 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -1786,6 +1780,42 @@ int usb_add_hcd(struct usb_hcd *hcd,
if ((retval = usb_register_bus(&hcd->self)) < 0) if ((retval = usb_register_bus(&hcd->self)) < 0)
goto err_register_bus; goto err_register_bus;
if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
dev_err(hcd->self.controller, "unable to allocate root hub\n");
retval = -ENOMEM;
goto err_allocate_root_hub;
}
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
USB_SPEED_FULL;
hcd->self.root_hub = rhdev;
/* "reset" is misnamed; its role is now one-time init. the controller
* should already have been reset (and boot firmware kicked off etc).
*/
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
dev_err(hcd->self.controller, "can't setup\n");
goto err_hcd_driver_setup;
}
/* wakeup flag init is in transition; for now we can't rely on PCI to
* initialize these bits properly, so we let reset() override it.
* This init should _precede_ the reset() once PCI behaves.
*/
device_init_wakeup(&rhdev->dev,
device_can_wakeup(hcd->self.controller));
// ... all these hcd->*_wakeup flags will vanish
hcd->can_wakeup = device_can_wakeup(hcd->self.controller);
/* hcd->driver->reset() reported can_wakeup, probably with
* assistance from board's boot firmware.
* NOTE: normal devices won't enable wakeup by default.
*/
if (hcd->can_wakeup)
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
hcd->remote_wakeup = hcd->can_wakeup;
/* enable irqs just before we start the controller */
if (hcd->driver->irq) { if (hcd->driver->irq) {
char buf[8], *bufp = buf; char buf[8], *bufp = buf;
...@@ -1817,56 +1847,32 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -1817,56 +1847,32 @@ int usb_add_hcd(struct usb_hcd *hcd,
(unsigned long long)hcd->rsrc_start); (unsigned long long)hcd->rsrc_start);
} }
/* Allocate the root hub before calling hcd->driver->start(),
* but don't register it until afterward so that the hardware
* is running.
*/
if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
dev_err(hcd->self.controller, "unable to allocate root hub\n");
retval = -ENOMEM;
goto err_allocate_root_hub;
}
/* Although in principle hcd->driver->start() might need to use rhdev,
* none of the current drivers do.
*/
if ((retval = hcd->driver->start(hcd)) < 0) { if ((retval = hcd->driver->start(hcd)) < 0) {
dev_err(hcd->self.controller, "startup error %d\n", retval); dev_err(hcd->self.controller, "startup error %d\n", retval);
goto err_hcd_driver_start; goto err_hcd_driver_start;
} }
/* hcd->driver->start() reported can_wakeup, probably with /* starting here, usbcore will pay attention to this root hub */
* assistance from board's boot firmware.
* NOTE: normal devices won't enable wakeup by default.
*/
if (hcd->can_wakeup)
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
hcd->remote_wakeup = hcd->can_wakeup;
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
USB_SPEED_FULL;
rhdev->bus_mA = min(500u, hcd->power_budget); rhdev->bus_mA = min(500u, hcd->power_budget);
if ((retval = register_root_hub(rhdev, hcd)) != 0) if ((retval = register_root_hub(hcd)) != 0)
goto err_register_root_hub; goto err_register_root_hub;
if (hcd->uses_new_polling && hcd->poll_rh) if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd); usb_hcd_poll_rh_status(hcd);
return retval; return retval;
err_register_root_hub: err_register_root_hub:
hcd->driver->stop(hcd); hcd->driver->stop(hcd);
err_hcd_driver_start:
err_hcd_driver_start:
usb_put_dev(rhdev);
err_allocate_root_hub:
if (hcd->irq >= 0) if (hcd->irq >= 0)
free_irq(irqnum, hcd); free_irq(irqnum, hcd);
err_request_irq:
err_request_irq: err_hcd_driver_setup:
hcd->self.root_hub = NULL;
usb_put_dev(rhdev);
err_allocate_root_hub:
usb_deregister_bus(&hcd->self); usb_deregister_bus(&hcd->self);
err_register_bus:
err_register_bus:
hcd_buffer_destroy(hcd); hcd_buffer_destroy(hcd);
return retval; return retval;
} }
......
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