aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/hcd.c44
-rw-r--r--include/linux/usb.h2
-rw-r--r--include/linux/usb/hcd.h3
3 files changed, 49 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 @@
39#include <asm/unaligned.h> 39#include <asm/unaligned.h>
40#include <linux/platform_device.h> 40#include <linux/platform_device.h>
41#include <linux/workqueue.h> 41#include <linux/workqueue.h>
42#include <linux/pm_runtime.h>
42 43
43#include <linux/usb.h> 44#include <linux/usb.h>
44#include <linux/usb/hcd.h> 45#include <linux/usb/hcd.h>
@@ -1025,6 +1026,49 @@ static int register_root_hub(struct usb_hcd *hcd)
1025 return retval; 1026 return retval;
1026} 1027}
1027 1028
1029/*
1030 * usb_hcd_start_port_resume - a root-hub port is sending a resume signal
1031 * @bus: the bus which the root hub belongs to
1032 * @portnum: the port which is being resumed
1033 *
1034 * HCDs should call this function when they know that a resume signal is
1035 * being sent to a root-hub port. The root hub will be prevented from
1036 * going into autosuspend until usb_hcd_end_port_resume() is called.
1037 *
1038 * The bus's private lock must be held by the caller.
1039 */
1040void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum)
1041{
1042 unsigned bit = 1 << portnum;
1043
1044 if (!(bus->resuming_ports & bit)) {
1045 bus->resuming_ports |= bit;
1046 pm_runtime_get_noresume(&bus->root_hub->dev);
1047 }
1048}
1049EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume);
1050
1051/*
1052 * usb_hcd_end_port_resume - a root-hub port has stopped sending a resume signal
1053 * @bus: the bus which the root hub belongs to
1054 * @portnum: the port which is being resumed
1055 *
1056 * HCDs should call this function when they know that a resume signal has
1057 * stopped being sent to a root-hub port. The root hub will be allowed to
1058 * autosuspend again.
1059 *
1060 * The bus's private lock must be held by the caller.
1061 */
1062void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum)
1063{
1064 unsigned bit = 1 << portnum;
1065
1066 if (bus->resuming_ports & bit) {
1067 bus->resuming_ports &= ~bit;
1068 pm_runtime_put_noidle(&bus->root_hub->dev);
1069 }
1070}
1071EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
1028 1072
1029/*-------------------------------------------------------------------------*/ 1073/*-------------------------------------------------------------------------*/
1030 1074
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 689b14b26c8d..4d22d0f6167a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -357,6 +357,8 @@ struct usb_bus {
357 int bandwidth_int_reqs; /* number of Interrupt requests */ 357 int bandwidth_int_reqs; /* number of Interrupt requests */
358 int bandwidth_isoc_reqs; /* number of Isoc. requests */ 358 int bandwidth_isoc_reqs; /* number of Isoc. requests */
359 359
360 unsigned resuming_ports; /* bit array: resuming root-hub ports */
361
360#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) 362#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
361 struct mon_bus *mon_bus; /* non-null when associated */ 363 struct mon_bus *mon_bus; /* non-null when associated */
362 int monitored; /* non-zero when monitored */ 364 int monitored; /* non-zero when monitored */
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 608050b2545f..0a78df5f6cfd 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -430,6 +430,9 @@ extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
430extern void usb_wakeup_notification(struct usb_device *hdev, 430extern void usb_wakeup_notification(struct usb_device *hdev,
431 unsigned int portnum); 431 unsigned int portnum);
432 432
433extern void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum);
434extern void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum);
435
433/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ 436/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
434#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) 437#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
435#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) 438#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep)))