All of lore.kernel.org
 help / color / mirror / Atom feed
From: thomas.haemmerle@wolfvision.net
To: laurent.pinchart@ideasonboard.com
Cc: balbi@kernel.org, linux-usb@vger.kernel.org,
	m.tretter@pengutronix.de,
	Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
Subject: [PATCH] usb: gadget: uvc: fix multiple opens
Date: Thu,  5 Nov 2020 11:31:19 +0100	[thread overview]
Message-ID: <20201105103119.11419-1-thomas.haemmerle@wolfvision.net> (raw)

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

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
another process potentially is streaming.

Move activation of UVC function to subscription on UVC_EVENT_SETUP and
keep track of the number of subscribers (limited to 1) because there we
can guarantee for a userspace program utilizing UVC.
Extend the `struct uvc_file_handle` with member `bool setup_subscriber`
to tag it for a deactivation of the function.

With this a process is able to check capabilities of the v4l2 device
without deactivating the function for another process actually using the
device for UVC streaming.

Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
---
 drivers/usb/gadget/function/uvc.h      |  2 +
 drivers/usb/gadget/function/uvc_v4l2.c | 57 +++++++++++++++++++++-----
 2 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 23ee25383c1f..deeec2b80786 100644
--- 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;
+	unsigned int connections;
 
 	/* 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 connected;
 };
 
 #define to_uvc_file_handle(handle) \
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 4ca89eab6159..c0c2588b0efb 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -227,17 +227,60 @@ 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->connections >= 1))
+		return -EBUSY;
+
+	ret = v4l2_event_subscribe(fh, sub, 2, NULL);
+	if (ret < 0)
+		return ret;
+
+	if (sub->type == UVC_EVENT_SETUP) {
+		uvc->connections++;
+		handle->connected = true;
+		uvc_function_connect(uvc);
+	}
+
+	return 0;
+}
+
+static void uvc_v4l2_disable(struct uvc_device *uvc)
+{
+	if (--uvc->connections)
+		return;
+
+	uvc_function_disconnect(uvc);
+
+	mutex_lock(&uvc->video.mutex);
+	uvcg_video_enable(&uvc->video, 0);
+	uvcg_free_buffers(&uvc->video.queue);
+	mutex_unlock(&uvc->video.mutex);
 }
 
 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->connected) {
+		uvc_v4l2_disable(uvc);
+		handle->connected = false;
+	}
+
+	return 0;
 }
 
 static long
@@ -292,7 +335,6 @@ uvc_v4l2_open(struct file *file)
 	handle->device = &uvc->video;
 	file->private_data = &handle->vfh;
 
-	uvc_function_connect(uvc);
 	return 0;
 }
 
@@ -302,14 +344,9 @@ uvc_v4l2_release(struct file *file)
 	struct video_device *vdev = video_devdata(file);
 	struct uvc_device *uvc = video_get_drvdata(vdev);
 	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);
-	mutex_unlock(&video->mutex);
+	if (handle->connected)
+		uvc_v4l2_disable(uvc);
 
 	file->private_data = NULL;
 	v4l2_fh_del(&handle->vfh);
-- 
2.17.1


             reply	other threads:[~2020-11-05 10:31 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-05 10:31 thomas.haemmerle [this message]
2020-11-05 10:37 ` [PATCH] usb: gadget: uvc: fix multiple opens Greg KH
2020-11-09  8:59   ` [PATCH v2] " thomas.haemmerle
2020-11-10  8:25   ` thomas.haemmerle
2020-11-10  8:40     ` Greg KH
2020-11-10  9:56       ` Thomas Hämmerle
2020-11-10 10:06         ` Greg KH
2020-11-10 14:30           ` [PATCH v3] " thomas.haemmerle
2020-11-13 13:36             ` Greg KH
2020-11-16 15:48             ` Laurent Pinchart
2020-11-21 12:50               ` Thomas Hämmerle
2020-12-01 19:27                 ` [PATCH v4] " Thomas Haemmerle
2020-12-07  8:53                   ` Michael Tretter
2021-01-15 12:55                     ` Michael Tretter
2021-01-15 13:09                   ` Felipe Balbi
2021-02-11 15:04                     ` Michael Tretter
2021-10-03 20:13                     ` [RESEND PATCH " Michael Grzeschik
2021-10-04 23:53                       ` Laurent Pinchart
2021-10-05 10:59                         ` Greg KH
2021-10-05 11:06                           ` Felipe Balbi
2021-10-05 11:37                             ` Greg KH
2021-10-04 23:55                 ` [PATCH v3] " Laurent Pinchart
2020-11-10 10:31     ` [PATCH v2] " Hans Verkuil
2020-11-10 11:53       ` Thomas Hämmerle
2020-11-10 14:43         ` Hans Verkuil
2020-11-10 15:10           ` Thomas Hämmerle
2020-11-10 15:36             ` Hans Verkuil
2020-11-10 15:50               ` Thomas Hämmerle
2020-11-10 16:01                 ` Hans Verkuil
2020-11-16 15:31                   ` Laurent Pinchart
2020-11-16 15:48                     ` Hans Verkuil
2020-11-16 15:50                       ` Laurent Pinchart

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201105103119.11419-1-thomas.haemmerle@wolfvision.net \
    --to=thomas.haemmerle@wolfvision.net \
    --cc=balbi@kernel.org \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-usb@vger.kernel.org \
    --cc=m.tretter@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.