From: Greg Kroah-Hartman Date: Wed, 8 Dec 2021 12:59:08 +0000 (+0100) Subject: 5.10-stable patches X-Git-Tag: v4.4.295~85 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1ec43bba3ad3e3c7bad2eba4bb37523130b29e36;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: usb-gadget-uvc-fix-multiple-opens.patch --- diff --git a/queue-5.10/series b/queue-5.10/series new file mode 100644 index 00000000000..6c381b92610 --- /dev/null +++ b/queue-5.10/series @@ -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 index 00000000000..57a7b10b42a --- /dev/null +++ b/queue-5.10/usb-gadget-uvc-fix-multiple-opens.patch @@ -0,0 +1,144 @@ +From 72ee48ee8925446eaeda8e4ef3f2eb16b4a93d2a Mon Sep 17 00:00:00 2001 +From: Thomas Haemmerle +Date: Sun, 3 Oct 2021 22:13:55 +0200 +Subject: usb: gadget: uvc: fix multiple opens + +From: Thomas Haemmerle + +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 +Reviewed-by: Laurent Pinchart +Signed-off-by: Thomas Haemmerle +Signed-off-by: Michael Tretter +Signed-off-by: Michael Grzeschik +Acked-by: Felipe Balbi +Link: https://lore.kernel.org/r/20211003201355.24081-1-m.grzeschik@pengutronix.de +Cc: Dan Vacura +Signed-off-by: Greg Kroah-Hartman +--- + 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;