]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Dec 2021 12:59:08 +0000 (13:59 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Dec 2021 12:59:08 +0000 (13:59 +0100)
added patches:
usb-gadget-uvc-fix-multiple-opens.patch

queue-5.10/series [new file with mode: 0644]
queue-5.10/usb-gadget-uvc-fix-multiple-opens.patch [new file with mode: 0644]

diff --git a/queue-5.10/series b/queue-5.10/series
new file mode 100644 (file)
index 0000000..6c381b9
--- /dev/null
@@ -0,0 +1 @@
+usb-gadget-uvc-fix-multiple-opens.patch
diff --git a/queue-5.10/usb-gadget-uvc-fix-multiple-opens.patch b/queue-5.10/usb-gadget-uvc-fix-multiple-opens.patch
new file mode 100644 (file)
index 0000000..57a7b10
--- /dev/null
@@ -0,0 +1,144 @@
+From 72ee48ee8925446eaeda8e4ef3f2eb16b4a93d2a Mon Sep 17 00:00:00 2001
+From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
+Date: Sun, 3 Oct 2021 22:13:55 +0200
+Subject: usb: gadget: uvc: fix multiple opens
+
+From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
+
+commit 72ee48ee8925446eaeda8e4ef3f2eb16b4a93d2a upstream.
+
+Currently, the UVC function is activated when open on the corresponding
+v4l2 device is called.  On another open the activation of the function
+fails since the deactivation counter in `usb_function_activate` equals
+0. However the error is not returned to userspace since the open of the
+v4l2 device is successful.
+
+On a close the function is deactivated (since deactivation counter still
+equals 0) and the video is disabled in `uvc_v4l2_release`, although the
+UVC application potentially is streaming.
+
+Move activation of UVC function to subscription on UVC_EVENT_SETUP
+because there we can guarantee for a userspace application utilizing
+UVC.  Block subscription on UVC_EVENT_SETUP while another application
+already is subscribed to it, indicated by `bool func_connected` in
+`struct uvc_device`.  Extend the `struct uvc_file_handle` with member
+`bool is_uvc_app_handle` to tag it as the handle used by the userspace
+UVC application.
+
+With this a process is able to check capabilities of the v4l2 device
+without deactivating the function for the actual UVC application.
+
+Reviewed-By: Michael Tretter <m.tretter@pengutronix.de>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
+Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Acked-by: Felipe Balbi <balbi@kernel.org>
+Link: https://lore.kernel.org/r/20211003201355.24081-1-m.grzeschik@pengutronix.de
+Cc: Dan Vacura <W36195@motorola.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/uvc.h      |    2 +
+ drivers/usb/gadget/function/uvc_v4l2.c |   49 ++++++++++++++++++++++++++++-----
+ 2 files changed, 44 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/gadget/function/uvc.h
++++ b/drivers/usb/gadget/function/uvc.h
+@@ -117,6 +117,7 @@ struct uvc_device {
+       enum uvc_state state;
+       struct usb_function func;
+       struct uvc_video video;
++      bool func_connected;
+       /* Descriptors */
+       struct {
+@@ -147,6 +148,7 @@ static inline struct uvc_device *to_uvc(
+ struct uvc_file_handle {
+       struct v4l2_fh vfh;
+       struct uvc_video *device;
++      bool is_uvc_app_handle;
+ };
+ #define to_uvc_file_handle(handle) \
+--- a/drivers/usb/gadget/function/uvc_v4l2.c
++++ b/drivers/usb/gadget/function/uvc_v4l2.c
+@@ -227,17 +227,55 @@ static int
+ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
+                        const struct v4l2_event_subscription *sub)
+ {
++      struct uvc_device *uvc = video_get_drvdata(fh->vdev);
++      struct uvc_file_handle *handle = to_uvc_file_handle(fh);
++      int ret;
++
+       if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
+               return -EINVAL;
+-      return v4l2_event_subscribe(fh, sub, 2, NULL);
++      if (sub->type == UVC_EVENT_SETUP && uvc->func_connected)
++              return -EBUSY;
++
++      ret = v4l2_event_subscribe(fh, sub, 2, NULL);
++      if (ret < 0)
++              return ret;
++
++      if (sub->type == UVC_EVENT_SETUP) {
++              uvc->func_connected = true;
++              handle->is_uvc_app_handle = true;
++              uvc_function_connect(uvc);
++      }
++
++      return 0;
++}
++
++static void uvc_v4l2_disable(struct uvc_device *uvc)
++{
++      uvc->func_connected = false;
++      uvc_function_disconnect(uvc);
++      uvcg_video_enable(&uvc->video, 0);
++      uvcg_free_buffers(&uvc->video.queue);
+ }
+ static int
+ uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+                          const struct v4l2_event_subscription *sub)
+ {
+-      return v4l2_event_unsubscribe(fh, sub);
++      struct uvc_device *uvc = video_get_drvdata(fh->vdev);
++      struct uvc_file_handle *handle = to_uvc_file_handle(fh);
++      int ret;
++
++      ret = v4l2_event_unsubscribe(fh, sub);
++      if (ret < 0)
++              return ret;
++
++      if (sub->type == UVC_EVENT_SETUP && handle->is_uvc_app_handle) {
++              uvc_v4l2_disable(uvc);
++              handle->is_uvc_app_handle = false;
++      }
++
++      return 0;
+ }
+ static long
+@@ -292,7 +330,6 @@ uvc_v4l2_open(struct file *file)
+       handle->device = &uvc->video;
+       file->private_data = &handle->vfh;
+-      uvc_function_connect(uvc);
+       return 0;
+ }
+@@ -304,11 +341,9 @@ uvc_v4l2_release(struct file *file)
+       struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
+       struct uvc_video *video = handle->device;
+-      uvc_function_disconnect(uvc);
+-
+       mutex_lock(&video->mutex);
+-      uvcg_video_enable(video, 0);
+-      uvcg_free_buffers(&video->queue);
++      if (handle->is_uvc_app_handle)
++              uvc_v4l2_disable(uvc);
+       mutex_unlock(&video->mutex);
+       file->private_data = NULL;