diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2006-11-20 11:14:30 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-12-01 17:25:52 -0500 |
commit | d25450c68767481f7c9cc4823a6da8235db40be6 (patch) | |
tree | 1a982e5b7ed83f1911bbc3e58a02552d765d192a | |
parent | ce3615879ae85373c03744b45b7c2d7ae5e29b2a (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.c | 43 |
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 | |||
1760 | hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) | 1762 | hub_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, | 1799 | SuspendCleared: |
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 | } |