diff options
| -rw-r--r-- | drivers/usb/core/hcd.c | 44 | ||||
| -rw-r--r-- | include/linux/usb.h | 2 | ||||
| -rw-r--r-- | include/linux/usb/hcd.h | 3 | 
3 files changed, 49 insertions, 0 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 4225d5e7213..8e64adf8e4d 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);  /*-------------------------------------------------------------------------*/ diff --git a/include/linux/usb.h b/include/linux/usb.h index 689b14b26c8..4d22d0f6167 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -357,6 +357,8 @@ struct usb_bus {  	int bandwidth_int_reqs;		/* number of Interrupt requests */  	int bandwidth_isoc_reqs;	/* number of Isoc. requests */ +	unsigned resuming_ports;	/* bit array: resuming root-hub ports */ +  #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)  	struct mon_bus *mon_bus;	/* non-null when associated */  	int monitored;			/* non-zero when monitored */ diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 608050b2545..0a78df5f6cf 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);  extern void usb_wakeup_notification(struct usb_device *hdev,  		unsigned int portnum); +extern void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum); +extern void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum); +  /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */  #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)  #define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))  |