summaryrefslogtreecommitdiff
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2013-01-26 02:09:42 +0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-26 03:06:01 +0400
commitda0aa7169b97d90f4af39a9dc84d58bbe19d7e78 (patch)
tree7d5e1d583787b07d6627f4acd46da1cc38deaf93 /drivers/usb/core
parent6e0c3339a6f19d748f16091d0a05adeb1e1f822b (diff)
downloadlinux-da0aa7169b97d90f4af39a9dc84d58bbe19d7e78.tar.xz
USB: add usb_hcd_{start,end}_port_resume
This patch (as1649) adds a mechanism for host controller drivers to inform usbcore when they have begun or ended resume signalling on a particular root-hub port. The core will then make sure that the root hub does not get runtime-suspended while the port resume is going on. Since commit 596d789a211d134dc5f94d1e5957248c204ef850 (USB: set hub's default autosuspend delay as 0), the system tries to suspend hubs whenever they aren't in use. While a root-hub port is being resumed, the root hub does not appear to be in use. Attempted runtime suspends fail because of the ongoing port resume, but the PM core just keeps on trying over and over again. We want to prevent this wasteful effort. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hcd.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 4225d5e72131..8e64adf8e4d5 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -39,6 +39,7 @@
#include <asm/unaligned.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -1025,6 +1026,49 @@ static int register_root_hub(struct usb_hcd *hcd)
return retval;
}
+/*
+ * usb_hcd_start_port_resume - a root-hub port is sending a resume signal
+ * @bus: the bus which the root hub belongs to
+ * @portnum: the port which is being resumed
+ *
+ * HCDs should call this function when they know that a resume signal is
+ * being sent to a root-hub port. The root hub will be prevented from
+ * going into autosuspend until usb_hcd_end_port_resume() is called.
+ *
+ * The bus's private lock must be held by the caller.
+ */
+void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum)
+{
+ unsigned bit = 1 << portnum;
+
+ if (!(bus->resuming_ports & bit)) {
+ bus->resuming_ports |= bit;
+ pm_runtime_get_noresume(&bus->root_hub->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume);
+
+/*
+ * usb_hcd_end_port_resume - a root-hub port has stopped sending a resume signal
+ * @bus: the bus which the root hub belongs to
+ * @portnum: the port which is being resumed
+ *
+ * HCDs should call this function when they know that a resume signal has
+ * stopped being sent to a root-hub port. The root hub will be allowed to
+ * autosuspend again.
+ *
+ * The bus's private lock must be held by the caller.
+ */
+void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum)
+{
+ unsigned bit = 1 << portnum;
+
+ if (bus->resuming_ports & bit) {
+ bus->resuming_ports &= ~bit;
+ pm_runtime_put_noidle(&bus->root_hub->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
/*-------------------------------------------------------------------------*/