summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function/f_uvc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/function/f_uvc.c')
-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
uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
{
struct uvc_device *uvc = to_uvc(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
int ret;
- INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
+ INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
if (interface == uvc->control_intf) {
if (alt)
@@ -299,7 +300,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (uvc->state == UVC_STATE_DISCONNECTED) {
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_CONNECT;
- uvc_event->speed = f->config->cdev->gadget->speed;
+ uvc_event->speed = cdev->gadget->speed;
v4l2_event_queue(uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_CONNECTED;
@@ -321,8 +322,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (uvc->state != UVC_STATE_STREAMING)
return 0;
- if (uvc->video.ep)
+ if (uvc->video.ep) {
usb_ep_disable(uvc->video.ep);
+ uvc->video.ep->driver_data = NULL;
+ }
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMOFF;
@@ -335,14 +338,22 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (uvc->state != UVC_STATE_CONNECTED)
return 0;
- if (uvc->video.ep) {
- ret = config_ep_by_speed(f->config->cdev->gadget,
- &(uvc->func), uvc->video.ep);
- if (ret)
- return ret;
- usb_ep_enable(uvc->video.ep);
+ if (!uvc->video.ep)
+ return -EINVAL;
+
+ if (uvc->video.ep->driver_data) {
+ INFO(cdev, "reset UVC\n");
+ usb_ep_disable(uvc->video.ep);
+ uvc->video.ep->driver_data = NULL;
}
+ ret = config_ep_by_speed(f->config->cdev->gadget,
+ &(uvc->func), uvc->video.ep);
+ if (ret)
+ return ret;
+ usb_ep_enable(uvc->video.ep);
+ uvc->video.ep->driver_data = uvc;
+
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(uvc->vdev, &v4l2_event);