To support OTG we want a mechanism to start and stop the HCD from the OTG state machine. Add usb_start_hcd() and usb_stop_hcd(). Signed-off-by: Roger Quadros <rogerq@xxxxxx> --- drivers/usb/core/hcd.c | 147 ++++++++++++++++++++++++++++++++---------------- include/linux/usb/hcd.h | 2 + 2 files changed, 100 insertions(+), 49 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 45a915c..e28bd9d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2613,7 +2613,76 @@ static void usb_put_invalidate_rhdev(struct usb_hcd *hcd) } /** - * usb_add_hcd - finish generic HCD structure initialization and register + * usb_start_hcd - start the HCD + * @hcd: the usb_hcd structure to initialize + * + * calls the drivers start() routine, registers the root hub + * and creates the USB sysfs attributes. + */ +int usb_start_hcd(struct usb_hcd *hcd) +{ + int retval; + struct usb_device *rhdev = hcd->self.root_hub; + + if (hcd->state != HC_STATE_HALT) { + dev_err(hcd->self.controller, "not starting a running HCD\n"); + return -EINVAL; + } + + hcd->state = HC_STATE_RUNNING; + retval = hcd->driver->start(hcd); + if (retval < 0) { + dev_err(hcd->self.controller, "startup error %d\n", retval); + hcd->state = HC_STATE_HALT; + return retval; + } + + /* starting here, usbcore will pay attention to this root hub */ + if ((retval = register_root_hub(hcd)) != 0) + goto err_register_root_hub; + + retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); + if (retval < 0) { + pr_err("Cannot register USB bus sysfs attributes: %d\n", + retval); + goto error_create_attr_group; + } + if (hcd->uses_new_polling && HCD_POLL_RH(hcd)) + usb_hcd_poll_rh_status(hcd); + + return retval; + +error_create_attr_group: + clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); + if (HC_IS_RUNNING(hcd->state)) + hcd->state = HC_STATE_QUIESCING; + spin_lock_irq(&hcd_root_hub_lock); + hcd->rh_registered = 0; + spin_unlock_irq(&hcd_root_hub_lock); + +#ifdef CONFIG_PM + cancel_work_sync(&hcd->wakeup_work); +#endif + mutex_lock(&usb_bus_list_lock); + usb_disconnect(&rhdev); /* Sets rhdev to NULL */ + mutex_unlock(&usb_bus_list_lock); +err_register_root_hub: + hcd->rh_pollable = 0; + clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); + del_timer_sync(&hcd->rh_timer); + hcd->driver->stop(hcd); + hcd->state = HC_STATE_HALT; + + /* In case the HCD restarted the timer, stop it again. */ + clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); + del_timer_sync(&hcd->rh_timer); + + return retval; +} +EXPORT_SYMBOL_GPL(usb_start_hcd); + +/** + * usb_add_hcd - finish generic HCD structure initialization and register. * @hcd: the usb_hcd structure to initialize * @irqnum: Interrupt line to allocate * @irqflags: Interrupt type flags @@ -2757,50 +2826,12 @@ int usb_add_hcd(struct usb_hcd *hcd, goto err_request_irq; } - hcd->state = HC_STATE_RUNNING; - retval = hcd->driver->start(hcd); - if (retval < 0) { - dev_err(hcd->self.controller, "startup error %d\n", retval); + retval = usb_start_hcd(hcd); + if (retval) goto err_hcd_driver_start; - } - - /* starting here, usbcore will pay attention to this root hub */ - if ((retval = register_root_hub(hcd)) != 0) - goto err_register_root_hub; - - retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); - if (retval < 0) { - printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n", - retval); - goto error_create_attr_group; - } - if (hcd->uses_new_polling && HCD_POLL_RH(hcd)) - usb_hcd_poll_rh_status(hcd); - - return retval; -error_create_attr_group: - clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); - if (HC_IS_RUNNING(hcd->state)) - hcd->state = HC_STATE_QUIESCING; - spin_lock_irq(&hcd_root_hub_lock); - hcd->rh_registered = 0; - spin_unlock_irq(&hcd_root_hub_lock); + return 0; -#ifdef CONFIG_PM - cancel_work_sync(&hcd->wakeup_work); -#endif - mutex_lock(&usb_bus_list_lock); - usb_disconnect(&rhdev); /* Sets rhdev to NULL */ - mutex_unlock(&usb_bus_list_lock); -err_register_root_hub: - hcd->rh_pollable = 0; - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - del_timer_sync(&hcd->rh_timer); - hcd->driver->stop(hcd); - hcd->state = HC_STATE_HALT; - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - del_timer_sync(&hcd->rh_timer); err_hcd_driver_start: if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0) free_irq(irqnum, hcd); @@ -2830,18 +2861,20 @@ err_phy: EXPORT_SYMBOL_GPL(usb_add_hcd); /** - * usb_remove_hcd - shutdown processing for generic HCDs - * @hcd: the usb_hcd structure to remove - * Context: !in_interrupt() + * usb_stop_hcd - stop the HCD + * @hcd: the usb_hcd structure to initialize * - * Disconnects the root hub, then reverses the effects of usb_add_hcd(), - * invoking the HCD's stop() method. + * removes the USB sysfs attributes, disconnects the root hub + * and calls the driver's stop() routine. */ -void usb_remove_hcd(struct usb_hcd *hcd) +void usb_stop_hcd(struct usb_hcd *hcd) { struct usb_device *rhdev = hcd->self.root_hub; - dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); + if (hcd->state == HC_STATE_HALT) { + dev_err(hcd->self.controller, "not stopping a halted HCD\n"); + return; + } usb_get_dev(rhdev); sysfs_remove_group(&rhdev->dev.kobj, &usb_bus_attr_group); @@ -2888,6 +2921,22 @@ void usb_remove_hcd(struct usb_hcd *hcd) /* In case the HCD restarted the timer, stop it again. */ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); del_timer_sync(&hcd->rh_timer); +} +EXPORT_SYMBOL_GPL(usb_stop_hcd); + +/** + * usb_remove_hcd - shutdown processing for generic HCDs + * @hcd: the usb_hcd structure to remove + * Context: !in_interrupt() + * + * Disconnects the root hub, then reverses the effects of usb_add_hcd(), + * invoking the HCD's stop() method. + */ +void usb_remove_hcd(struct usb_hcd *hcd) +{ + dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); + + usb_stop_hcd(hcd); if (usb_hcd_is_primary_hcd(hcd)) { if (hcd->irq > 0) diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 68b1e83..12aaf4c 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -433,6 +433,8 @@ extern void usb_put_hcd(struct usb_hcd *hcd); extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); +extern int usb_start_hcd(struct usb_hcd *hcd); +extern void usb_stop_hcd(struct usb_hcd *hcd); extern void usb_remove_hcd(struct usb_hcd *hcd); extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1); -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html