aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-09-13 22:57:04 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:38 -0400
commitc9f89fa40cf274130b56475175a35af961d4b165 (patch)
tree9d02038c4e5589a2b13df98da647a59d46b69567 /drivers/usb
parentdb69087437dd5135a9362da1c37fe072070e8f60 (diff)
[PATCH] remove suspend-path recursion
This patch removes some recursion in the CONFIG_USB_SUSPEND logic, which suspended children (of devices or hubs) that weren't already suspended. When it sees such cases, suspend now just fails cleanly. That logic was not needed during system-wide sleep state transitions; and given the current notions of how to manage selective suspend transitions, we don't want it there either. Where it was particularly handy was coping with various limitations of the sysfs "echo -n N > power/state" support. (These include assuming that "N" is always meaningful to the driver; and that drivers can only transition to state N from state zero.) Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/hub.c76
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