aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-11-20 11:14:30 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-01 17:25:52 -0500
commitd25450c68767481f7c9cc4823a6da8235db40be6 (patch)
tree1a982e5b7ed83f1911bbc3e58a02552d765d192a
parentce3615879ae85373c03744b45b7c2d7ae5e29b2a (diff)
USB hub: simplify remote-wakeup handling
This patch (as817) simplifies the remote-wakeup processing in the hub driver. Now instead of using a specialized code path, it relies on the standard USB resume routines. The hub_port_resume() function does an initial get_port_status() to see whether the port has already resumed itself (as it does when a remote-wakeup request is sent). This will slow down handling of other resume events slightly, but not enough to matter. The patch also changes the hub_port_status() routine, making it return an error if a short reply is received. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/hub.c43
1 files changed, 20 insertions, 23 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 55812a5ac661..46df5e60764b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1409,10 +1409,12 @@ static int hub_port_status(struct usb_hub *hub, int port1,
1409 int ret; 1409 int ret;
1410 1410
1411 ret = get_port_status(hub->hdev, port1, &hub->status->port); 1411 ret = get_port_status(hub->hdev, port1, &hub->status->port);
1412 if (ret < 0) 1412 if (ret < 4) {
1413 dev_err (hub->intfdev, 1413 dev_err (hub->intfdev,
1414 "%s failed (err = %d)\n", __FUNCTION__, ret); 1414 "%s failed (err = %d)\n", __FUNCTION__, ret);
1415 else { 1415 if (ret >= 0)
1416 ret = -EIO;
1417 } else {
1416 *status = le16_to_cpu(hub->status->port.wPortStatus); 1418 *status = le16_to_cpu(hub->status->port.wPortStatus);
1417 *change = le16_to_cpu(hub->status->port.wPortChange); 1419 *change = le16_to_cpu(hub->status->port.wPortChange);
1418 ret = 0; 1420 ret = 0;
@@ -1760,6 +1762,12 @@ static int
1760hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) 1762hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
1761{ 1763{
1762 int status; 1764 int status;
1765 u16 portchange, portstatus;
1766
1767 /* Skip the initial Clear-Suspend step for a remote wakeup */
1768 status = hub_port_status(hub, port1, &portstatus, &portchange);
1769 if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND))
1770 goto SuspendCleared;
1763 1771
1764 // dev_dbg(hub->intfdev, "resume port %d\n", port1); 1772 // dev_dbg(hub->intfdev, "resume port %d\n", port1);
1765 1773
@@ -1773,9 +1781,6 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
1773 "can't resume port %d, status %d\n", 1781 "can't resume port %d, status %d\n",
1774 port1, status); 1782 port1, status);
1775 } else { 1783 } else {
1776 u16 devstatus;
1777 u16 portchange;
1778
1779 /* drive resume for at least 20 msec */ 1784 /* drive resume for at least 20 msec */
1780 if (udev) 1785 if (udev)
1781 dev_dbg(&udev->dev, "usb %sresume\n", 1786 dev_dbg(&udev->dev, "usb %sresume\n",
@@ -1790,16 +1795,15 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
1790 * stop resume signaling. Then finish the resume 1795 * stop resume signaling. Then finish the resume
1791 * sequence. 1796 * sequence.
1792 */ 1797 */
1793 devstatus = portchange = 0; 1798 status = hub_port_status(hub, port1, &portstatus, &portchange);
1794 status = hub_port_status(hub, port1, 1799SuspendCleared:
1795 &devstatus, &portchange);
1796 if (status < 0 1800 if (status < 0
1797 || (devstatus & LIVE_FLAGS) != LIVE_FLAGS 1801 || (portstatus & LIVE_FLAGS) != LIVE_FLAGS
1798 || (devstatus & USB_PORT_STAT_SUSPEND) != 0 1802 || (portstatus & USB_PORT_STAT_SUSPEND) != 0
1799 ) { 1803 ) {
1800 dev_dbg(hub->intfdev, 1804 dev_dbg(hub->intfdev,
1801 "port %d status %04x.%04x after resume, %d\n", 1805 "port %d status %04x.%04x after resume, %d\n",
1802 port1, portchange, devstatus, status); 1806 port1, portchange, portstatus, status);
1803 if (status >= 0) 1807 if (status >= 0)
1804 status = -ENODEV; 1808 status = -ENODEV;
1805 } else { 1809 } else {
@@ -1860,23 +1864,16 @@ static int remote_wakeup(struct usb_device *udev)
1860{ 1864{
1861 int status = 0; 1865 int status = 0;
1862 1866
1863 /* All this just to avoid sending a port-resume message
1864 * to the parent hub! */
1865
1866 usb_lock_device(udev); 1867 usb_lock_device(udev);
1867 usb_pm_lock(udev);
1868 if (udev->state == USB_STATE_SUSPENDED) { 1868 if (udev->state == USB_STATE_SUSPENDED) {
1869 dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); 1869 dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
1870 /* TRSMRCY = 10 msec */ 1870 status = usb_autoresume_device(udev, 1);
1871 msleep(10); 1871
1872 status = finish_port_resume(udev); 1872 /* Give the interface drivers a chance to do something,
1873 * then autosuspend the device again. */
1873 if (status == 0) 1874 if (status == 0)
1874 udev->dev.power.power_state.event = PM_EVENT_ON; 1875 usb_autosuspend_device(udev, 1);
1875 } 1876 }
1876 usb_pm_unlock(udev);
1877
1878 if (status == 0)
1879 usb_autoresume_device(udev, 0);
1880 usb_unlock_device(udev); 1877 usb_unlock_device(udev);
1881 return status; 1878 return status;
1882} 1879}