Skip to content

Commit

Permalink
USB: gadget: gadget zero uses new suspend/resume hooks
Browse files Browse the repository at this point in the history
Use the new device-level suspend/resume hooks for Gadget Zero;
always enable them with the OTG test mode; and support remote
wakeup on both configurations even in non-OTG mode.

This ensures that both configurations can pass the USBCV remote
wakeup tests when the OTG test mode is enabled.  This changes
behavior by adding autoresume support to the loopback config
even in non-OTG mode; the test failure was that it didn't work
in OTG mode.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
David Brownell authored and Greg Kroah-Hartman committed Mar 24, 2009
1 parent 8942939 commit ab943a2
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 58 deletions.
6 changes: 5 additions & 1 deletion drivers/usb/gadget/f_loopback.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ static struct usb_configuration loopback_driver = {
* loopback_add - add a loopback testing configuration to a device
* @cdev: the device to support the loopback configuration
*/
int __init loopback_add(struct usb_composite_dev *cdev)
int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume)
{
int id;

Expand All @@ -372,6 +372,10 @@ int __init loopback_add(struct usb_composite_dev *cdev)
loopback_intf.iInterface = id;
loopback_driver.iConfiguration = id;

/* support autoresume for remote wakeup testing */
if (autoresume)
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;

/* support OTG systems */
if (gadget_is_otg(cdev->gadget)) {
loopback_driver.descriptors = otg_desc;
Expand Down
52 changes: 1 addition & 51 deletions drivers/usb/gadget/f_sourcesink.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,13 @@ struct f_sourcesink {

struct usb_ep *in_ep;
struct usb_ep *out_ep;
struct timer_list resume;
};

static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
{
return container_of(f, struct f_sourcesink, function);
}

static unsigned autoresume;
module_param(autoresume, uint, 0);
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");

static unsigned pattern;
module_param(pattern, uint, 0);
MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 ");
Expand Down Expand Up @@ -155,21 +150,6 @@ static struct usb_gadget_strings *sourcesink_strings[] = {

/*-------------------------------------------------------------------------*/

static void sourcesink_autoresume(unsigned long _c)
{
struct usb_composite_dev *cdev = (void *)_c;
struct usb_gadget *g = cdev->gadget;

/* Normally the host would be woken up for something
* more significant than just a timer firing; likely
* because of some direct user request.
*/
if (g->speed != USB_SPEED_UNKNOWN) {
int status = usb_gadget_wakeup(g);
DBG(cdev, "%s --> %d\n", __func__, status);
}
}

static int __init
sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
{
Expand Down Expand Up @@ -198,9 +178,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
goto autoconf_fail;
ss->out_ep->driver_data = cdev; /* claim */

setup_timer(&ss->resume, sourcesink_autoresume,
(unsigned long) c->cdev);

/* support high speed hardware */
if (gadget_is_dualspeed(c->cdev->gadget)) {
hs_source_desc.bEndpointAddress =
Expand Down Expand Up @@ -359,7 +336,6 @@ static void disable_source_sink(struct f_sourcesink *ss)

cdev = ss->function.config->cdev;
disable_endpoints(cdev, ss->in_ep, ss->out_ep);
del_timer(&ss->resume);
VDBG(cdev, "%s disabled\n", ss->function.name);
}

Expand Down Expand Up @@ -426,30 +402,6 @@ static void sourcesink_disable(struct usb_function *f)
disable_source_sink(ss);
}

static void sourcesink_suspend(struct usb_function *f)
{
struct f_sourcesink *ss = func_to_ss(f);
struct usb_composite_dev *cdev = f->config->cdev;

if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
return;

if (autoresume) {
mod_timer(&ss->resume, jiffies + (HZ * autoresume));
DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
} else
DBG(cdev, "%s\n", __func__);
}

static void sourcesink_resume(struct usb_function *f)
{
struct f_sourcesink *ss = func_to_ss(f);
struct usb_composite_dev *cdev = f->config->cdev;

DBG(cdev, "%s\n", __func__);
del_timer(&ss->resume);
}

/*-------------------------------------------------------------------------*/

static int __init sourcesink_bind_config(struct usb_configuration *c)
Expand All @@ -467,8 +419,6 @@ static int __init sourcesink_bind_config(struct usb_configuration *c)
ss->function.unbind = sourcesink_unbind;
ss->function.set_alt = sourcesink_set_alt;
ss->function.disable = sourcesink_disable;
ss->function.suspend = sourcesink_suspend;
ss->function.resume = sourcesink_resume;

status = usb_add_function(c, &ss->function);
if (status)
Expand Down Expand Up @@ -559,7 +509,7 @@ static struct usb_configuration sourcesink_driver = {
* sourcesink_add - add a source/sink testing configuration to a device
* @cdev: the device to support the configuration
*/
int __init sourcesink_add(struct usb_composite_dev *cdev)
int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)
{
int id;

Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/gadget/g_zero.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void disable_endpoints(struct usb_composite_dev *cdev,
struct usb_ep *in, struct usb_ep *out);

/* configuration-specific linkup */
int sourcesink_add(struct usb_composite_dev *cdev);
int loopback_add(struct usb_composite_dev *cdev);
int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume);
int loopback_add(struct usb_composite_dev *cdev, bool autoresume);

#endif /* __G_ZERO_H */
70 changes: 66 additions & 4 deletions drivers/usb/gadget/zero.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,21 @@ module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
#ifndef CONFIG_USB_ZERO_HNPTEST
#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
#define DEFAULT_AUTORESUME 0
#else
#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
#define DRIVER_PRODUCT_NUM 0xbadd
#define DEFAULT_AUTORESUME 5
#endif

/* If the optional "autoresume" mode is enabled, it provides good
* functional coverage for the "USBCV" test harness from USB-IF.
* It's always set if OTG mode is enabled.
*/
unsigned autoresume = DEFAULT_AUTORESUME;
module_param(autoresume, uint, S_IRUGO);
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");

/*-------------------------------------------------------------------------*/

static struct usb_device_descriptor device_desc = {
Expand Down Expand Up @@ -212,6 +222,47 @@ void disable_endpoints(struct usb_composite_dev *cdev,

/*-------------------------------------------------------------------------*/

static struct timer_list autoresume_timer;

static void zero_autoresume(unsigned long _c)
{
struct usb_composite_dev *cdev = (void *)_c;
struct usb_gadget *g = cdev->gadget;

/* unconfigured devices can't issue wakeups */
if (!cdev->config)
return;

/* Normally the host would be woken up for something
* more significant than just a timer firing; likely
* because of some direct user request.
*/
if (g->speed != USB_SPEED_UNKNOWN) {
int status = usb_gadget_wakeup(g);
INFO(cdev, "%s --> %d\n", __func__, status);
}
}

static void zero_suspend(struct usb_composite_dev *cdev)
{
if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
return;

if (autoresume) {
mod_timer(&autoresume_timer, jiffies + (HZ * autoresume));
DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
} else
DBG(cdev, "%s\n", __func__);
}

static void zero_resume(struct usb_composite_dev *cdev)
{
DBG(cdev, "%s\n", __func__);
del_timer(&autoresume_timer);
}

/*-------------------------------------------------------------------------*/

static int __init zero_bind(struct usb_composite_dev *cdev)
{
int gcnum;
Expand Down Expand Up @@ -239,17 +290,19 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
strings_dev[STRING_SERIAL_IDX].id = id;
device_desc.iSerialNumber = id;

setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);

/* Register primary, then secondary configuration. Note that
* SH3 only allows one config...
*/
if (loopdefault) {
loopback_add(cdev);
loopback_add(cdev, autoresume != 0);
if (!gadget_is_sh(gadget))
sourcesink_add(cdev);
sourcesink_add(cdev, autoresume != 0);
} else {
sourcesink_add(cdev);
sourcesink_add(cdev, autoresume != 0);
if (!gadget_is_sh(gadget))
loopback_add(cdev);
loopback_add(cdev, autoresume != 0);
}

gcnum = usb_gadget_controller_number(gadget);
Expand Down Expand Up @@ -278,11 +331,20 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
return 0;
}

static int zero_unbind(struct usb_composite_dev *cdev)
{
del_timer_sync(&autoresume_timer);
return 0;
}

static struct usb_composite_driver zero_driver = {
.name = "zero",
.dev = &device_desc,
.strings = dev_strings,
.bind = zero_bind,
.unbind = zero_unbind,
.suspend = zero_suspend,
.resume = zero_resume,
};

MODULE_AUTHOR("David Brownell");
Expand Down

0 comments on commit ab943a2

Please sign in to comment.