提交 49e7c420 编写于 作者: T Thomas Haemmerle 提交者: Zheng Zengkai

usb: gadget: uvc: fix multiple opens

stable inclusion
from stable-v5.10.85
commit 518c3f98e57a8081de3d8bc39d7bf9025326c3bd
bugzilla: 186032 https://gitee.com/openeuler/kernel/issues/I4QVI4

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=518c3f98e57a8081de3d8bc39d7bf9025326c3bd

--------------------------------

commit 72ee48ee 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: NMichael Tretter <m.tretter@pengutronix.de>
Reviewed-by: NLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: NThomas Haemmerle <thomas.haemmerle@wolfvision.net>
Signed-off-by: NMichael Tretter <m.tretter@pengutronix.de>
Signed-off-by: NMichael Grzeschik <m.grzeschik@pengutronix.de>
Acked-by: NFelipe 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: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NChen Jun <chenjun102@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 523b16e6
......@@ -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 usb_function *f)
struct uvc_file_handle {
struct v4l2_fh vfh;
struct uvc_video *device;
bool is_uvc_app_handle;
};
#define to_uvc_file_handle(handle) \
......
......@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册