diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2010-06-09 17:34:05 -0400 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-10 14:35:33 -0700 | 
| commit | 96e077ae347912dfce0e93f5958efc3ed6f311f4 (patch) | |
| tree | 58eef1baba1052090daa8c457936c1a1ff66b470 /drivers/usb/core | |
| parent | b34d8915c413acb51d837a45fb8747b61f65c020 (diff) | |
| download | olio-linux-3.10-96e077ae347912dfce0e93f5958efc3ed6f311f4.tar.xz olio-linux-3.10-96e077ae347912dfce0e93f5958efc3ed6f311f4.zip  | |
USB: fix failure path in usb_add_hcd()
This patch (as1389) fixes some errors in the failure pathway of
usb_add_hcd().  The actions it takes ought to be exactly the same as
those taken by usb_remove_hcd(), but they aren't.
In one case (removal of the usb_bus_attr_group), the two routines are
brought into agreement by changing usb_remove_hcd().  All the other
discrepancies are fixed by changing usb_add_hcd().
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/hcd.c | 18 | 
1 files changed, 16 insertions, 2 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 12742f152f4..caae4625a1f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2229,7 +2229,7 @@ int usb_add_hcd(struct usb_hcd *hcd,  		rhdev->speed = USB_SPEED_SUPER;  		break;  	default: -		goto err_allocate_root_hub; +		goto err_set_rh_speed;  	}  	hcd->self.root_hub = rhdev; @@ -2305,16 +2305,29 @@ int usb_add_hcd(struct usb_hcd *hcd,  	return retval;  error_create_attr_group: +	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_USB_SUSPEND +	cancel_work_sync(&hcd->wakeup_work); +#endif  	mutex_lock(&usb_bus_list_lock);  	usb_disconnect(&hcd->self.root_hub);  	mutex_unlock(&usb_bus_list_lock);  err_register_root_hub:  	hcd->driver->stop(hcd); +	hcd->state = HC_STATE_HALT; +	hcd->poll_rh = 0; +	del_timer_sync(&hcd->rh_timer);  err_hcd_driver_start:  	if (hcd->irq >= 0)  		free_irq(irqnum, hcd);  err_request_irq:  err_hcd_driver_setup: +err_set_rh_speed:  	hcd->self.root_hub = NULL;  	usb_put_dev(rhdev);  err_allocate_root_hub: @@ -2337,6 +2350,8 @@ void usb_remove_hcd(struct usb_hcd *hcd)  {  	dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); +	sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group); +  	if (HC_IS_RUNNING (hcd->state))  		hcd->state = HC_STATE_QUIESCING; @@ -2349,7 +2364,6 @@ void usb_remove_hcd(struct usb_hcd *hcd)  	cancel_work_sync(&hcd->wakeup_work);  #endif -	sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);  	mutex_lock(&usb_bus_list_lock);  	usb_disconnect(&hcd->self.root_hub);  	mutex_unlock(&usb_bus_list_lock);  |