diff options
-rw-r--r-- | drivers/usb/core/hub.c | 76 |
1 files changed, 12 insertions, 64 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 61341d2f3c0e..d3337d9c31dc 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -453,6 +453,7 @@ static void hub_quiesce(struct usb_hub *hub) | |||
453 | { | 453 | { |
454 | /* stop khubd and related activity */ | 454 | /* stop khubd and related activity */ |
455 | hub->quiescing = 1; | 455 | hub->quiescing = 1; |
456 | hub->activating = 0; | ||
456 | usb_kill_urb(hub->urb); | 457 | usb_kill_urb(hub->urb); |
457 | if (hub->has_indicators) | 458 | if (hub->has_indicators) |
458 | cancel_delayed_work(&hub->leds); | 459 | cancel_delayed_work(&hub->leds); |
@@ -1613,68 +1614,21 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, | |||
1613 | return 0; | 1614 | return 0; |
1614 | } | 1615 | } |
1615 | 1616 | ||
1616 | /* suspend interface drivers; if this is a hub, it | 1617 | /* all interfaces must already be suspended */ |
1617 | * suspends the child devices | ||
1618 | */ | ||
1619 | if (udev->actconfig) { | 1618 | if (udev->actconfig) { |
1620 | int i; | 1619 | int i; |
1621 | 1620 | ||
1622 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { | 1621 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { |
1623 | struct usb_interface *intf; | 1622 | struct usb_interface *intf; |
1624 | struct usb_driver *driver; | ||
1625 | 1623 | ||
1626 | intf = udev->actconfig->interface[i]; | 1624 | intf = udev->actconfig->interface[i]; |
1627 | if (!is_active(intf)) | 1625 | if (is_active(intf)) { |
1628 | continue; | 1626 | dev_dbg(&intf->dev, "nyet suspended\n"); |
1629 | if (!intf->dev.driver) | 1627 | return -EBUSY; |
1630 | continue; | ||
1631 | driver = to_usb_driver(intf->dev.driver); | ||
1632 | |||
1633 | if (driver->suspend) { | ||
1634 | status = driver->suspend(intf, state); | ||
1635 | if (status == 0) | ||
1636 | mark_quiesced(intf); | ||
1637 | else | ||
1638 | dev_err(&intf->dev, | ||
1639 | "suspend error %d\n", | ||
1640 | status); | ||
1641 | } | ||
1642 | |||
1643 | /* only drivers with suspend() can ever resume(); | ||
1644 | * and after power loss, even they won't. | ||
1645 | * bus_rescan_devices() can rebind drivers later. | ||
1646 | * | ||
1647 | * FIXME the PM core self-deadlocks when unbinding | ||
1648 | * drivers during suspend/resume ... everything grabs | ||
1649 | * dpm_sem (not a spinlock, ugh). we want to unbind, | ||
1650 | * since we know every driver's probe/disconnect works | ||
1651 | * even for drivers that can't suspend. | ||
1652 | */ | ||
1653 | if (!driver->suspend || state.event > PM_EVENT_FREEZE) { | ||
1654 | #if 1 | ||
1655 | dev_warn(&intf->dev, "resume is unsafe!\n"); | ||
1656 | #else | ||
1657 | down_write(&usb_bus_type.rwsem); | ||
1658 | device_release_driver(&intf->dev); | ||
1659 | up_write(&usb_bus_type.rwsem); | ||
1660 | #endif | ||
1661 | } | 1628 | } |
1662 | } | 1629 | } |
1663 | } | 1630 | } |
1664 | 1631 | ||
1665 | /* | ||
1666 | * FIXME this needs port power off call paths too, to help force | ||
1667 | * USB into the "generic" PM model. At least for devices on | ||
1668 | * ports that aren't using ganged switching (usually root hubs). | ||
1669 | * | ||
1670 | * NOTE: SRP-capable links should adopt more aggressive poweroff | ||
1671 | * policies (when HNP doesn't apply) once we have mechanisms to | ||
1672 | * turn power back on! (Likely not before 2.7...) | ||
1673 | */ | ||
1674 | if (state.event > PM_EVENT_FREEZE) { | ||
1675 | dev_warn(&udev->dev, "no poweroff yet, suspending instead\n"); | ||
1676 | } | ||
1677 | |||
1678 | /* "global suspend" of the HC-to-USB interface (root hub), or | 1632 | /* "global suspend" of the HC-to-USB interface (root hub), or |
1679 | * "selective suspend" of just one hub-device link. | 1633 | * "selective suspend" of just one hub-device link. |
1680 | */ | 1634 | */ |
@@ -1960,26 +1914,20 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) | |||
1960 | struct usb_hub *hub = usb_get_intfdata (intf); | 1914 | struct usb_hub *hub = usb_get_intfdata (intf); |
1961 | struct usb_device *hdev = hub->hdev; | 1915 | struct usb_device *hdev = hub->hdev; |
1962 | unsigned port1; | 1916 | unsigned port1; |
1963 | int status; | ||
1964 | |||
1965 | /* stop khubd and related activity */ | ||
1966 | hub_quiesce(hub); | ||
1967 | 1917 | ||
1968 | /* then suspend every port */ | 1918 | /* fail if children aren't already suspended */ |
1969 | for (port1 = 1; port1 <= hdev->maxchild; port1++) { | 1919 | for (port1 = 1; port1 <= hdev->maxchild; port1++) { |
1970 | struct usb_device *udev; | 1920 | struct usb_device *udev; |
1971 | 1921 | ||
1972 | udev = hdev->children [port1-1]; | 1922 | udev = hdev->children [port1-1]; |
1973 | if (!udev) | 1923 | if (udev && udev->state != USB_STATE_SUSPENDED) { |
1974 | continue; | 1924 | dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); |
1975 | down(&udev->serialize); | 1925 | return -EBUSY; |
1976 | status = __usb_suspend_device(udev, port1, msg); | 1926 | } |
1977 | up(&udev->serialize); | ||
1978 | if (status < 0) | ||
1979 | dev_dbg(&intf->dev, "suspend port %d --> %d\n", | ||
1980 | port1, status); | ||
1981 | } | 1927 | } |
1982 | 1928 | ||
1929 | /* stop khubd and related activity */ | ||
1930 | hub_quiesce(hub); | ||
1983 | return 0; | 1931 | return 0; |
1984 | } | 1932 | } |
1985 | 1933 | ||