diff options
Diffstat (limited to 'drivers/usb/gadget/zero.c')
-rw-r--r-- | drivers/usb/gadget/zero.c | 78 |
1 files changed, 70 insertions, 8 deletions
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 361d9659ac48..2d772401b7ad 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c | |||
@@ -102,22 +102,32 @@ module_param(loopdefault, bool, S_IRUGO|S_IWUSR); | |||
102 | #ifndef CONFIG_USB_ZERO_HNPTEST | 102 | #ifndef CONFIG_USB_ZERO_HNPTEST |
103 | #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ | 103 | #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ |
104 | #define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */ | 104 | #define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */ |
105 | #define DEFAULT_AUTORESUME 0 | ||
105 | #else | 106 | #else |
106 | #define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */ | 107 | #define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */ |
107 | #define DRIVER_PRODUCT_NUM 0xbadd | 108 | #define DRIVER_PRODUCT_NUM 0xbadd |
109 | #define DEFAULT_AUTORESUME 5 | ||
108 | #endif | 110 | #endif |
109 | 111 | ||
112 | /* If the optional "autoresume" mode is enabled, it provides good | ||
113 | * functional coverage for the "USBCV" test harness from USB-IF. | ||
114 | * It's always set if OTG mode is enabled. | ||
115 | */ | ||
116 | unsigned autoresume = DEFAULT_AUTORESUME; | ||
117 | module_param(autoresume, uint, S_IRUGO); | ||
118 | MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup"); | ||
119 | |||
110 | /*-------------------------------------------------------------------------*/ | 120 | /*-------------------------------------------------------------------------*/ |
111 | 121 | ||
112 | static struct usb_device_descriptor device_desc = { | 122 | static struct usb_device_descriptor device_desc = { |
113 | .bLength = sizeof device_desc, | 123 | .bLength = sizeof device_desc, |
114 | .bDescriptorType = USB_DT_DEVICE, | 124 | .bDescriptorType = USB_DT_DEVICE, |
115 | 125 | ||
116 | .bcdUSB = __constant_cpu_to_le16(0x0200), | 126 | .bcdUSB = cpu_to_le16(0x0200), |
117 | .bDeviceClass = USB_CLASS_VENDOR_SPEC, | 127 | .bDeviceClass = USB_CLASS_VENDOR_SPEC, |
118 | 128 | ||
119 | .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), | 129 | .idVendor = cpu_to_le16(DRIVER_VENDOR_NUM), |
120 | .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), | 130 | .idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM), |
121 | .bNumConfigurations = 2, | 131 | .bNumConfigurations = 2, |
122 | }; | 132 | }; |
123 | 133 | ||
@@ -212,6 +222,47 @@ void disable_endpoints(struct usb_composite_dev *cdev, | |||
212 | 222 | ||
213 | /*-------------------------------------------------------------------------*/ | 223 | /*-------------------------------------------------------------------------*/ |
214 | 224 | ||
225 | static struct timer_list autoresume_timer; | ||
226 | |||
227 | static void zero_autoresume(unsigned long _c) | ||
228 | { | ||
229 | struct usb_composite_dev *cdev = (void *)_c; | ||
230 | struct usb_gadget *g = cdev->gadget; | ||
231 | |||
232 | /* unconfigured devices can't issue wakeups */ | ||
233 | if (!cdev->config) | ||
234 | return; | ||
235 | |||
236 | /* Normally the host would be woken up for something | ||
237 | * more significant than just a timer firing; likely | ||
238 | * because of some direct user request. | ||
239 | */ | ||
240 | if (g->speed != USB_SPEED_UNKNOWN) { | ||
241 | int status = usb_gadget_wakeup(g); | ||
242 | INFO(cdev, "%s --> %d\n", __func__, status); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static void zero_suspend(struct usb_composite_dev *cdev) | ||
247 | { | ||
248 | if (cdev->gadget->speed == USB_SPEED_UNKNOWN) | ||
249 | return; | ||
250 | |||
251 | if (autoresume) { | ||
252 | mod_timer(&autoresume_timer, jiffies + (HZ * autoresume)); | ||
253 | DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume); | ||
254 | } else | ||
255 | DBG(cdev, "%s\n", __func__); | ||
256 | } | ||
257 | |||
258 | static void zero_resume(struct usb_composite_dev *cdev) | ||
259 | { | ||
260 | DBG(cdev, "%s\n", __func__); | ||
261 | del_timer(&autoresume_timer); | ||
262 | } | ||
263 | |||
264 | /*-------------------------------------------------------------------------*/ | ||
265 | |||
215 | static int __init zero_bind(struct usb_composite_dev *cdev) | 266 | static int __init zero_bind(struct usb_composite_dev *cdev) |
216 | { | 267 | { |
217 | int gcnum; | 268 | int gcnum; |
@@ -239,17 +290,19 @@ static int __init zero_bind(struct usb_composite_dev *cdev) | |||
239 | strings_dev[STRING_SERIAL_IDX].id = id; | 290 | strings_dev[STRING_SERIAL_IDX].id = id; |
240 | device_desc.iSerialNumber = id; | 291 | device_desc.iSerialNumber = id; |
241 | 292 | ||
293 | setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); | ||
294 | |||
242 | /* Register primary, then secondary configuration. Note that | 295 | /* Register primary, then secondary configuration. Note that |
243 | * SH3 only allows one config... | 296 | * SH3 only allows one config... |
244 | */ | 297 | */ |
245 | if (loopdefault) { | 298 | if (loopdefault) { |
246 | loopback_add(cdev); | 299 | loopback_add(cdev, autoresume != 0); |
247 | if (!gadget_is_sh(gadget)) | 300 | if (!gadget_is_sh(gadget)) |
248 | sourcesink_add(cdev); | 301 | sourcesink_add(cdev, autoresume != 0); |
249 | } else { | 302 | } else { |
250 | sourcesink_add(cdev); | 303 | sourcesink_add(cdev, autoresume != 0); |
251 | if (!gadget_is_sh(gadget)) | 304 | if (!gadget_is_sh(gadget)) |
252 | loopback_add(cdev); | 305 | loopback_add(cdev, autoresume != 0); |
253 | } | 306 | } |
254 | 307 | ||
255 | gcnum = usb_gadget_controller_number(gadget); | 308 | gcnum = usb_gadget_controller_number(gadget); |
@@ -265,7 +318,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev) | |||
265 | */ | 318 | */ |
266 | pr_warning("%s: controller '%s' not recognized\n", | 319 | pr_warning("%s: controller '%s' not recognized\n", |
267 | longname, gadget->name); | 320 | longname, gadget->name); |
268 | device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); | 321 | device_desc.bcdDevice = cpu_to_le16(0x9999); |
269 | } | 322 | } |
270 | 323 | ||
271 | 324 | ||
@@ -278,11 +331,20 @@ static int __init zero_bind(struct usb_composite_dev *cdev) | |||
278 | return 0; | 331 | return 0; |
279 | } | 332 | } |
280 | 333 | ||
334 | static int zero_unbind(struct usb_composite_dev *cdev) | ||
335 | { | ||
336 | del_timer_sync(&autoresume_timer); | ||
337 | return 0; | ||
338 | } | ||
339 | |||
281 | static struct usb_composite_driver zero_driver = { | 340 | static struct usb_composite_driver zero_driver = { |
282 | .name = "zero", | 341 | .name = "zero", |
283 | .dev = &device_desc, | 342 | .dev = &device_desc, |
284 | .strings = dev_strings, | 343 | .strings = dev_strings, |
285 | .bind = zero_bind, | 344 | .bind = zero_bind, |
345 | .unbind = zero_unbind, | ||
346 | .suspend = zero_suspend, | ||
347 | .resume = zero_resume, | ||
286 | }; | 348 | }; |
287 | 349 | ||
288 | MODULE_AUTHOR("David Brownell"); | 350 | MODULE_AUTHOR("David Brownell"); |