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"); |
