aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/hub.c34
-rw-r--r--drivers/usb/core/usb.c23
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/isp116x-hcd.c2
-rw-r--r--drivers/usb/host/ohci-pci.c2
-rw-r--r--include/linux/usb.h2
6 files changed, 46 insertions, 19 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d3337d9c31dc..33127b828d60 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1323,11 +1323,9 @@ int usb_new_device(struct usb_device *udev)
1323 * (Includes HNP test device.) 1323 * (Includes HNP test device.)
1324 */ 1324 */
1325 if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { 1325 if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
1326 static int __usb_suspend_device (struct usb_device *, 1326 static int __usb_suspend_device(struct usb_device *,
1327 int port1, pm_message_t state); 1327 int port1);
1328 err = __usb_suspend_device(udev, 1328 err = __usb_suspend_device(udev, udev->bus->otg_port);
1329 udev->bus->otg_port,
1330 PMSG_SUSPEND);
1331 if (err < 0) 1329 if (err < 0)
1332 dev_dbg(&udev->dev, "HNP fail, %d\n", err); 1330 dev_dbg(&udev->dev, "HNP fail, %d\n", err);
1333 } 1331 }
@@ -1517,7 +1515,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
1517 /* FIXME let caller ask to power down the port: 1515 /* FIXME let caller ask to power down the port:
1518 * - some devices won't enumerate without a VBUS power cycle 1516 * - some devices won't enumerate without a VBUS power cycle
1519 * - SRP saves power that way 1517 * - SRP saves power that way
1520 * - usb_suspend_device(dev, PMSG_SUSPEND) 1518 * - ... new call, TBD ...
1521 * That's easy if this hub can switch power per-port, and 1519 * That's easy if this hub can switch power per-port, and
1522 * khubd reactivates the port later (timer, SRP, etc). 1520 * khubd reactivates the port later (timer, SRP, etc).
1523 * Powerdown must be optional, because of reset/DFU. 1521 * Powerdown must be optional, because of reset/DFU.
@@ -1599,9 +1597,12 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
1599 * Other than re-initializing the hub (plug/unplug, except for root hubs), 1597 * Other than re-initializing the hub (plug/unplug, except for root hubs),
1600 * Linux (2.6) currently has NO mechanisms to initiate that: no khubd 1598 * Linux (2.6) currently has NO mechanisms to initiate that: no khubd
1601 * timer, no SRP, no requests through sysfs. 1599 * timer, no SRP, no requests through sysfs.
1600 *
1601 * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
1602 * the root hub for their bus goes into global suspend ... so we don't
1603 * (falsely) update the device power state to say it suspended.
1602 */ 1604 */
1603static int __usb_suspend_device (struct usb_device *udev, int port1, 1605static int __usb_suspend_device (struct usb_device *udev, int port1)
1604 pm_message_t state)
1605{ 1606{
1606 int status; 1607 int status;
1607 1608
@@ -1648,14 +1649,13 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
1648 udev); 1649 udev);
1649 1650
1650 if (status == 0) 1651 if (status == 0)
1651 udev->dev.power.power_state = state; 1652 udev->dev.power.power_state = PMSG_SUSPEND;
1652 return status; 1653 return status;
1653} 1654}
1654 1655
1655/** 1656/**
1656 * usb_suspend_device - suspend a usb device 1657 * usb_suspend_device - suspend a usb device
1657 * @udev: device that's no longer in active use 1658 * @udev: device that's no longer in active use
1658 * @state: PMSG_SUSPEND to suspend
1659 * Context: must be able to sleep; device not locked 1659 * Context: must be able to sleep; device not locked
1660 * 1660 *
1661 * Suspends a USB device that isn't in active use, conserving power. 1661 * Suspends a USB device that isn't in active use, conserving power.
@@ -1664,13 +1664,16 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
1664 * suspend by the host, using usb_resume_device(). It's also routine 1664 * suspend by the host, using usb_resume_device(). It's also routine
1665 * to disconnect devices while they are suspended. 1665 * to disconnect devices while they are suspended.
1666 * 1666 *
1667 * This only affects the USB hardware for a device; its interfaces
1668 * (and, for hubs, child devices) must already have been suspended.
1669 *
1667 * Suspending OTG devices may trigger HNP, if that's been enabled 1670 * Suspending OTG devices may trigger HNP, if that's been enabled
1668 * between a pair of dual-role devices. That will change roles, such 1671 * between a pair of dual-role devices. That will change roles, such
1669 * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. 1672 * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
1670 * 1673 *
1671 * Returns 0 on success, else negative errno. 1674 * Returns 0 on success, else negative errno.
1672 */ 1675 */
1673int usb_suspend_device(struct usb_device *udev, pm_message_t state) 1676int usb_suspend_device(struct usb_device *udev)
1674{ 1677{
1675 int port1, status; 1678 int port1, status;
1676 1679
@@ -1678,12 +1681,15 @@ int usb_suspend_device(struct usb_device *udev, pm_message_t state)
1678 if (port1 < 0) 1681 if (port1 < 0)
1679 return port1; 1682 return port1;
1680 1683
1681 status = __usb_suspend_device(udev, port1, state); 1684 status = __usb_suspend_device(udev, port1);
1682 usb_unlock_device(udev); 1685 usb_unlock_device(udev);
1683 return status; 1686 return status;
1684} 1687}
1685 1688
1686/* 1689/*
1690 * If the USB "suspend" state is in use (rather than "global suspend"),
1691 * many devices will be individually taken out of suspend state using
1692 * special" resume" signaling. These routines kick in shortly after
1687 * hardware resume signaling is finished, either because of selective 1693 * hardware resume signaling is finished, either because of selective
1688 * resume (by host) or remote wakeup (by device) ... now see what changed 1694 * resume (by host) or remote wakeup (by device) ... now see what changed
1689 * in the tree that's rooted at this device. 1695 * in the tree that's rooted at this device.
@@ -1986,13 +1992,15 @@ void usb_resume_root_hub(struct usb_device *hdev)
1986 1992
1987#else /* !CONFIG_USB_SUSPEND */ 1993#else /* !CONFIG_USB_SUSPEND */
1988 1994
1989int usb_suspend_device(struct usb_device *udev, pm_message_t state) 1995int usb_suspend_device(struct usb_device *udev)
1990{ 1996{
1997 /* state does NOT lie by saying it's USB_STATE_SUSPENDED! */
1991 return 0; 1998 return 0;
1992} 1999}
1993 2000
1994int usb_resume_device(struct usb_device *udev) 2001int usb_resume_device(struct usb_device *udev)
1995{ 2002{
2003 udev->dev.power_state.event = PM_EVENT_ON;
1996 return 0; 2004 return 0;
1997} 2005}
1998 2006
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 6ecfdce4f848..e89dbd43e952 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1414,14 +1414,33 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
1414 usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); 1414 usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
1415} 1415}
1416 1416
1417static int verify_suspended(struct device *dev, void *unused)
1418{
1419 return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
1420}
1421
1417static int usb_generic_suspend(struct device *dev, pm_message_t message) 1422static int usb_generic_suspend(struct device *dev, pm_message_t message)
1418{ 1423{
1419 struct usb_interface *intf; 1424 struct usb_interface *intf;
1420 struct usb_driver *driver; 1425 struct usb_driver *driver;
1421 int status; 1426 int status;
1422 1427
1423 if (dev->driver == &usb_generic_driver) 1428 /* USB devices enter SUSPEND state through their hubs, but can be
1424 return usb_suspend_device (to_usb_device(dev), message); 1429 * marked for FREEZE as soon as their children are already idled.
1430 */
1431 if (dev->driver == &usb_generic_driver) {
1432 if (dev->power.power_state.event == message.event)
1433 return 0;
1434 /* we need to rule out bogus requests through sysfs */
1435 status = device_for_each_child(dev, NULL, verify_suspended);
1436 if (status)
1437 return status;
1438 if (message.event == PM_EVENT_FREEZE) {
1439 dev->power.power_state = message;
1440 return 0;
1441 }
1442 return usb_suspend_device (to_usb_device(dev));
1443 }
1425 1444
1426 if ((dev->driver == NULL) || 1445 if ((dev->driver == NULL) ||
1427 (dev->driver_data == &usb_generic_driver_data)) 1446 (dev->driver_data == &usb_generic_driver_data))
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index b3eb02613bff..513fccbb8e43 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -759,7 +759,7 @@ static int ehci_suspend (struct usb_hcd *hcd, pm_message_t message)
759 msleep (100); 759 msleep (100);
760 760
761#ifdef CONFIG_USB_SUSPEND 761#ifdef CONFIG_USB_SUSPEND
762 (void) usb_suspend_device (hcd->self.root_hub, message); 762 (void) usb_suspend_device (hcd->self.root_hub);
763#else 763#else
764 usb_lock_device (hcd->self.root_hub); 764 usb_lock_device (hcd->self.root_hub);
765 (void) ehci_hub_suspend (hcd); 765 (void) ehci_hub_suspend (hcd);
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 642f35068ce2..554d60282a9d 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1781,7 +1781,7 @@ static int isp116x_suspend(struct device *dev, pm_message_t state)
1781 1781
1782 VDBG("%s: state %x\n", __func__, state); 1782 VDBG("%s: state %x\n", __func__, state);
1783 1783
1784 ret = usb_suspend_device(hcd->self.root_hub, state); 1784 ret = usb_suspend_device(hcd->self.root_hub);
1785 if (!ret) { 1785 if (!ret) {
1786 dev->power.power_state = state; 1786 dev->power.power_state = state;
1787 INFO("%s suspended\n", hcd_name); 1787 INFO("%s suspended\n", hcd_name);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index eede6be098d2..41e85980fa7a 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -119,7 +119,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
119 msleep (100); 119 msleep (100);
120 120
121#ifdef CONFIG_USB_SUSPEND 121#ifdef CONFIG_USB_SUSPEND
122 (void) usb_suspend_device (hcd->self.root_hub, message); 122 (void) usb_suspend_device (hcd->self.root_hub);
123#else 123#else
124 usb_lock_device (hcd->self.root_hub); 124 usb_lock_device (hcd->self.root_hub);
125 (void) ohci_hub_suspend (hcd); 125 (void) ohci_hub_suspend (hcd);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 04502e183dd1..25ec91ddcd04 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -976,7 +976,7 @@ extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
976 int timeout); 976 int timeout);
977 977
978/* selective suspend/resume */ 978/* selective suspend/resume */
979extern int usb_suspend_device(struct usb_device *dev, pm_message_t message); 979extern int usb_suspend_device(struct usb_device *dev);
980extern int usb_resume_device(struct usb_device *dev); 980extern int usb_resume_device(struct usb_device *dev);
981 981
982 982