diff options
Diffstat (limited to 'drivers/usb/core/hcd.c')
-rw-r--r-- | drivers/usb/core/hcd.c | 44 |
1 files changed, 29 insertions, 15 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 975d7c1288e3..94d22551fc1b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1878,23 +1878,10 @@ rescan: | |||
1878 | /* kick hcd */ | 1878 | /* kick hcd */ |
1879 | unlink1(hcd, urb, -ESHUTDOWN); | 1879 | unlink1(hcd, urb, -ESHUTDOWN); |
1880 | dev_dbg (hcd->self.controller, | 1880 | dev_dbg (hcd->self.controller, |
1881 | "shutdown urb %pK ep%d%s%s\n", | 1881 | "shutdown urb %pK ep%d%s-%s\n", |
1882 | urb, usb_endpoint_num(&ep->desc), | 1882 | urb, usb_endpoint_num(&ep->desc), |
1883 | is_in ? "in" : "out", | 1883 | is_in ? "in" : "out", |
1884 | ({ char *s; | 1884 | usb_ep_type_string(usb_endpoint_type(&ep->desc))); |
1885 | |||
1886 | switch (usb_endpoint_type(&ep->desc)) { | ||
1887 | case USB_ENDPOINT_XFER_CONTROL: | ||
1888 | s = ""; break; | ||
1889 | case USB_ENDPOINT_XFER_BULK: | ||
1890 | s = "-bulk"; break; | ||
1891 | case USB_ENDPOINT_XFER_INT: | ||
1892 | s = "-intr"; break; | ||
1893 | default: | ||
1894 | s = "-iso"; break; | ||
1895 | }; | ||
1896 | s; | ||
1897 | })); | ||
1898 | usb_put_urb (urb); | 1885 | usb_put_urb (urb); |
1899 | 1886 | ||
1900 | /* list contents may have changed */ | 1887 | /* list contents may have changed */ |
@@ -2448,6 +2435,19 @@ EXPORT_SYMBOL_GPL(usb_hcd_irq); | |||
2448 | 2435 | ||
2449 | /*-------------------------------------------------------------------------*/ | 2436 | /*-------------------------------------------------------------------------*/ |
2450 | 2437 | ||
2438 | /* Workqueue routine for when the root-hub has died. */ | ||
2439 | static void hcd_died_work(struct work_struct *work) | ||
2440 | { | ||
2441 | struct usb_hcd *hcd = container_of(work, struct usb_hcd, died_work); | ||
2442 | static char *env[] = { | ||
2443 | "ERROR=DEAD", | ||
2444 | NULL | ||
2445 | }; | ||
2446 | |||
2447 | /* Notify user space that the host controller has died */ | ||
2448 | kobject_uevent_env(&hcd->self.root_hub->dev.kobj, KOBJ_OFFLINE, env); | ||
2449 | } | ||
2450 | |||
2451 | /** | 2451 | /** |
2452 | * usb_hc_died - report abnormal shutdown of a host controller (bus glue) | 2452 | * usb_hc_died - report abnormal shutdown of a host controller (bus glue) |
2453 | * @hcd: pointer to the HCD representing the controller | 2453 | * @hcd: pointer to the HCD representing the controller |
@@ -2488,6 +2488,13 @@ void usb_hc_died (struct usb_hcd *hcd) | |||
2488 | usb_kick_hub_wq(hcd->self.root_hub); | 2488 | usb_kick_hub_wq(hcd->self.root_hub); |
2489 | } | 2489 | } |
2490 | } | 2490 | } |
2491 | |||
2492 | /* Handle the case where this function gets called with a shared HCD */ | ||
2493 | if (usb_hcd_is_primary_hcd(hcd)) | ||
2494 | schedule_work(&hcd->died_work); | ||
2495 | else | ||
2496 | schedule_work(&hcd->primary_hcd->died_work); | ||
2497 | |||
2491 | spin_unlock_irqrestore (&hcd_root_hub_lock, flags); | 2498 | spin_unlock_irqrestore (&hcd_root_hub_lock, flags); |
2492 | /* Make sure that the other roothub is also deallocated. */ | 2499 | /* Make sure that the other roothub is also deallocated. */ |
2493 | } | 2500 | } |
@@ -2555,6 +2562,8 @@ struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, | |||
2555 | INIT_WORK(&hcd->wakeup_work, hcd_resume_work); | 2562 | INIT_WORK(&hcd->wakeup_work, hcd_resume_work); |
2556 | #endif | 2563 | #endif |
2557 | 2564 | ||
2565 | INIT_WORK(&hcd->died_work, hcd_died_work); | ||
2566 | |||
2558 | hcd->driver = driver; | 2567 | hcd->driver = driver; |
2559 | hcd->speed = driver->flags & HCD_MASK; | 2568 | hcd->speed = driver->flags & HCD_MASK; |
2560 | hcd->product_desc = (driver->product_desc) ? driver->product_desc : | 2569 | hcd->product_desc = (driver->product_desc) ? driver->product_desc : |
@@ -2908,6 +2917,7 @@ error_create_attr_group: | |||
2908 | #ifdef CONFIG_PM | 2917 | #ifdef CONFIG_PM |
2909 | cancel_work_sync(&hcd->wakeup_work); | 2918 | cancel_work_sync(&hcd->wakeup_work); |
2910 | #endif | 2919 | #endif |
2920 | cancel_work_sync(&hcd->died_work); | ||
2911 | mutex_lock(&usb_bus_idr_lock); | 2921 | mutex_lock(&usb_bus_idr_lock); |
2912 | usb_disconnect(&rhdev); /* Sets rhdev to NULL */ | 2922 | usb_disconnect(&rhdev); /* Sets rhdev to NULL */ |
2913 | mutex_unlock(&usb_bus_idr_lock); | 2923 | mutex_unlock(&usb_bus_idr_lock); |
@@ -2968,6 +2978,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) | |||
2968 | #ifdef CONFIG_PM | 2978 | #ifdef CONFIG_PM |
2969 | cancel_work_sync(&hcd->wakeup_work); | 2979 | cancel_work_sync(&hcd->wakeup_work); |
2970 | #endif | 2980 | #endif |
2981 | cancel_work_sync(&hcd->died_work); | ||
2971 | 2982 | ||
2972 | mutex_lock(&usb_bus_idr_lock); | 2983 | mutex_lock(&usb_bus_idr_lock); |
2973 | usb_disconnect(&rhdev); /* Sets rhdev to NULL */ | 2984 | usb_disconnect(&rhdev); /* Sets rhdev to NULL */ |
@@ -3020,6 +3031,9 @@ usb_hcd_platform_shutdown(struct platform_device *dev) | |||
3020 | { | 3031 | { |
3021 | struct usb_hcd *hcd = platform_get_drvdata(dev); | 3032 | struct usb_hcd *hcd = platform_get_drvdata(dev); |
3022 | 3033 | ||
3034 | /* No need for pm_runtime_put(), we're shutting down */ | ||
3035 | pm_runtime_get_sync(&dev->dev); | ||
3036 | |||
3023 | if (hcd->driver->shutdown) | 3037 | if (hcd->driver->shutdown) |
3024 | hcd->driver->shutdown(hcd); | 3038 | hcd->driver->shutdown(hcd); |
3025 | } | 3039 | } |