diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/core/hub.c | 34 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 23 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/isp116x-hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 2 |
5 files changed, 45 insertions, 18 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 | */ |
1603 | static int __usb_suspend_device (struct usb_device *udev, int port1, | 1605 | static 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 | */ |
1673 | int usb_suspend_device(struct usb_device *udev, pm_message_t state) | 1676 | int 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 | ||
1989 | int usb_suspend_device(struct usb_device *udev, pm_message_t state) | 1995 | int 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 | ||
1994 | int usb_resume_device(struct usb_device *udev) | 2001 | int 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 | ||
1417 | static int verify_suspended(struct device *dev, void *unused) | ||
1418 | { | ||
1419 | return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0; | ||
1420 | } | ||
1421 | |||
1417 | static int usb_generic_suspend(struct device *dev, pm_message_t message) | 1422 | static 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); |