#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 = {
/*-------------------------------------------------------------------------*/
+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;
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);
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");