Commit eb9f952a authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB Gadget: gadget zero and USB suspend/resume

This patch lets gadget zero be more useful in testing usb suspend
and resume.  It prints messages on suspend() and resume(), and
supports an "autoresume=N" mode to wake the host after N seconds.
parent 8fba64b0
...@@ -130,6 +130,9 @@ struct zero_dev { ...@@ -130,6 +130,9 @@ struct zero_dev {
*/ */
u8 config; u8 config;
struct usb_ep *in_ep, *out_ep; struct usb_ep *in_ep, *out_ep;
/* autoresume timer */
struct timer_list resume;
}; };
#define xprintk(d,level,fmt,args...) \ #define xprintk(d,level,fmt,args...) \
...@@ -167,6 +170,12 @@ module_param (buflen, uint, S_IRUGO|S_IWUSR); ...@@ -167,6 +170,12 @@ module_param (buflen, uint, S_IRUGO|S_IWUSR);
module_param (qlen, uint, S_IRUGO|S_IWUSR); module_param (qlen, uint, S_IRUGO|S_IWUSR);
module_param (pattern, uint, S_IRUGO|S_IWUSR); module_param (pattern, uint, S_IRUGO|S_IWUSR);
/*
* if it's nonzero, autoresume says how many seconds to wait
* before trying to wake up the host after suspend.
*/
static unsigned autoresume = 0;
module_param (autoresume, uint, 0);
/* /*
* Normally the "loopback" configuration is second (index 1) so * Normally the "loopback" configuration is second (index 1) so
...@@ -224,7 +233,7 @@ device_desc = { ...@@ -224,7 +233,7 @@ device_desc = {
.bNumConfigurations = 2, .bNumConfigurations = 2,
}; };
static const struct usb_config_descriptor static struct usb_config_descriptor
source_sink_config = { source_sink_config = {
.bLength = sizeof source_sink_config, .bLength = sizeof source_sink_config,
.bDescriptorType = USB_DT_CONFIG, .bDescriptorType = USB_DT_CONFIG,
...@@ -237,7 +246,7 @@ source_sink_config = { ...@@ -237,7 +246,7 @@ source_sink_config = {
.bMaxPower = 1, /* self-powered */ .bMaxPower = 1, /* self-powered */
}; };
static const struct usb_config_descriptor static struct usb_config_descriptor
loopback_config = { loopback_config = {
.bLength = sizeof loopback_config, .bLength = sizeof loopback_config,
.bDescriptorType = USB_DT_CONFIG, .bDescriptorType = USB_DT_CONFIG,
...@@ -1060,6 +1069,19 @@ zero_disconnect (struct usb_gadget *gadget) ...@@ -1060,6 +1069,19 @@ zero_disconnect (struct usb_gadget *gadget)
*/ */
} }
static void
zero_autoresume (unsigned long _dev)
{
struct zero_dev *dev = (struct zero_dev *) _dev;
int status;
/* normally the host would be woken up for something
* more significant than just a timer firing...
*/
status = usb_gadget_wakeup (dev->gadget);
DBG (dev, "wakeup --> %d\n", status);
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void static void
...@@ -1072,6 +1094,7 @@ zero_unbind (struct usb_gadget *gadget) ...@@ -1072,6 +1094,7 @@ zero_unbind (struct usb_gadget *gadget)
/* we've already been disconnected ... no i/o is active */ /* we've already been disconnected ... no i/o is active */
if (dev->req) if (dev->req)
free_ep_req (gadget->ep0, dev->req); free_ep_req (gadget->ep0, dev->req);
del_timer_sync (&dev->resume);
kfree (dev); kfree (dev);
set_gadget_data (gadget, 0); set_gadget_data (gadget, 0);
} }
...@@ -1176,6 +1199,14 @@ zero_bind (struct usb_gadget *gadget) ...@@ -1176,6 +1199,14 @@ zero_bind (struct usb_gadget *gadget)
usb_gadget_set_selfpowered (gadget); usb_gadget_set_selfpowered (gadget);
init_timer (&dev->resume);
dev->resume.function = zero_autoresume;
dev->resume.data = (unsigned long) dev;
if (autoresume) {
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
gadget->ep0->driver_data = dev; gadget->ep0->driver_data = dev;
INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
...@@ -1193,6 +1224,33 @@ zero_bind (struct usb_gadget *gadget) ...@@ -1193,6 +1224,33 @@ zero_bind (struct usb_gadget *gadget)
return -ENOMEM; return -ENOMEM;
} }
/*-------------------------------------------------------------------------*/
static void
zero_suspend (struct usb_gadget *gadget)
{
struct zero_dev *dev = get_gadget_data (gadget);
if (gadget->speed == USB_SPEED_UNKNOWN)
return;
if (autoresume) {
mod_timer (&dev->resume, jiffies + (HZ * autoresume));
DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
} else
DBG (dev, "suspend\n");
}
static void
zero_resume (struct usb_gadget *gadget)
{
struct zero_dev *dev = get_gadget_data (gadget);
DBG (dev, "resume\n");
del_timer (&dev->resume);
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct usb_gadget_driver zero_driver = { static struct usb_gadget_driver zero_driver = {
...@@ -1208,6 +1266,9 @@ static struct usb_gadget_driver zero_driver = { ...@@ -1208,6 +1266,9 @@ static struct usb_gadget_driver zero_driver = {
.setup = zero_setup, .setup = zero_setup,
.disconnect = zero_disconnect, .disconnect = zero_disconnect,
.suspend = zero_suspend,
.resume = zero_resume,
.driver = { .driver = {
.name = (char *) shortname, .name = (char *) shortname,
// .shutdown = ... // .shutdown = ...
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment