aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/hcd.c32
-rw-r--r--include/linux/usb/hcd.h1
2 files changed, 26 insertions, 7 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index caae4625a1f1..53f14c82ff2e 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -667,7 +667,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
667 unsigned long flags; 667 unsigned long flags;
668 char buffer[6]; /* Any root hubs with > 31 ports? */ 668 char buffer[6]; /* Any root hubs with > 31 ports? */
669 669
670 if (unlikely(!hcd->rh_registered)) 670 if (unlikely(!hcd->rh_pollable))
671 return; 671 return;
672 if (!hcd->uses_new_polling && !hcd->status_urb) 672 if (!hcd->uses_new_polling && !hcd->status_urb)
673 return; 673 return;
@@ -2217,6 +2217,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
2217 retval = -ENOMEM; 2217 retval = -ENOMEM;
2218 goto err_allocate_root_hub; 2218 goto err_allocate_root_hub;
2219 } 2219 }
2220 hcd->self.root_hub = rhdev;
2220 2221
2221 switch (hcd->driver->flags & HCD_MASK) { 2222 switch (hcd->driver->flags & HCD_MASK) {
2222 case HCD_USB11: 2223 case HCD_USB11:
@@ -2231,7 +2232,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
2231 default: 2232 default:
2232 goto err_set_rh_speed; 2233 goto err_set_rh_speed;
2233 } 2234 }
2234 hcd->self.root_hub = rhdev;
2235 2235
2236 /* wakeup flag init defaults to "everything works" for root hubs, 2236 /* wakeup flag init defaults to "everything works" for root hubs,
2237 * but drivers can override it in reset() if needed, along with 2237 * but drivers can override it in reset() if needed, along with
@@ -2246,6 +2246,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
2246 dev_err(hcd->self.controller, "can't setup\n"); 2246 dev_err(hcd->self.controller, "can't setup\n");
2247 goto err_hcd_driver_setup; 2247 goto err_hcd_driver_setup;
2248 } 2248 }
2249 hcd->rh_pollable = 1;
2249 2250
2250 /* NOTE: root hub and controller capabilities may not be the same */ 2251 /* NOTE: root hub and controller capabilities may not be the same */
2251 if (device_can_wakeup(hcd->self.controller) 2252 if (device_can_wakeup(hcd->self.controller)
@@ -2315,9 +2316,12 @@ error_create_attr_group:
2315 cancel_work_sync(&hcd->wakeup_work); 2316 cancel_work_sync(&hcd->wakeup_work);
2316#endif 2317#endif
2317 mutex_lock(&usb_bus_list_lock); 2318 mutex_lock(&usb_bus_list_lock);
2318 usb_disconnect(&hcd->self.root_hub); 2319 usb_disconnect(&rhdev); /* Sets rhdev to NULL */
2319 mutex_unlock(&usb_bus_list_lock); 2320 mutex_unlock(&usb_bus_list_lock);
2320err_register_root_hub: 2321err_register_root_hub:
2322 hcd->rh_pollable = 0;
2323 hcd->poll_rh = 0;
2324 del_timer_sync(&hcd->rh_timer);
2321 hcd->driver->stop(hcd); 2325 hcd->driver->stop(hcd);
2322 hcd->state = HC_STATE_HALT; 2326 hcd->state = HC_STATE_HALT;
2323 hcd->poll_rh = 0; 2327 hcd->poll_rh = 0;
@@ -2328,8 +2332,7 @@ err_hcd_driver_start:
2328err_request_irq: 2332err_request_irq:
2329err_hcd_driver_setup: 2333err_hcd_driver_setup:
2330err_set_rh_speed: 2334err_set_rh_speed:
2331 hcd->self.root_hub = NULL; 2335 usb_put_dev(hcd->self.root_hub);
2332 usb_put_dev(rhdev);
2333err_allocate_root_hub: 2336err_allocate_root_hub:
2334 usb_deregister_bus(&hcd->self); 2337 usb_deregister_bus(&hcd->self);
2335err_register_bus: 2338err_register_bus:
@@ -2348,9 +2351,12 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
2348 */ 2351 */
2349void usb_remove_hcd(struct usb_hcd *hcd) 2352void usb_remove_hcd(struct usb_hcd *hcd)
2350{ 2353{
2354 struct usb_device *rhdev = hcd->self.root_hub;
2355
2351 dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); 2356 dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
2352 2357
2353 sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group); 2358 usb_get_dev(rhdev);
2359 sysfs_remove_group(&rhdev->dev.kobj, &usb_bus_attr_group);
2354 2360
2355 if (HC_IS_RUNNING (hcd->state)) 2361 if (HC_IS_RUNNING (hcd->state))
2356 hcd->state = HC_STATE_QUIESCING; 2362 hcd->state = HC_STATE_QUIESCING;
@@ -2365,17 +2371,29 @@ void usb_remove_hcd(struct usb_hcd *hcd)
2365#endif 2371#endif
2366 2372
2367 mutex_lock(&usb_bus_list_lock); 2373 mutex_lock(&usb_bus_list_lock);
2368 usb_disconnect(&hcd->self.root_hub); 2374 usb_disconnect(&rhdev); /* Sets rhdev to NULL */
2369 mutex_unlock(&usb_bus_list_lock); 2375 mutex_unlock(&usb_bus_list_lock);
2370 2376
2377 /* Prevent any more root-hub status calls from the timer.
2378 * The HCD might still restart the timer (if a port status change
2379 * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke
2380 * the hub_status_data() callback.
2381 */
2382 hcd->rh_pollable = 0;
2383 hcd->poll_rh = 0;
2384 del_timer_sync(&hcd->rh_timer);
2385
2371 hcd->driver->stop(hcd); 2386 hcd->driver->stop(hcd);
2372 hcd->state = HC_STATE_HALT; 2387 hcd->state = HC_STATE_HALT;
2373 2388
2389 /* In case the HCD restarted the timer, stop it again. */
2374 hcd->poll_rh = 0; 2390 hcd->poll_rh = 0;
2375 del_timer_sync(&hcd->rh_timer); 2391 del_timer_sync(&hcd->rh_timer);
2376 2392
2377 if (hcd->irq >= 0) 2393 if (hcd->irq >= 0)
2378 free_irq(hcd->irq, hcd); 2394 free_irq(hcd->irq, hcd);
2395
2396 usb_put_dev(hcd->self.root_hub);
2379 usb_deregister_bus(&hcd->self); 2397 usb_deregister_bus(&hcd->self);
2380 hcd_buffer_destroy(hcd); 2398 hcd_buffer_destroy(hcd);
2381} 2399}
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 2e3a4ea1a3da..11b638195901 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -95,6 +95,7 @@ struct usb_hcd {
95#define HCD_FLAG_SAW_IRQ 0x00000002 95#define HCD_FLAG_SAW_IRQ 0x00000002
96 96
97 unsigned rh_registered:1;/* is root hub registered? */ 97 unsigned rh_registered:1;/* is root hub registered? */
98 unsigned rh_pollable:1; /* may we poll the root hub? */
98 99
99 /* The next flag is a stopgap, to be removed when all the HCDs 100 /* The next flag is a stopgap, to be removed when all the HCDs
100 * support the new root-hub polling mechanism. */ 101 * support the new root-hub polling mechanism. */