]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
USB: gadget: gadget zero uses new suspend/resume hooks
authorDavid Brownell <dbrownell@users.sourceforge.net>
Thu, 19 Mar 2009 21:16:09 +0000 (14:16 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 24 Mar 2009 23:20:45 +0000 (16:20 -0700)
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>
drivers/usb/gadget/f_loopback.c
drivers/usb/gadget/f_sourcesink.c
drivers/usb/gadget/g_zero.h
drivers/usb/gadget/zero.c

index 83301bdcdd1ac41e16deebfe86d0fda58cd34d83..eb6ddfc20857741354ca959702dfbdae0f55103f 100644 (file)
@@ -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;
 
@@ -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;
index 6aca5c81414a15d858323b447ecf46331e99e9ef..bffe91d525f977ba2fa32dec574996e99f67ad72 100644 (file)
@@ -59,7 +59,6 @@ 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)
@@ -67,10 +66,6 @@ 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 ");
@@ -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)
 {
@@ -198,9 +178,6 @@ autoconf_fail:
                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 =
@@ -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);
 }
 
@@ -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)
@@ -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)
@@ -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;
 
index dd2f16ad5a888541da09071f83a7b963c59f962e..e84b3c47ed3c3da1d9676b5a32055eac8caad6fd 100644 (file)
@@ -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 */
index 20614dce8db9a81be569bc7de9a482b6267f0b78..2d772401b7ad4879762d118e8ff12231d103a912 100644 (file)
@@ -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 = {
@@ -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;
@@ -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);
@@ -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");