aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2014-09-29 10:20:35 -0400
committerFelipe Balbi <balbi@ti.com>2014-10-20 16:58:48 -0400
commitc92bae753722a0010f1cabfb242581e130378b9f (patch)
treed75ed6695fc8ba493fca5918809671973ce46b18
parentd7577b389233a74609841492feaf6a55967aa5c8 (diff)
usb: gadget: function: uvc: make sure to balance ep enable/disable
If a set_alt() to the same alternate setting that's already selected is received, functions are required to reset the interface state, this means we must disable all endpoints and reenable them again. This is also documented on our kdoc for struct usb_function * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may * initialize usb_ep.driver data at this time (when it is used). * Note that setting an interface to its current altsetting resets * interface state, and that all interfaces have a disabled state. Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/function/f_uvc.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index e126439e4b65..e00e8b79390a 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -286,11 +286,12 @@ static int
286uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) 286uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
287{ 287{
288 struct uvc_device *uvc = to_uvc(f); 288 struct uvc_device *uvc = to_uvc(f);
289 struct usb_composite_dev *cdev = f->config->cdev;
289 struct v4l2_event v4l2_event; 290 struct v4l2_event v4l2_event;
290 struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; 291 struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
291 int ret; 292 int ret;
292 293
293 INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); 294 INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
294 295
295 if (interface == uvc->control_intf) { 296 if (interface == uvc->control_intf) {
296 if (alt) 297 if (alt)
@@ -299,7 +300,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
299 if (uvc->state == UVC_STATE_DISCONNECTED) { 300 if (uvc->state == UVC_STATE_DISCONNECTED) {
300 memset(&v4l2_event, 0, sizeof(v4l2_event)); 301 memset(&v4l2_event, 0, sizeof(v4l2_event));
301 v4l2_event.type = UVC_EVENT_CONNECT; 302 v4l2_event.type = UVC_EVENT_CONNECT;
302 uvc_event->speed = f->config->cdev->gadget->speed; 303 uvc_event->speed = cdev->gadget->speed;
303 v4l2_event_queue(uvc->vdev, &v4l2_event); 304 v4l2_event_queue(uvc->vdev, &v4l2_event);
304 305
305 uvc->state = UVC_STATE_CONNECTED; 306 uvc->state = UVC_STATE_CONNECTED;
@@ -321,8 +322,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
321 if (uvc->state != UVC_STATE_STREAMING) 322 if (uvc->state != UVC_STATE_STREAMING)
322 return 0; 323 return 0;
323 324
324 if (uvc->video.ep) 325 if (uvc->video.ep) {
325 usb_ep_disable(uvc->video.ep); 326 usb_ep_disable(uvc->video.ep);
327 uvc->video.ep->driver_data = NULL;
328 }
326 329
327 memset(&v4l2_event, 0, sizeof(v4l2_event)); 330 memset(&v4l2_event, 0, sizeof(v4l2_event));
328 v4l2_event.type = UVC_EVENT_STREAMOFF; 331 v4l2_event.type = UVC_EVENT_STREAMOFF;
@@ -335,14 +338,22 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
335 if (uvc->state != UVC_STATE_CONNECTED) 338 if (uvc->state != UVC_STATE_CONNECTED)
336 return 0; 339 return 0;
337 340
338 if (uvc->video.ep) { 341 if (!uvc->video.ep)
339 ret = config_ep_by_speed(f->config->cdev->gadget, 342 return -EINVAL;
340 &(uvc->func), uvc->video.ep); 343
341 if (ret) 344 if (uvc->video.ep->driver_data) {
342 return ret; 345 INFO(cdev, "reset UVC\n");
343 usb_ep_enable(uvc->video.ep); 346 usb_ep_disable(uvc->video.ep);
347 uvc->video.ep->driver_data = NULL;
344 } 348 }
345 349
350 ret = config_ep_by_speed(f->config->cdev->gadget,
351 &(uvc->func), uvc->video.ep);
352 if (ret)
353 return ret;
354 usb_ep_enable(uvc->video.ep);
355 uvc->video.ep->driver_data = uvc;
356
346 memset(&v4l2_event, 0, sizeof(v4l2_event)); 357 memset(&v4l2_event, 0, sizeof(v4l2_event));
347 v4l2_event.type = UVC_EVENT_STREAMON; 358 v4l2_event.type = UVC_EVENT_STREAMON;
348 v4l2_event_queue(uvc->vdev, &v4l2_event); 359 v4l2_event_queue(uvc->vdev, &v4l2_event);