All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v10 00/21] Fix v4l2-compliance errors
@ 2021-06-18 12:29 Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 01/21] media: v4l2-ioctl: Fix check_ext_ctrls Ricardo Ribalda
                   ` (20 more replies)
  0 siblings, 21 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

*v4l2-compliance -m /dev/media0 -a -f
Total for uvcvideo device /dev/media0: 8, Succeeded: 6, Failed: 2, Warnings: 0
Total for uvcvideo device /dev/video0: 54, Succeeded: 50, Failed: 4, Warnings: 2
Total for uvcvideo device /dev/video1: 46, Succeeded: 46, Failed: 0, Warnings: 0
Grand Total for uvcvideo device /dev/media0: 108, Succeeded: 102,
Failed: 6, Warnings: 2

After fixing all of them we go down to:

Total for uvcvideo device /dev/media0: 8, Succeeded: 8, Failed: 0, Warnings: 0
Total for uvcvideo device /dev/video0: 54, Succeeded: 54, Failed: 0, Warnings: 0
Total for uvcvideo device /dev/video1: 46, Succeeded: 46, Failed: 0, Warnings: 0
Grand Total for uvcvideo device /dev/media0: 108, Succeeded: 108,
Failed: 0, Warnings: 0

YES, NO MORE WARNINGS :)

Note that we depend on:

https://patchwork.linuxtv.org/project/linux-media/patch/20210317143453.483470-1-ribalda@chromium.org/

With Hans patch we can also pass v4l2-compliance -s.


Changelog from v9 (Thanks to Hans and Laurent)

- Convert struct uvc_control_class into u32
- Rename uvc_control_class into uvc_control_classes
- Order of variables
- Do not duplicate error messages
- Move "Return -EACCES to inactive control" to the end

Hans Verkuil (4):
  uvcvideo: uvc_ctrl_is_accessible: check for INACTIVE
  uvcvideo: improve error handling in uvc_query_ctrl()
  uvcvideo: don't spam the log in uvc_ctrl_restore_values()
  uvc: use vb2 ioctl and fop helpers

Ricardo Ribalda (17):
  media: v4l2-ioctl: Fix check_ext_ctrls
  media: pvrusb2: Do not check for V4L2_CTRL_WHICH_DEF_VAL
  media: uvcvideo: Do not check for V4L2_CTRL_WHICH_DEF_VAL
  media: v4l2-ioctl: S_CTRL output the right value
  media: uvcvideo: Remove s_ctrl and g_ctrl
  media: uvcvideo: Set capability in s_param
  media: uvcvideo: Return -EIO for control errors
  media: uvcvideo: refactor __uvc_ctrl_add_mapping
  media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS
  media: uvcvideo: Use dev->name for querycap()
  media: uvcvideo: Set unique vdev name based in type
  media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE
  media: uvcvideo: Use control names from framework
  media: uvcvideo: Check controls flags before accessing them
  media: uvcvideo: Set error_idx during ctrl_commit errors
  media: docs: Document the behaviour of uvcvideo driver
  media: uvcvideo: Return -EACCES to inactive controls

 .../userspace-api/media/v4l/vidioc-g-ctrl.rst |   3 +
 .../media/v4l/vidioc-g-ext-ctrls.rst          |   3 +
 drivers/media/usb/pvrusb2/pvrusb2-v4l2.c      |   4 -
 drivers/media/usb/uvc/uvc_ctrl.c              | 339 +++++++++++----
 drivers/media/usb/uvc/uvc_driver.c            |  22 +-
 drivers/media/usb/uvc/uvc_metadata.c          |  10 +-
 drivers/media/usb/uvc/uvc_queue.c             | 143 -------
 drivers/media/usb/uvc/uvc_v4l2.c              | 389 +++---------------
 drivers/media/usb/uvc/uvc_video.c             |  43 +-
 drivers/media/usb/uvc/uvcvideo.h              |  50 +--
 drivers/media/v4l2-core/v4l2-ioctl.c          |  67 +--
 11 files changed, 428 insertions(+), 645 deletions(-)

-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v10 01/21] media: v4l2-ioctl: Fix check_ext_ctrls
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 02/21] media: pvrusb2: Do not check for V4L2_CTRL_WHICH_DEF_VAL Ricardo Ribalda
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda, stable

Drivers that do not use the ctrl-framework use this function instead.

Fix the following issues:

- Do not check for multiple classes when getting the DEF_VAL.
- Return -EINVAL for request_api calls
- Default value cannot be changed, return EINVAL as soon as possible.
- Return the right error_idx
[If an error is found when validating the list of controls passed with
VIDIOC_G_EXT_CTRLS, then error_idx shall be set to ctrls->count to
indicate to userspace that no actual hardware was touched.
It would have been much nicer of course if error_idx could point to the
control index that failed the validation, but sadly that's not how the
API was designed.]

Fixes v4l2-compliance:
Control ioctls (Input 0):
        warn: v4l2-test-controls.cpp(834): error_idx should be equal to count
        warn: v4l2-test-controls.cpp(855): error_idx should be equal to count
		fail: v4l2-test-controls.cpp(813): doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls)
	test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
Buffer ioctls (Input 0):
		fail: v4l2-test-buffers.cpp(1994): ret != EINVAL && ret != EBADR && ret != ENOTTY
	test Requests: FAIL

Cc: stable@vger.kernel.org
Fixes: 6fa6f831f095 ("media: v4l2-ctrls: add core request support")
Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ioctl.c | 60 ++++++++++++++++++----------
 1 file changed, 39 insertions(+), 21 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 2673f51aafa4..8b3977a85b23 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -869,7 +869,7 @@ static void v4l_print_default(const void *arg, bool write_only)
 	pr_cont("driver-specific ioctl\n");
 }
 
-static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
+static bool check_ext_ctrls(struct v4l2_ext_controls *c, unsigned long ioctl)
 {
 	__u32 i;
 
@@ -878,23 +878,41 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
 	for (i = 0; i < c->count; i++)
 		c->controls[i].reserved2[0] = 0;
 
-	/* V4L2_CID_PRIVATE_BASE cannot be used as control class
-	   when using extended controls.
-	   Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
-	   is it allowed for backwards compatibility.
-	 */
-	if (!allow_priv && c->which == V4L2_CID_PRIVATE_BASE)
-		return 0;
-	if (!c->which)
-		return 1;
+	switch (c->which) {
+	case V4L2_CID_PRIVATE_BASE:
+		/*
+		 * V4L2_CID_PRIVATE_BASE cannot be used as control class
+		 * when using extended controls.
+		 * Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
+		 * is it allowed for backwards compatibility.
+		 */
+		if (ioctl == VIDIOC_G_CTRL || ioctl == VIDIOC_S_CTRL)
+			return false;
+		break;
+	case V4L2_CTRL_WHICH_DEF_VAL:
+		/* Default value cannot be changed */
+		if (ioctl == VIDIOC_S_EXT_CTRLS ||
+		    ioctl == VIDIOC_TRY_EXT_CTRLS) {
+			c->error_idx = c->count;
+			return false;
+		}
+		return true;
+	case V4L2_CTRL_WHICH_CUR_VAL:
+		return true;
+	case V4L2_CTRL_WHICH_REQUEST_VAL:
+		c->error_idx = c->count;
+		return false;
+	}
+
 	/* Check that all controls are from the same control class. */
 	for (i = 0; i < c->count; i++) {
 		if (V4L2_CTRL_ID2WHICH(c->controls[i].id) != c->which) {
-			c->error_idx = i;
-			return 0;
+			c->error_idx = ioctl == VIDIOC_TRY_EXT_CTRLS ? i :
+								      c->count;
+			return false;
 		}
 	}
-	return 1;
+	return true;
 }
 
 static int check_fmt(struct file *file, enum v4l2_buf_type type)
@@ -2187,7 +2205,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops,
 	ctrls.controls = &ctrl;
 	ctrl.id = p->id;
 	ctrl.value = p->value;
-	if (check_ext_ctrls(&ctrls, 1)) {
+	if (check_ext_ctrls(&ctrls, VIDIOC_G_CTRL)) {
 		int ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls);
 
 		if (ret == 0)
@@ -2221,7 +2239,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
 	ctrls.controls = &ctrl;
 	ctrl.id = p->id;
 	ctrl.value = p->value;
-	if (check_ext_ctrls(&ctrls, 1))
+	if (check_ext_ctrls(&ctrls, VIDIOC_S_CTRL))
 		return ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
 	return -EINVAL;
 }
@@ -2243,8 +2261,8 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops,
 					vfd, vfd->v4l2_dev->mdev, p);
 	if (ops->vidioc_g_ext_ctrls == NULL)
 		return -ENOTTY;
-	return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) :
-					-EINVAL;
+	return check_ext_ctrls(p, VIDIOC_G_EXT_CTRLS) ?
+				ops->vidioc_g_ext_ctrls(file, fh, p) : -EINVAL;
 }
 
 static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
@@ -2264,8 +2282,8 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
 					vfd, vfd->v4l2_dev->mdev, p);
 	if (ops->vidioc_s_ext_ctrls == NULL)
 		return -ENOTTY;
-	return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) :
-					-EINVAL;
+	return check_ext_ctrls(p, VIDIOC_S_EXT_CTRLS) ?
+				ops->vidioc_s_ext_ctrls(file, fh, p) : -EINVAL;
 }
 
 static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops,
@@ -2285,8 +2303,8 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops,
 					  vfd, vfd->v4l2_dev->mdev, p);
 	if (ops->vidioc_try_ext_ctrls == NULL)
 		return -ENOTTY;
-	return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) :
-					-EINVAL;
+	return check_ext_ctrls(p, VIDIOC_TRY_EXT_CTRLS) ?
+			ops->vidioc_try_ext_ctrls(file, fh, p) : -EINVAL;
 }
 
 /*
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 02/21] media: pvrusb2: Do not check for V4L2_CTRL_WHICH_DEF_VAL
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 01/21] media: v4l2-ioctl: Fix check_ext_ctrls Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 03/21] media: uvcvideo: " Ricardo Ribalda
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda, Mike Isely

The framework already checks for us if V4L2_CTRL_WHICH_DEF_VAL is
written.

Cc: Mike Isely <isely@pobox.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index 9657c1883311..c04ab7258d64 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -640,10 +640,6 @@ static int pvr2_s_ext_ctrls(struct file *file, void *priv,
 	unsigned int idx;
 	int ret;
 
-	/* Default value cannot be changed */
-	if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL)
-		return -EINVAL;
-
 	ret = 0;
 	for (idx = 0; idx < ctls->count; idx++) {
 		ctrl = ctls->controls + idx;
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 03/21] media: uvcvideo: Do not check for V4L2_CTRL_WHICH_DEF_VAL
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 01/21] media: v4l2-ioctl: Fix check_ext_ctrls Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 02/21] media: pvrusb2: Do not check for V4L2_CTRL_WHICH_DEF_VAL Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 04/21] media: v4l2-ioctl: S_CTRL output the right value Ricardo Ribalda
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

The framework already checks for us if V4L2_CTRL_WHICH_DEF_VAL is
written.

Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_v4l2.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 252136cc885c..47b0e3224205 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1089,10 +1089,6 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
 	unsigned int i;
 	int ret;
 
-	/* Default value cannot be changed */
-	if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL)
-		return -EINVAL;
-
 	ret = uvc_ctrl_begin(chain);
 	if (ret < 0)
 		return ret;
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 04/21] media: v4l2-ioctl: S_CTRL output the right value
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (2 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 03/21] media: uvcvideo: " Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 05/21] media: uvcvideo: Remove s_ctrl and g_ctrl Ricardo Ribalda
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

If the driver does not implement s_ctrl, but it does implement
s_ext_ctrls, we convert the call.

When that happens we have also to convert back the response from
s_ext_ctrls.

Fixes v4l2_compliance:
Control ioctls (Input 0):
		fail: v4l2-test-controls.cpp(411): returned control value out of range
		fail: v4l2-test-controls.cpp(507): invalid control 00980900
	test VIDIOC_G/S_CTRL: FAIL

Fixes: 35ea11ff8471 ("V4L/DVB (8430): videodev: move some functions from v4l2-dev.h to v4l2-common.h or v4l2-ioctl.h")
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ioctl.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 8b3977a85b23..1a305aeab2f5 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -2224,6 +2224,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
 		test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL;
 	struct v4l2_ext_controls ctrls;
 	struct v4l2_ext_control ctrl;
+	int ret;
 
 	if (vfh && vfh->ctrl_handler)
 		return v4l2_s_ctrl(vfh, vfh->ctrl_handler, p);
@@ -2239,9 +2240,11 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
 	ctrls.controls = &ctrl;
 	ctrl.id = p->id;
 	ctrl.value = p->value;
-	if (check_ext_ctrls(&ctrls, VIDIOC_S_CTRL))
-		return ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
-	return -EINVAL;
+	if (!check_ext_ctrls(&ctrls, VIDIOC_S_CTRL))
+		return -EINVAL;
+	ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
+	p->value = ctrl.value;
+	return ret;
 }
 
 static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops,
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 05/21] media: uvcvideo: Remove s_ctrl and g_ctrl
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (3 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 04/21] media: v4l2-ioctl: S_CTRL output the right value Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 06/21] media: uvcvideo: Set capability in s_param Ricardo Ribalda
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

If we do not implement these callbacks the framework will call the
ext_ctrl callbaks instead, which are a superset of this functions.

Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_v4l2.c | 56 --------------------------------
 1 file changed, 56 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 47b0e3224205..ac98869d5a05 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -983,60 +983,6 @@ static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
 	return 0;
 }
 
-static int uvc_ioctl_g_ctrl(struct file *file, void *fh,
-			    struct v4l2_control *ctrl)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_video_chain *chain = handle->chain;
-	struct v4l2_ext_control xctrl;
-	int ret;
-
-	memset(&xctrl, 0, sizeof(xctrl));
-	xctrl.id = ctrl->id;
-
-	ret = uvc_ctrl_begin(chain);
-	if (ret < 0)
-		return ret;
-
-	ret = uvc_ctrl_get(chain, &xctrl);
-	uvc_ctrl_rollback(handle);
-	if (ret < 0)
-		return ret;
-
-	ctrl->value = xctrl.value;
-	return 0;
-}
-
-static int uvc_ioctl_s_ctrl(struct file *file, void *fh,
-			    struct v4l2_control *ctrl)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_video_chain *chain = handle->chain;
-	struct v4l2_ext_control xctrl;
-	int ret;
-
-	memset(&xctrl, 0, sizeof(xctrl));
-	xctrl.id = ctrl->id;
-	xctrl.value = ctrl->value;
-
-	ret = uvc_ctrl_begin(chain);
-	if (ret < 0)
-		return ret;
-
-	ret = uvc_ctrl_set(handle, &xctrl);
-	if (ret < 0) {
-		uvc_ctrl_rollback(handle);
-		return ret;
-	}
-
-	ret = uvc_ctrl_commit(handle, &xctrl, 1);
-	if (ret < 0)
-		return ret;
-
-	ctrl->value = xctrl.value;
-	return 0;
-}
-
 static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
 				 struct v4l2_ext_controls *ctrls)
 {
@@ -1522,8 +1468,6 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = {
 	.vidioc_s_input = uvc_ioctl_s_input,
 	.vidioc_queryctrl = uvc_ioctl_queryctrl,
 	.vidioc_query_ext_ctrl = uvc_ioctl_query_ext_ctrl,
-	.vidioc_g_ctrl = uvc_ioctl_g_ctrl,
-	.vidioc_s_ctrl = uvc_ioctl_s_ctrl,
 	.vidioc_g_ext_ctrls = uvc_ioctl_g_ext_ctrls,
 	.vidioc_s_ext_ctrls = uvc_ioctl_s_ext_ctrls,
 	.vidioc_try_ext_ctrls = uvc_ioctl_try_ext_ctrls,
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 06/21] media: uvcvideo: Set capability in s_param
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (4 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 05/21] media: uvcvideo: Remove s_ctrl and g_ctrl Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 07/21] media: uvcvideo: Return -EIO for control errors Ricardo Ribalda
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

Fixes v4l2-compliance:

Format ioctls (Input 0):
                warn: v4l2-test-formats.cpp(1339): S_PARM is supported but doesn't report V4L2_CAP_TIMEPERFRAME
                fail: v4l2-test-formats.cpp(1241): node->has_frmintervals && !cap->capability

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_v4l2.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index ac98869d5a05..1eeeb00280e4 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -472,10 +472,13 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
 	uvc_simplify_fraction(&timeperframe.numerator,
 		&timeperframe.denominator, 8, 333);
 
-	if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		parm->parm.capture.timeperframe = timeperframe;
-	else
+		parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	} else {
 		parm->parm.output.timeperframe = timeperframe;
+		parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+	}
 
 	return 0;
 }
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 07/21] media: uvcvideo: Return -EIO for control errors
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (5 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 06/21] media: uvcvideo: Set capability in s_param Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 08/21] media: uvcvideo: refactor __uvc_ctrl_add_mapping Ricardo Ribalda
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

The device is doing something unspected with the control. Either because
the protocol is not properly implemented or there has been a HW error.

Fixes v4l2-compliance:

Control ioctls (Input 0):
                fail: v4l2-test-controls.cpp(448): s_ctrl returned an error (22)
        test VIDIOC_G/S_CTRL: FAIL
                fail: v4l2-test-controls.cpp(698): s_ext_ctrls returned an error (22)
        test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_video.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index a777b389a66e..daba5fe352ea 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -115,6 +115,11 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
 	case 5: /* Invalid unit */
 	case 6: /* Invalid control */
 	case 7: /* Invalid Request */
+		/*
+		 * The firmware has not properly implemented
+		 * the control or there has been a HW error.
+		 */
+		return -EIO;
 	case 8: /* Invalid value within range */
 		return -EINVAL;
 	default: /* reserved or unknown */
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 08/21] media: uvcvideo: refactor __uvc_ctrl_add_mapping
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (6 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 07/21] media: uvcvideo: Return -EIO for control errors Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 09/21] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS Ricardo Ribalda
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

Pass the chain instead of the device. We want to keep the reference to
the chain that controls belong to.

We need to delay the initialization of the controls after the chains
have been initialized.

This is a cleanup needed for the next patches.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_ctrl.c   | 41 ++++++++++++++++++++----------
 drivers/media/usb/uvc/uvc_driver.c |  8 +++---
 2 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index b3dde98499f4..b75da65115ef 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2057,7 +2057,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
 /*
  * Add a control mapping to a given control.
  */
-static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
+static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 	struct uvc_control *ctrl, const struct uvc_control_mapping *mapping)
 {
 	struct uvc_control_mapping *map;
@@ -2086,7 +2086,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
 		map->set = uvc_set_le_value;
 
 	list_add_tail(&map->list, &ctrl->info.mappings);
-	uvc_dbg(dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n",
+	uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n",
 		map->name, ctrl->info.entity, ctrl->info.selector);
 
 	return 0;
@@ -2168,7 +2168,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 		goto done;
 	}
 
-	ret = __uvc_ctrl_add_mapping(dev, ctrl, mapping);
+	ret = __uvc_ctrl_add_mapping(chain, ctrl, mapping);
 	if (ret < 0)
 		atomic_dec(&dev->nmappings);
 
@@ -2244,7 +2244,8 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev,
  * Add control information and hardcoded stock control mappings to the given
  * device.
  */
-static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
+static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
+			       struct uvc_control *ctrl)
 {
 	const struct uvc_control_info *info = uvc_ctrls;
 	const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls);
@@ -2263,14 +2264,14 @@ static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
 	for (; info < iend; ++info) {
 		if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
 		    ctrl->index == info->index) {
-			uvc_ctrl_add_info(dev, ctrl, info);
+			uvc_ctrl_add_info(chain->dev, ctrl, info);
 			/*
 			 * Retrieve control flags from the device. Ignore errors
 			 * and work with default flag values from the uvc_ctrl
 			 * array when the device doesn't properly implement
 			 * GET_INFO on standard controls.
 			 */
-			uvc_ctrl_get_flags(dev, ctrl, &ctrl->info);
+			uvc_ctrl_get_flags(chain->dev, ctrl, &ctrl->info);
 			break;
 		 }
 	}
@@ -2281,22 +2282,20 @@ static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
 	for (; mapping < mend; ++mapping) {
 		if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
 		    ctrl->info.selector == mapping->selector)
-			__uvc_ctrl_add_mapping(dev, ctrl, mapping);
+			__uvc_ctrl_add_mapping(chain, ctrl, mapping);
 	}
 }
 
 /*
  * Initialize device controls.
  */
-int uvc_ctrl_init_device(struct uvc_device *dev)
+static int uvc_ctrl_init_chain(struct uvc_video_chain *chain)
 {
 	struct uvc_entity *entity;
 	unsigned int i;
 
-	INIT_WORK(&dev->async_ctrl.work, uvc_ctrl_status_event_work);
-
 	/* Walk the entities list and instantiate controls */
-	list_for_each_entry(entity, &dev->entities, list) {
+	list_for_each_entry(entity, &chain->entities, chain) {
 		struct uvc_control *ctrl;
 		unsigned int bControlSize = 0, ncontrols;
 		u8 *bmControls = NULL;
@@ -2316,7 +2315,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 		}
 
 		/* Remove bogus/blacklisted controls */
-		uvc_ctrl_prune_entity(dev, entity);
+		uvc_ctrl_prune_entity(chain->dev, entity);
 
 		/* Count supported controls and allocate the controls array */
 		ncontrols = memweight(bmControls, bControlSize);
@@ -2338,7 +2337,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 			ctrl->entity = entity;
 			ctrl->index = i;
 
-			uvc_ctrl_init_ctrl(dev, ctrl);
+			uvc_ctrl_init_ctrl(chain, ctrl);
 			ctrl++;
 		}
 	}
@@ -2346,6 +2345,22 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 	return 0;
 }
 
+int uvc_ctrl_init_device(struct uvc_device *dev)
+{
+	struct uvc_video_chain *chain;
+	int ret;
+
+	INIT_WORK(&dev->async_ctrl.work, uvc_ctrl_status_event_work);
+
+	list_for_each_entry(chain, &dev->chains, list) {
+		ret = uvc_ctrl_init_chain(chain);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 /*
  * Cleanup device controls.
  */
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 9a791d8ef200..14b60792ffab 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2455,14 +2455,14 @@ static int uvc_probe(struct usb_interface *intf,
 	if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
 		goto error;
 
-	/* Initialize controls. */
-	if (uvc_ctrl_init_device(dev) < 0)
-		goto error;
-
 	/* Scan the device for video chains. */
 	if (uvc_scan_device(dev) < 0)
 		goto error;
 
+	/* Initialize controls. */
+	if (uvc_ctrl_init_device(dev) < 0)
+		goto error;
+
 	/* Register video device nodes. */
 	if (uvc_register_chains(dev) < 0)
 		goto error;
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 09/21] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (7 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 08/21] media: uvcvideo: refactor __uvc_ctrl_add_mapping Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 10/21] media: uvcvideo: Use dev->name for querycap() Ricardo Ribalda
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

Create all the class controls for the device defined controls.

Fixes v4l2-compliance:
Control ioctls (Input 0):
		fail: v4l2-test-controls.cpp(216): missing control class for class 00980000
		fail: v4l2-test-controls.cpp(216): missing control tclass for class 009a0000
	test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL

Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 90 ++++++++++++++++++++++++++++++++
 drivers/media/usb/uvc/uvcvideo.h |  1 +
 2 files changed, 91 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index b75da65115ef..7c1d71782281 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -357,6 +357,11 @@ static const struct uvc_control_info uvc_ctrls[] = {
 	},
 };
 
+static const u32 uvc_control_classes[] = {
+	V4L2_CID_CAMERA_CLASS,
+	V4L2_CID_USER_CLASS,
+};
+
 static const struct uvc_menu_info power_line_frequency_controls[] = {
 	{ 0, "Disabled" },
 	{ 1, "50 Hz" },
@@ -1024,6 +1029,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
 	return 0;
 }
 
+static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
+				  u32 found_id)
+{
+	bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL;
+	unsigned int i;
+
+	req_id &= V4L2_CTRL_ID_MASK;
+
+	for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) {
+		if (!(chain->ctrl_class_bitmap & BIT(i)))
+			continue;
+		if (!find_next) {
+			if (uvc_control_classes[i] == req_id)
+				return i;
+			continue;
+		}
+		if (uvc_control_classes[i] > req_id &&
+		    uvc_control_classes[i] < found_id)
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
+				u32 found_id, struct v4l2_queryctrl *v4l2_ctrl)
+{
+	int idx;
+
+	idx = __uvc_query_v4l2_class(chain, req_id, found_id);
+	if (idx < 0)
+		return -ENODEV;
+
+	memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
+	v4l2_ctrl->id = uvc_control_classes[idx];
+	strscpy(v4l2_ctrl->name, v4l2_ctrl_get_name(v4l2_ctrl->id),
+		sizeof(v4l2_ctrl->name));
+	v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
+	v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY
+			 | V4L2_CTRL_FLAG_READ_ONLY;
+	return 0;
+}
+
 static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 	struct uvc_control *ctrl,
 	struct uvc_control_mapping *mapping,
@@ -1127,12 +1175,31 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 	if (ret < 0)
 		return -ERESTARTSYS;
 
+	/* Check if the ctrl is a know class */
+	if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
+		ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, 0, v4l2_ctrl);
+		if (!ret)
+			goto done;
+	}
+
 	ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
 	if (ctrl == NULL) {
 		ret = -EINVAL;
 		goto done;
 	}
 
+	/*
+	 * If we're enumerating control with V4L2_CTRL_FLAG_NEXT_CTRL, check if
+	 * a class should be inserted between the previous control and the one
+	 * we have just found.
+	 */
+	if (v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+		ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, mapping->id,
+					   v4l2_ctrl);
+		if (!ret)
+			goto done;
+	}
+
 	ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl);
 done:
 	mutex_unlock(&chain->ctrl_mutex);
@@ -1426,6 +1493,11 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
 	if (ret < 0)
 		return -ERESTARTSYS;
 
+	if (__uvc_query_v4l2_class(handle->chain, sev->id, 0) >= 0) {
+		ret = 0;
+		goto done;
+	}
+
 	ctrl = uvc_find_control(handle->chain, sev->id, &mapping);
 	if (ctrl == NULL) {
 		ret = -EINVAL;
@@ -1459,7 +1531,10 @@ static void uvc_ctrl_del_event(struct v4l2_subscribed_event *sev)
 	struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
 
 	mutex_lock(&handle->chain->ctrl_mutex);
+	if (__uvc_query_v4l2_class(handle->chain, sev->id, 0) >= 0)
+		goto done;
 	list_del(&sev->node);
+done:
 	mutex_unlock(&handle->chain->ctrl_mutex);
 }
 
@@ -1577,6 +1652,9 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
 	struct uvc_control *ctrl;
 	struct uvc_control_mapping *mapping;
 
+	if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
+		return -EACCES;
+
 	ctrl = uvc_find_control(chain, xctrl->id, &mapping);
 	if (ctrl == NULL)
 		return -EINVAL;
@@ -1596,6 +1674,9 @@ int uvc_ctrl_set(struct uvc_fh *handle,
 	s32 max;
 	int ret;
 
+	if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
+		return -EACCES;
+
 	ctrl = uvc_find_control(chain, xctrl->id, &mapping);
 	if (ctrl == NULL)
 		return -EINVAL;
@@ -2062,6 +2143,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 {
 	struct uvc_control_mapping *map;
 	unsigned int size;
+	unsigned int i;
 
 	/* Most mappings come from static kernel data and need to be duplicated.
 	 * Mappings that come from userspace will be unnecessarily duplicated,
@@ -2085,6 +2167,14 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 	if (map->set == NULL)
 		map->set = uvc_set_le_value;
 
+	for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) {
+		if (V4L2_CTRL_ID2WHICH(uvc_control_classes[i]) ==
+						V4L2_CTRL_ID2WHICH(map->id)) {
+			chain->ctrl_class_bitmap |= BIT(i);
+			break;
+		}
+	}
+
 	list_add_tail(&map->list, &ctrl->info.mappings);
 	uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n",
 		map->name, ctrl->info.entity, ctrl->info.selector);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index cce5e38133cd..5eb7e87f8430 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -476,6 +476,7 @@ struct uvc_video_chain {
 
 	struct v4l2_prio_state prio;		/* V4L2 priority state */
 	u32 caps;				/* V4L2 chain-wide caps */
+	u8 ctrl_class_bitmap;			/* Bitmap of valid classes */
 };
 
 struct uvc_stats_frame {
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 10/21] media: uvcvideo: Use dev->name for querycap()
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (8 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 09/21] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 11/21] media: uvcvideo: Set unique vdev name based in type Ricardo Ribalda
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

Use the device name for the card name instead of vdev->name. That way
all the devices have a different name instead of the common vdev->name.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_metadata.c | 2 +-
 drivers/media/usb/uvc/uvc_v4l2.c     | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c
index b6279ad7ac84..82de7781f5b6 100644
--- a/drivers/media/usb/uvc/uvc_metadata.c
+++ b/drivers/media/usb/uvc/uvc_metadata.c
@@ -30,7 +30,7 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh,
 	struct uvc_video_chain *chain = stream->chain;
 
 	strscpy(cap->driver, "uvcvideo", sizeof(cap->driver));
-	strscpy(cap->card, vfh->vdev->name, sizeof(cap->card));
+	strscpy(cap->card, stream->dev->name, sizeof(cap->card));
 	usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info));
 	cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
 			  | chain->caps;
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 1eeeb00280e4..9cdd30eff495 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -617,13 +617,12 @@ static int uvc_v4l2_release(struct file *file)
 static int uvc_ioctl_querycap(struct file *file, void *fh,
 			      struct v4l2_capability *cap)
 {
-	struct video_device *vdev = video_devdata(file);
 	struct uvc_fh *handle = file->private_data;
 	struct uvc_video_chain *chain = handle->chain;
 	struct uvc_streaming *stream = handle->stream;
 
 	strscpy(cap->driver, "uvcvideo", sizeof(cap->driver));
-	strscpy(cap->card, vdev->name, sizeof(cap->card));
+	strscpy(cap->card, handle->stream->dev->name, sizeof(cap->card));
 	usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info));
 	cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
 			  | chain->caps;
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 11/21] media: uvcvideo: Set unique vdev name based in type
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (9 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 10/21] media: uvcvideo: Use dev->name for querycap() Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-12-06 19:05   ` [REGRESSION] " Nicolas Dufresne
  2021-06-18 12:29 ` [PATCH v10 12/21] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE Ricardo Ribalda
                   ` (9 subsequent siblings)
  20 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

All the entities must have a unique name. We can have a descriptive and
unique name by appending the function and the entity->id.

This is even resilent to multi chain devices.

Fixes v4l2-compliance:
Media Controller ioctls:
                fail: v4l2-test-media.cpp(205): v2_entity_names_set.find(key) != v2_entity_names_set.end()
        test MEDIA_IOC_G_TOPOLOGY: FAIL
                fail: v4l2-test-media.cpp(394): num_data_links != num_links
	test MEDIA_IOC_ENUM_ENTITIES/LINKS: FAIL

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 drivers/media/usb/uvc/uvc_driver.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 14b60792ffab..037bf80d1100 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2194,6 +2194,7 @@ int uvc_register_video_device(struct uvc_device *dev,
 			      const struct v4l2_file_operations *fops,
 			      const struct v4l2_ioctl_ops *ioctl_ops)
 {
+	const char *name;
 	int ret;
 
 	/* Initialize the video buffers queue. */
@@ -2222,16 +2223,20 @@ int uvc_register_video_device(struct uvc_device *dev,
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	default:
 		vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+		name = "Video Capture";
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+		name = "Video Output";
 		break;
 	case V4L2_BUF_TYPE_META_CAPTURE:
 		vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
+		name = "Metadata";
 		break;
 	}
 
-	strscpy(vdev->name, dev->name, sizeof(vdev->name));
+	snprintf(vdev->name, sizeof(vdev->name), "%s %u", name,
+		 stream->header.bTerminalLink);
 
 	/*
 	 * Set the driver data before calling video_register_device, otherwise
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 12/21] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (10 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 11/21] media: uvcvideo: Set unique vdev name based in type Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 13/21] media: uvcvideo: Use control names from framework Ricardo Ribalda
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

Hans has discovered that in his test device, for the H264 format
bytesused goes up to about 570, for YUYV it will actually go up
to a bit over 5000 bytes, and for MJPG up to about 2706 bytes.

We should also, according to V4L2_META_FMT_UVC docs, drop headers when
the buffer is full.

Credit-to: Hans Verkuil <hverkuil@xs4all.nl>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvcvideo.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 5eb7e87f8430..37a092d717cf 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -524,7 +524,7 @@ struct uvc_stats_stream {
 	unsigned int max_sof;		/* Maximum STC.SOF value */
 };
 
-#define UVC_METADATA_BUF_SIZE 1024
+#define UVC_METADATA_BUF_SIZE 10240
 
 /**
  * struct uvc_copy_op: Context structure to schedule asynchronous memcpy
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 13/21] media: uvcvideo: Use control names from framework
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (11 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 12/21] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-09-03 10:10   ` Mauro Carvalho Chehab
  2021-06-18 12:29 ` [PATCH v10 14/21] media: uvcvideo: Check controls flags before accessing them Ricardo Ribalda
                   ` (7 subsequent siblings)
  20 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda, Hans Verkuil

The framework already contains a map of IDs to names, lets use it when
possible.

Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Suggested-by: Hans Verkuil <hverkuil@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 57 ++++++++++++--------------------
 drivers/media/usb/uvc/uvc_v4l2.c |  8 ++++-
 drivers/media/usb/uvc/uvcvideo.h |  2 +-
 3 files changed, 30 insertions(+), 37 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 7c1d71782281..2cc2ff0d0cae 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -432,7 +432,6 @@ static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
 static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	{
 		.id		= V4L2_CID_BRIGHTNESS,
-		.name		= "Brightness",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_BRIGHTNESS_CONTROL,
 		.size		= 16,
@@ -442,7 +441,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_CONTRAST,
-		.name		= "Contrast",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_CONTRAST_CONTROL,
 		.size		= 16,
@@ -452,7 +450,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_HUE,
-		.name		= "Hue",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_HUE_CONTROL,
 		.size		= 16,
@@ -464,7 +461,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_SATURATION,
-		.name		= "Saturation",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_SATURATION_CONTROL,
 		.size		= 16,
@@ -474,7 +470,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_SHARPNESS,
-		.name		= "Sharpness",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_SHARPNESS_CONTROL,
 		.size		= 16,
@@ -484,7 +479,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_GAMMA,
-		.name		= "Gamma",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_GAMMA_CONTROL,
 		.size		= 16,
@@ -494,7 +488,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_BACKLIGHT_COMPENSATION,
-		.name		= "Backlight Compensation",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
 		.size		= 16,
@@ -504,7 +497,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_GAIN,
-		.name		= "Gain",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_GAIN_CONTROL,
 		.size		= 16,
@@ -514,7 +506,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_POWER_LINE_FREQUENCY,
-		.name		= "Power Line Frequency",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
 		.size		= 2,
@@ -526,7 +517,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_HUE_AUTO,
-		.name		= "Hue, Auto",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_HUE_AUTO_CONTROL,
 		.size		= 1,
@@ -537,7 +527,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_EXPOSURE_AUTO,
-		.name		= "Exposure, Auto",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_AE_MODE_CONTROL,
 		.size		= 4,
@@ -550,7 +539,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_EXPOSURE_AUTO_PRIORITY,
-		.name		= "Exposure, Auto Priority",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_AE_PRIORITY_CONTROL,
 		.size		= 1,
@@ -560,7 +548,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_EXPOSURE_ABSOLUTE,
-		.name		= "Exposure (Absolute)",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
 		.size		= 32,
@@ -572,7 +559,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
-		.name		= "White Balance Temperature, Auto",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
 		.size		= 1,
@@ -583,7 +569,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_WHITE_BALANCE_TEMPERATURE,
-		.name		= "White Balance Temperature",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
 		.size		= 16,
@@ -595,7 +580,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
-		.name		= "White Balance Component, Auto",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
 		.size		= 1,
@@ -607,7 +591,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_BLUE_BALANCE,
-		.name		= "White Balance Blue Component",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
 		.size		= 16,
@@ -619,7 +602,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_RED_BALANCE,
-		.name		= "White Balance Red Component",
 		.entity		= UVC_GUID_UVC_PROCESSING,
 		.selector	= UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
 		.size		= 16,
@@ -631,7 +613,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_FOCUS_ABSOLUTE,
-		.name		= "Focus (absolute)",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_FOCUS_ABSOLUTE_CONTROL,
 		.size		= 16,
@@ -643,7 +624,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_FOCUS_AUTO,
-		.name		= "Focus, Auto",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_FOCUS_AUTO_CONTROL,
 		.size		= 1,
@@ -654,7 +634,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_IRIS_ABSOLUTE,
-		.name		= "Iris, Absolute",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_IRIS_ABSOLUTE_CONTROL,
 		.size		= 16,
@@ -664,7 +643,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_IRIS_RELATIVE,
-		.name		= "Iris, Relative",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_IRIS_RELATIVE_CONTROL,
 		.size		= 8,
@@ -674,7 +652,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_ZOOM_ABSOLUTE,
-		.name		= "Zoom, Absolute",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_ZOOM_ABSOLUTE_CONTROL,
 		.size		= 16,
@@ -684,7 +661,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_ZOOM_CONTINUOUS,
-		.name		= "Zoom, Continuous",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_ZOOM_RELATIVE_CONTROL,
 		.size		= 0,
@@ -696,7 +672,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_PAN_ABSOLUTE,
-		.name		= "Pan (Absolute)",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_PANTILT_ABSOLUTE_CONTROL,
 		.size		= 32,
@@ -706,7 +681,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_TILT_ABSOLUTE,
-		.name		= "Tilt (Absolute)",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_PANTILT_ABSOLUTE_CONTROL,
 		.size		= 32,
@@ -716,7 +690,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_PAN_SPEED,
-		.name		= "Pan (Speed)",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_PANTILT_RELATIVE_CONTROL,
 		.size		= 16,
@@ -728,7 +701,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_TILT_SPEED,
-		.name		= "Tilt (Speed)",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_PANTILT_RELATIVE_CONTROL,
 		.size		= 16,
@@ -740,7 +712,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_PRIVACY,
-		.name		= "Privacy",
 		.entity		= UVC_GUID_UVC_CAMERA,
 		.selector	= UVC_CT_PRIVACY_CONTROL,
 		.size		= 1,
@@ -750,7 +721,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 	{
 		.id		= V4L2_CID_PRIVACY,
-		.name		= "Privacy",
 		.entity		= UVC_GUID_EXT_GPIO_CONTROLLER,
 		.selector	= UVC_CT_PRIVACY_CONTROL,
 		.size		= 1,
@@ -1072,6 +1042,20 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
 	return 0;
 }
 
+static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
+{
+	const char *name;
+
+	if (map->name)
+		return map->name;
+
+	name = v4l2_ctrl_get_name(map->id);
+	if (name)
+		return name;
+
+	return "Unknown Control";
+}
+
 static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 	struct uvc_control *ctrl,
 	struct uvc_control_mapping *mapping,
@@ -1085,7 +1069,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 	memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
 	v4l2_ctrl->id = mapping->id;
 	v4l2_ctrl->type = mapping->v4l2_type;
-	strscpy(v4l2_ctrl->name, mapping->name, sizeof(v4l2_ctrl->name));
+	strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping),
+		sizeof(v4l2_ctrl->name));
 	v4l2_ctrl->flags = 0;
 
 	if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
@@ -2177,7 +2162,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 
 	list_add_tail(&map->list, &ctrl->info.mappings);
 	uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n",
-		map->name, ctrl->info.entity, ctrl->info.selector);
+		uvc_map_get_name(map), ctrl->info.entity,
+		ctrl->info.selector);
 
 	return 0;
 }
@@ -2195,7 +2181,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 	if (mapping->id & ~V4L2_CTRL_ID_MASK) {
 		uvc_dbg(dev, CONTROL,
 			"Can't add mapping '%s', control id 0x%08x is invalid\n",
-			mapping->name, mapping->id);
+			uvc_map_get_name(mapping), mapping->id);
 		return -EINVAL;
 	}
 
@@ -2242,7 +2228,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 		if (mapping->id == map->id) {
 			uvc_dbg(dev, CONTROL,
 				"Can't add mapping '%s', control id 0x%08x already exists\n",
-				mapping->name, mapping->id);
+				uvc_map_get_name(mapping), mapping->id);
 			ret = -EEXIST;
 			goto done;
 		}
@@ -2253,7 +2239,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 		atomic_dec(&dev->nmappings);
 		uvc_dbg(dev, CONTROL,
 			"Can't add mapping '%s', maximum mappings count (%u) exceeded\n",
-			mapping->name, UVC_MAX_CONTROL_MAPPINGS);
+			uvc_map_get_name(mapping), UVC_MAX_CONTROL_MAPPINGS);
 		ret = -ENOMEM;
 		goto done;
 	}
@@ -2462,6 +2448,7 @@ static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev,
 	list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
 		list_del(&mapping->list);
 		kfree(mapping->menu_info);
+		kfree(mapping->name);
 		kfree(mapping);
 	}
 }
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 9cdd30eff495..28ccaa8b9e42 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -40,7 +40,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
 		return -ENOMEM;
 
 	map->id = xmap->id;
-	memcpy(map->name, xmap->name, sizeof(map->name));
+	/* Non standard control id. */
+	if (v4l2_ctrl_get_name(map->id) == NULL) {
+		map->name = kmemdup(xmap->name, sizeof(xmap->name),
+				    GFP_KERNEL);
+		if (!map->name)
+			return -ENOMEM;
+	}
 	memcpy(map->entity, xmap->entity, sizeof(map->entity));
 	map->selector = xmap->selector;
 	map->size = xmap->size;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 37a092d717cf..b044d9455b2c 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -241,7 +241,7 @@ struct uvc_control_mapping {
 	struct list_head ev_subs;
 
 	u32 id;
-	u8 name[32];
+	char *name;
 	u8 entity[16];
 	u8 selector;
 
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 14/21] media: uvcvideo: Check controls flags before accessing them
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (12 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 13/21] media: uvcvideo: Use control names from framework Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 15/21] media: uvcvideo: Set error_idx during ctrl_commit errors Ricardo Ribalda
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

We can figure out if reading/writing a set of controls can fail without
accessing them by checking their flags.

This way we can honor the API closer:

If an error is found when validating the list of controls passed with
VIDIOC_G_EXT_CTRLS, then error_idx shall be set to ctrls->count to
indicate to userspace that no actual hardware was touched.

Fixes v4l2-compliance:
Control ioctls (Input 0):
		warn: v4l2-test-controls.cpp(765): g_ext_ctrls(0) invalid error_idx 0
                fail: v4l2-test-controls.cpp(645): invalid error index write only control
        test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL

Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 22 ++++++++++++++++++
 drivers/media/usb/uvc/uvc_v4l2.c | 39 ++++++++++++++++++++++++++++----
 drivers/media/usb/uvc/uvcvideo.h |  2 ++
 3 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 2cc2ff0d0cae..18c315b52ef5 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1042,6 +1042,28 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
 	return 0;
 }
 
+int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
+			   bool read)
+{
+	struct uvc_control_mapping *mapping;
+	struct uvc_control *ctrl;
+
+	if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0)
+		return -EACCES;
+
+	ctrl = uvc_find_control(chain, v4l2_id, &mapping);
+	if (!ctrl)
+		return -EINVAL;
+
+	if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) && read)
+		return -EACCES;
+
+	if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read)
+		return -EACCES;
+
+	return 0;
+}
+
 static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
 {
 	const char *name;
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 28ccaa8b9e42..a3ee1dc003fc 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -991,6 +991,26 @@ static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
 	return 0;
 }
 
+static int uvc_ctrl_check_access(struct uvc_video_chain *chain,
+				 struct v4l2_ext_controls *ctrls,
+				 unsigned long ioctl)
+{
+	struct v4l2_ext_control *ctrl = ctrls->controls;
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+		ret = uvc_ctrl_is_accessible(chain, ctrl->id,
+					    ioctl == VIDIOC_G_EXT_CTRLS);
+		if (ret)
+			break;
+	}
+
+	ctrls->error_idx = ioctl == VIDIOC_TRY_EXT_CTRLS ? i : ctrls->count;
+
+	return ret;
+}
+
 static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
 				 struct v4l2_ext_controls *ctrls)
 {
@@ -1000,6 +1020,10 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
 	unsigned int i;
 	int ret;
 
+	ret = uvc_ctrl_check_access(chain, ctrls, VIDIOC_G_EXT_CTRLS);
+	if (ret < 0)
+		return ret;
+
 	if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
 		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
 			struct v4l2_queryctrl qc = { .id = ctrl->id };
@@ -1036,13 +1060,17 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
 
 static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
 				     struct v4l2_ext_controls *ctrls,
-				     bool commit)
+				     unsigned long ioctl)
 {
 	struct v4l2_ext_control *ctrl = ctrls->controls;
 	struct uvc_video_chain *chain = handle->chain;
 	unsigned int i;
 	int ret;
 
+	ret = uvc_ctrl_check_access(chain, ctrls, ioctl);
+	if (ret < 0)
+		return ret;
+
 	ret = uvc_ctrl_begin(chain);
 	if (ret < 0)
 		return ret;
@@ -1051,14 +1079,15 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
 		ret = uvc_ctrl_set(handle, ctrl);
 		if (ret < 0) {
 			uvc_ctrl_rollback(handle);
-			ctrls->error_idx = commit ? ctrls->count : i;
+			ctrls->error_idx = ioctl == VIDIOC_S_EXT_CTRLS ?
+						    ctrls->count : i;
 			return ret;
 		}
 	}
 
 	ctrls->error_idx = 0;
 
-	if (commit)
+	if (ioctl == VIDIOC_S_EXT_CTRLS)
 		return uvc_ctrl_commit(handle, ctrls->controls, ctrls->count);
 	else
 		return uvc_ctrl_rollback(handle);
@@ -1069,7 +1098,7 @@ static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh,
 {
 	struct uvc_fh *handle = fh;
 
-	return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, true);
+	return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS);
 }
 
 static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh,
@@ -1077,7 +1106,7 @@ static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh,
 {
 	struct uvc_fh *handle = fh;
 
-	return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, false);
+	return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS);
 }
 
 static int uvc_ioctl_querymenu(struct file *file, void *fh,
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index b044d9455b2c..4aa78591d9b0 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -901,6 +901,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
 
 int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
 int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
+int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
+			   bool read);
 
 int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
 		      struct uvc_xu_control_query *xqry);
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 15/21] media: uvcvideo: Set error_idx during ctrl_commit errors
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (13 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 14/21] media: uvcvideo: Check controls flags before accessing them Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 16/21] media: docs: Document the behaviour of uvcvideo driver Ricardo Ribalda
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

If we have an error setting a control, return the affected control in
the error_idx field.

Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 42 ++++++++++++++++++++++++++------
 drivers/media/usb/uvc/uvc_v4l2.c |  2 +-
 drivers/media/usb/uvc/uvcvideo.h | 10 +++-----
 3 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 18c315b52ef5..dd6ebcc7344a 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1582,7 +1582,7 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain)
 }
 
 static int uvc_ctrl_commit_entity(struct uvc_device *dev,
-	struct uvc_entity *entity, int rollback)
+	struct uvc_entity *entity, int rollback, struct uvc_control **err_ctrl)
 {
 	struct uvc_control *ctrl;
 	unsigned int i;
@@ -1624,31 +1624,59 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
 
 		ctrl->dirty = 0;
 
-		if (ret < 0)
+		if (ret < 0) {
+			if (err_ctrl)
+				*err_ctrl = ctrl;
 			return ret;
+		}
 	}
 
 	return 0;
 }
 
+static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
+				  struct v4l2_ext_controls *ctrls,
+				  struct uvc_control *uvc_control)
+{
+	struct uvc_control_mapping *mapping;
+	struct uvc_control *ctrl_found;
+	unsigned int i;
+
+	if (!entity)
+		return ctrls->count;
+
+	for (i = 0; i < ctrls->count; i++) {
+		__uvc_find_control(entity, ctrls->controls[i].id, &mapping,
+				   &ctrl_found, 0);
+		if (uvc_control == ctrl_found)
+			return i;
+	}
+
+	return ctrls->count;
+}
+
 int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
-		      const struct v4l2_ext_control *xctrls,
-		      unsigned int xctrls_count)
+		      struct v4l2_ext_controls *ctrls)
 {
 	struct uvc_video_chain *chain = handle->chain;
+	struct uvc_control *err_ctrl;
 	struct uvc_entity *entity;
 	int ret = 0;
 
 	/* Find the control. */
 	list_for_each_entry(entity, &chain->entities, chain) {
-		ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
+		ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback,
+					     &err_ctrl);
 		if (ret < 0)
 			goto done;
 	}
 
 	if (!rollback)
-		uvc_ctrl_send_events(handle, xctrls, xctrls_count);
+		uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
 done:
+	if (ret < 0 && ctrls)
+		ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
+							  err_ctrl);
 	mutex_unlock(&chain->ctrl_mutex);
 	return ret;
 }
@@ -2106,7 +2134,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
 			ctrl->dirty = 1;
 		}
 
-		ret = uvc_ctrl_commit_entity(dev, entity, 0);
+		ret = uvc_ctrl_commit_entity(dev, entity, 0, NULL);
 		if (ret < 0)
 			return ret;
 	}
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index a3ee1dc003fc..8d8b12a4db34 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1088,7 +1088,7 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
 	ctrls->error_idx = 0;
 
 	if (ioctl == VIDIOC_S_EXT_CTRLS)
-		return uvc_ctrl_commit(handle, ctrls->controls, ctrls->count);
+		return uvc_ctrl_commit(handle, ctrls);
 	else
 		return uvc_ctrl_rollback(handle);
 }
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 4aa78591d9b0..2e5366143b81 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -886,17 +886,15 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
 
 int uvc_ctrl_begin(struct uvc_video_chain *chain);
 int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
-		      const struct v4l2_ext_control *xctrls,
-		      unsigned int xctrls_count);
+		      struct v4l2_ext_controls *ctrls);
 static inline int uvc_ctrl_commit(struct uvc_fh *handle,
-				  const struct v4l2_ext_control *xctrls,
-				  unsigned int xctrls_count)
+				  struct v4l2_ext_controls *ctrls)
 {
-	return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
+	return __uvc_ctrl_commit(handle, 0, ctrls);
 }
 static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
 {
-	return __uvc_ctrl_commit(handle, 1, NULL, 0);
+	return __uvc_ctrl_commit(handle, 1, NULL);
 }
 
 int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 16/21] media: docs: Document the behaviour of uvcvideo driver
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (14 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 15/21] media: uvcvideo: Set error_idx during ctrl_commit errors Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 17/21] uvcvideo: uvc_ctrl_is_accessible: check for INACTIVE Ricardo Ribalda
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

The uvc driver relies on the camera firmware to keep the control states
and therefore is not capable of changing an inactive control.

Allow returning -EACCES in those cases.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst      | 3 +++
 Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst
index 80e8c63d530f..fd09677f64f8 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst
@@ -95,3 +95,6 @@ EBUSY
 
 EACCES
     Attempt to set a read-only control or to get a write-only control.
+
+    Or if there is an attempt to set an inactive control and the driver is
+    not capable of caching the new value until the control is active again.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
index 3ba22983d21f..b42b822e9ede 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
@@ -458,3 +458,6 @@ EACCES
 
     Or the ``which`` field was set to ``V4L2_CTRL_WHICH_REQUEST_VAL`` but the
     device does not support requests.
+
+    Or if there is an attempt to set an inactive control and the driver is
+    not capable of caching the new value until the control is active again.
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 17/21] uvcvideo: uvc_ctrl_is_accessible: check for INACTIVE
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (15 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 16/21] media: docs: Document the behaviour of uvcvideo driver Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-08-22 23:40   ` Laurent Pinchart
  2021-06-18 12:29 ` [PATCH v10 18/21] uvcvideo: improve error handling in uvc_query_ctrl() Ricardo Ribalda
                   ` (3 subsequent siblings)
  20 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Hans Verkuil, Ricardo Ribalda, Hans Verkuil

From: Hans Verkuil <hverkuil@xs4all.nl>

Check for inactive controls in uvc_ctrl_is_accessible().
Use the new value for the master_id controls if present,
otherwise use the existing value to determine if it is OK
to set the control. Doing this here avoids attempting to
set an inactive control, which will return an error from the
USB device.

Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 28 +++++++++++++++++++++++++++-
 drivers/media/usb/uvc/uvc_v4l2.c |  4 ++--
 drivers/media/usb/uvc/uvcvideo.h |  3 ++-
 3 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index dd6ebcc7344a..11c25d4b5c20 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1043,10 +1043,18 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
 }
 
 int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
-			   bool read)
+			   const struct v4l2_ext_controls *ctrls,
+			   unsigned long ioctl)
 {
+	struct uvc_control_mapping *master_map = NULL;
+	struct uvc_control *master_ctrl = NULL;
 	struct uvc_control_mapping *mapping;
 	struct uvc_control *ctrl;
+	bool read = ioctl == VIDIOC_G_EXT_CTRLS;
+	bool try = ioctl == VIDIOC_TRY_EXT_CTRLS;
+	s32 val;
+	int ret;
+	int i;
 
 	if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0)
 		return -EACCES;
@@ -1061,6 +1069,24 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
 	if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read)
 		return -EACCES;
 
+	if (read || try || !mapping->master_id)
+		return 0;
+
+	for (i = ctrls->count - 1; i >= 0; i--)
+		if (ctrls->controls[i].id == mapping->master_id)
+			return ctrls->controls[i].value ==
+					mapping->master_manual ? 0 : -EACCES;
+
+	__uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
+			   &master_ctrl, 0);
+
+	if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
+		return 0;
+
+	ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
+	if (ret >= 0 && val != mapping->master_manual)
+		return -EACCES;
+
 	return 0;
 }
 
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 8d8b12a4db34..0f4d893eff46 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1000,8 +1000,8 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain,
 	int ret = 0;
 
 	for (i = 0; i < ctrls->count; ++ctrl, ++i) {
-		ret = uvc_ctrl_is_accessible(chain, ctrl->id,
-					    ioctl == VIDIOC_G_EXT_CTRLS);
+		ret = uvc_ctrl_is_accessible(chain, ctrl->id, ctrls,
+					    ioctl);
 		if (ret)
 			break;
 	}
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 2e5366143b81..fd4f5ef47dfb 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -900,7 +900,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
 int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
 int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
 int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
-			   bool read);
+			   const struct v4l2_ext_controls *ctrls,
+			   unsigned long ioctl);
 
 int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
 		      struct uvc_xu_control_query *xqry);
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 18/21] uvcvideo: improve error handling in uvc_query_ctrl()
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (16 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 17/21] uvcvideo: uvc_ctrl_is_accessible: check for INACTIVE Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-08-22 23:52   ` Laurent Pinchart
  2021-06-18 12:29 ` [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values() Ricardo Ribalda
                   ` (2 subsequent siblings)
  20 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda, Hans Verkuil

From: Hans Verkuil <hverkuil-cisco@xs4all.nl>

- If __uvc_query_ctrl() failed with a non-EPIPE error, then
  report that with dev_err. If an error code is obtained, then
  report that with dev_dbg.

- For error 2 (Wrong state) return -EACCES instead of -EILSEQ.
  EACCES is a much more appropriate error code. EILSEQ will return
  "Invalid or incomplete multibyte or wide character." in strerror(),
  which is a *very* confusing message.

Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/uvc/uvc_video.c | 38 ++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index daba5fe352ea..00488f15cdbf 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -79,15 +79,11 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
 	if (likely(ret == size))
 		return 0;
 
-	dev_err(&dev->udev->dev,
-		"Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n",
-		uvc_query_name(query), cs, unit, ret, size);
-
-	if (ret != -EPIPE)
-		return ret;
+	if (ret < 0 && ret != -EPIPE)
+		goto err;
 
+	/* reuse data[0] to request the error code. */
 	tmp = *(u8 *)data;
-
 	ret = __uvc_query_ctrl(dev, UVC_GET_CUR, 0, intfnum,
 			       UVC_VC_REQUEST_ERROR_CODE_CONTROL, data, 1,
 			       UVC_CTRL_CONTROL_TIMEOUT);
@@ -95,19 +91,21 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
 	error = *(u8 *)data;
 	*(u8 *)data = tmp;
 
-	if (ret != 1)
-		return ret < 0 ? ret : -EPIPE;
+	if (ret != 1) {
+		ret = ret < 0 ? ret : -EPIPE;
+		goto err;
+	}
 
-	uvc_dbg(dev, CONTROL, "Control error %u\n", error);
+	if (error >=1 && error <=8)
+		uvc_dbg(dev, CONTROL,
+			"Failed to query (%s) UVC control %u on unit %u: got error %u.\n",
+			uvc_query_name(query), cs, unit, error);
 
 	switch (error) {
-	case 0:
-		/* Cannot happen - we received a STALL */
-		return -EPIPE;
 	case 1: /* Not ready */
 		return -EBUSY;
 	case 2: /* Wrong state */
-		return -EILSEQ;
+		return -EACCES;
 	case 3: /* Power */
 		return -EREMOTE;
 	case 4: /* Out of range */
@@ -123,10 +121,18 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
 	case 8: /* Invalid value within range */
 		return -EINVAL;
 	default: /* reserved or unknown */
-		break;
+		dev_err(&dev->udev->dev,
+			"Failed to query (%s) UVC control %u on unit %u: got error %u.\n",
+			uvc_query_name(query), cs, unit, error);
+		return -EPIPE;
 	}
 
-	return -EPIPE;
+err:
+	dev_err(&dev->udev->dev,
+		"Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n",
+		uvc_query_name(query), cs, unit, ret, size);
+
+	return ret;
 }
 
 static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values()
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (17 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 18/21] uvcvideo: improve error handling in uvc_query_ctrl() Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-08-22 23:23   ` Laurent Pinchart
  2021-08-23  0:17   ` Laurent Pinchart
  2021-06-18 12:29 ` [PATCH v10 20/21] uvc: use vb2 ioctl and fop helpers Ricardo Ribalda
  2021-06-18 12:29 ` [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls Ricardo Ribalda
  20 siblings, 2 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda, Hans Verkuil

From: Hans Verkuil <hverkuil-cisco@xs4all.nl>

Don't report the restored controls with dev_info, use dev_dbg instead.
This prevents a lot of noise in the kernel log.

Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 11c25d4b5c20..da44d5c0b9ad 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2153,10 +2153,10 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
 			if (!ctrl->initialized || !ctrl->modified ||
 			    (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
 				continue;
-			dev_info(&dev->udev->dev,
-				 "restoring control %pUl/%u/%u\n",
-				 ctrl->info.entity, ctrl->info.index,
-				 ctrl->info.selector);
+			dev_dbg(&dev->udev->dev,
+				"restoring control %pUl/%u/%u\n",
+				ctrl->info.entity, ctrl->info.index,
+				ctrl->info.selector);
 			ctrl->dirty = 1;
 		}
 
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 20/21] uvc: use vb2 ioctl and fop helpers
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (18 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values() Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-08-23  0:00   ` Laurent Pinchart
  2021-06-18 12:29 ` [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls Ricardo Ribalda
  20 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Hans Verkuil

From: Hans Verkuil <hverkuil@xs4all.nl>

When uvc was written the vb2 ioctl and file operation helpers didn't exist.

This patch switches uvc over to those helpers, which removes a lot of boilerplate
code and simplifies VIDIOC_G/S_PRIORITY handling and allows us to drop the
'privileges' scheme, since that's now handled inside the vb2 helpers.

This makes it possible for uvc to pass the v4l2-compliance streaming tests.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 drivers/media/usb/uvc/uvc_driver.c   |   7 +-
 drivers/media/usb/uvc/uvc_metadata.c |   8 +-
 drivers/media/usb/uvc/uvc_queue.c    | 143 -------------
 drivers/media/usb/uvc/uvc_v4l2.c     | 288 ++-------------------------
 drivers/media/usb/uvc/uvcvideo.h     |  32 ---
 5 files changed, 25 insertions(+), 453 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 037bf80d1100..9416e80fe392 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1943,7 +1943,6 @@ static struct uvc_video_chain *uvc_alloc_chain(struct uvc_device *dev)
 	INIT_LIST_HEAD(&chain->entities);
 	mutex_init(&chain->ctrl_mutex);
 	chain->dev = dev;
-	v4l2_prio_init(&chain->prio);
 
 	return chain;
 }
@@ -2213,7 +2212,7 @@ int uvc_register_video_device(struct uvc_device *dev,
 	vdev->fops = fops;
 	vdev->ioctl_ops = ioctl_ops;
 	vdev->release = uvc_release;
-	vdev->prio = &stream->chain->prio;
+	vdev->queue = &queue->queue;
 	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
 		vdev->vfl_dir = VFL_DIR_TX;
 	else
@@ -2578,8 +2577,8 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
 		if (stream->intf == intf) {
 			ret = uvc_video_resume(stream, reset);
 			if (ret < 0)
-				uvc_queue_streamoff(&stream->queue,
-						    stream->queue.queue.type);
+				vb2_streamoff(&stream->queue.queue,
+					      stream->queue.queue.type);
 			return ret;
 		}
 	}
diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c
index 82de7781f5b6..d3aab22f91ce 100644
--- a/drivers/media/usb/uvc/uvc_metadata.c
+++ b/drivers/media/usb/uvc/uvc_metadata.c
@@ -96,7 +96,7 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh,
 	 */
 	mutex_lock(&stream->mutex);
 
-	if (uvc_queue_allocated(&stream->queue))
+	if (vb2_is_busy(&stream->meta.queue.queue))
 		ret = -EBUSY;
 	else
 		stream->meta.format = fmt->dataformat;
@@ -164,12 +164,6 @@ int uvc_meta_register(struct uvc_streaming *stream)
 
 	stream->meta.format = V4L2_META_FMT_UVC;
 
-	/*
-	 * The video interface queue uses manual locking and thus does not set
-	 * the queue pointer. Set it manually here.
-	 */
-	vdev->queue = &queue->queue;
-
 	return uvc_register_video_device(dev, stream, vdev, queue,
 					 V4L2_BUF_TYPE_META_CAPTURE,
 					 &uvc_meta_fops, &uvc_meta_ioctl_ops);
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 21a907d32bb7..437e48b32480 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -247,153 +247,10 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
 	return 0;
 }
 
-void uvc_queue_release(struct uvc_video_queue *queue)
-{
-	mutex_lock(&queue->mutex);
-	vb2_queue_release(&queue->queue);
-	mutex_unlock(&queue->mutex);
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 queue operations
- */
-
-int uvc_request_buffers(struct uvc_video_queue *queue,
-			struct v4l2_requestbuffers *rb)
-{
-	int ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_reqbufs(&queue->queue, rb);
-	mutex_unlock(&queue->mutex);
-
-	return ret ? ret : rb->count;
-}
-
-int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
-{
-	int ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_querybuf(&queue->queue, buf);
-	mutex_unlock(&queue->mutex);
-
-	return ret;
-}
-
-int uvc_create_buffers(struct uvc_video_queue *queue,
-		       struct v4l2_create_buffers *cb)
-{
-	int ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_create_bufs(&queue->queue, cb);
-	mutex_unlock(&queue->mutex);
-
-	return ret;
-}
-
-int uvc_queue_buffer(struct uvc_video_queue *queue,
-		     struct media_device *mdev, struct v4l2_buffer *buf)
-{
-	int ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_qbuf(&queue->queue, mdev, buf);
-	mutex_unlock(&queue->mutex);
-
-	return ret;
-}
-
-int uvc_export_buffer(struct uvc_video_queue *queue,
-		      struct v4l2_exportbuffer *exp)
-{
-	int ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_expbuf(&queue->queue, exp);
-	mutex_unlock(&queue->mutex);
-
-	return ret;
-}
-
-int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
-		       int nonblocking)
-{
-	int ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
-	mutex_unlock(&queue->mutex);
-
-	return ret;
-}
-
-int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type)
-{
-	int ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_streamon(&queue->queue, type);
-	mutex_unlock(&queue->mutex);
-
-	return ret;
-}
-
-int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type)
-{
-	int ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_streamoff(&queue->queue, type);
-	mutex_unlock(&queue->mutex);
-
-	return ret;
-}
-
-int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
-{
-	return vb2_mmap(&queue->queue, vma);
-}
-
-#ifndef CONFIG_MMU
-unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
-		unsigned long pgoff)
-{
-	return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
-}
-#endif
-
-__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
-			    poll_table *wait)
-{
-	__poll_t ret;
-
-	mutex_lock(&queue->mutex);
-	ret = vb2_poll(&queue->queue, file, wait);
-	mutex_unlock(&queue->mutex);
-
-	return ret;
-}
-
 /* -----------------------------------------------------------------------------
  *
  */
 
-/*
- * Check if buffers have been allocated.
- */
-int uvc_queue_allocated(struct uvc_video_queue *queue)
-{
-	int allocated;
-
-	mutex_lock(&queue->mutex);
-	allocated = vb2_is_busy(&queue->queue);
-	mutex_unlock(&queue->mutex);
-
-	return allocated;
-}
-
 /*
  * Cancel the video buffers queue.
  *
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 0f4d893eff46..e40db7ae18b1 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -352,17 +352,13 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
 		return ret;
 
 	mutex_lock(&stream->mutex);
-
-	if (uvc_queue_allocated(&stream->queue)) {
+	if (vb2_is_busy(&stream->queue.queue)) {
 		ret = -EBUSY;
-		goto done;
+	} else {
+		stream->ctrl = probe;
+		stream->cur_format = format;
+		stream->cur_frame = frame;
 	}
-
-	stream->ctrl = probe;
-	stream->cur_format = format;
-	stream->cur_frame = frame;
-
-done:
 	mutex_unlock(&stream->mutex);
 	return ret;
 }
@@ -489,62 +485,6 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
 	return 0;
 }
 
-/* ------------------------------------------------------------------------
- * Privilege management
- */
-
-/*
- * Privilege management is the multiple-open implementation basis. The current
- * implementation is completely transparent for the end-user and doesn't
- * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls.
- * Those ioctls enable finer control on the device (by making possible for a
- * user to request exclusive access to a device), but are not mature yet.
- * Switching to the V4L2 priority mechanism might be considered in the future
- * if this situation changes.
- *
- * Each open instance of a UVC device can either be in a privileged or
- * unprivileged state. Only a single instance can be in a privileged state at
- * a given time. Trying to perform an operation that requires privileges will
- * automatically acquire the required privileges if possible, or return -EBUSY
- * otherwise. Privileges are dismissed when closing the instance or when
- * freeing the video buffers using VIDIOC_REQBUFS.
- *
- * Operations that require privileges are:
- *
- * - VIDIOC_S_INPUT
- * - VIDIOC_S_PARM
- * - VIDIOC_S_FMT
- * - VIDIOC_REQBUFS
- */
-static int uvc_acquire_privileges(struct uvc_fh *handle)
-{
-	/* Always succeed if the handle is already privileged. */
-	if (handle->state == UVC_HANDLE_ACTIVE)
-		return 0;
-
-	/* Check if the device already has a privileged handle. */
-	if (atomic_inc_return(&handle->stream->active) != 1) {
-		atomic_dec(&handle->stream->active);
-		return -EBUSY;
-	}
-
-	handle->state = UVC_HANDLE_ACTIVE;
-	return 0;
-}
-
-static void uvc_dismiss_privileges(struct uvc_fh *handle)
-{
-	if (handle->state == UVC_HANDLE_ACTIVE)
-		atomic_dec(&handle->stream->active);
-
-	handle->state = UVC_HANDLE_PASSIVE;
-}
-
-static int uvc_has_privileges(struct uvc_fh *handle)
-{
-	return handle->state == UVC_HANDLE_ACTIVE;
-}
-
 /* ------------------------------------------------------------------------
  * V4L2 file operations
  */
@@ -587,7 +527,6 @@ static int uvc_v4l2_open(struct file *file)
 	v4l2_fh_add(&handle->vfh);
 	handle->chain = stream->chain;
 	handle->stream = stream;
-	handle->state = UVC_HANDLE_PASSIVE;
 	file->private_data = handle;
 
 	return 0;
@@ -600,15 +539,8 @@ static int uvc_v4l2_release(struct file *file)
 
 	uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
 
-	/* Only free resources if this is a privileged handle. */
-	if (uvc_has_privileges(handle))
-		uvc_queue_release(&stream->queue);
-
 	/* Release the file handle. */
-	uvc_dismiss_privileges(handle);
-	v4l2_fh_del(&handle->vfh);
-	v4l2_fh_exit(&handle->vfh);
-	kfree(handle);
+	vb2_fop_release(file);
 	file->private_data = NULL;
 
 	mutex_lock(&stream->dev->lock);
@@ -701,11 +633,6 @@ static int uvc_ioctl_s_fmt_vid_cap(struct file *file, void *fh,
 {
 	struct uvc_fh *handle = fh;
 	struct uvc_streaming *stream = handle->stream;
-	int ret;
-
-	ret = uvc_acquire_privileges(handle);
-	if (ret < 0)
-		return ret;
 
 	return uvc_v4l2_set_format(stream, fmt);
 }
@@ -715,11 +642,6 @@ static int uvc_ioctl_s_fmt_vid_out(struct file *file, void *fh,
 {
 	struct uvc_fh *handle = fh;
 	struct uvc_streaming *stream = handle->stream;
-	int ret;
-
-	ret = uvc_acquire_privileges(handle);
-	if (ret < 0)
-		return ret;
 
 	return uvc_v4l2_set_format(stream, fmt);
 }
@@ -744,124 +666,6 @@ static int uvc_ioctl_try_fmt_vid_out(struct file *file, void *fh,
 	return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL);
 }
 
-static int uvc_ioctl_reqbufs(struct file *file, void *fh,
-			     struct v4l2_requestbuffers *rb)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_streaming *stream = handle->stream;
-	int ret;
-
-	ret = uvc_acquire_privileges(handle);
-	if (ret < 0)
-		return ret;
-
-	mutex_lock(&stream->mutex);
-	ret = uvc_request_buffers(&stream->queue, rb);
-	mutex_unlock(&stream->mutex);
-	if (ret < 0)
-		return ret;
-
-	if (ret == 0)
-		uvc_dismiss_privileges(handle);
-
-	return 0;
-}
-
-static int uvc_ioctl_querybuf(struct file *file, void *fh,
-			      struct v4l2_buffer *buf)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_streaming *stream = handle->stream;
-
-	if (!uvc_has_privileges(handle))
-		return -EBUSY;
-
-	return uvc_query_buffer(&stream->queue, buf);
-}
-
-static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_streaming *stream = handle->stream;
-
-	if (!uvc_has_privileges(handle))
-		return -EBUSY;
-
-	return uvc_queue_buffer(&stream->queue,
-				stream->vdev.v4l2_dev->mdev, buf);
-}
-
-static int uvc_ioctl_expbuf(struct file *file, void *fh,
-			    struct v4l2_exportbuffer *exp)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_streaming *stream = handle->stream;
-
-	if (!uvc_has_privileges(handle))
-		return -EBUSY;
-
-	return uvc_export_buffer(&stream->queue, exp);
-}
-
-static int uvc_ioctl_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_streaming *stream = handle->stream;
-
-	if (!uvc_has_privileges(handle))
-		return -EBUSY;
-
-	return uvc_dequeue_buffer(&stream->queue, buf,
-				  file->f_flags & O_NONBLOCK);
-}
-
-static int uvc_ioctl_create_bufs(struct file *file, void *fh,
-				  struct v4l2_create_buffers *cb)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_streaming *stream = handle->stream;
-	int ret;
-
-	ret = uvc_acquire_privileges(handle);
-	if (ret < 0)
-		return ret;
-
-	return uvc_create_buffers(&stream->queue, cb);
-}
-
-static int uvc_ioctl_streamon(struct file *file, void *fh,
-			      enum v4l2_buf_type type)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_streaming *stream = handle->stream;
-	int ret;
-
-	if (!uvc_has_privileges(handle))
-		return -EBUSY;
-
-	mutex_lock(&stream->mutex);
-	ret = uvc_queue_streamon(&stream->queue, type);
-	mutex_unlock(&stream->mutex);
-
-	return ret;
-}
-
-static int uvc_ioctl_streamoff(struct file *file, void *fh,
-			       enum v4l2_buf_type type)
-{
-	struct uvc_fh *handle = fh;
-	struct uvc_streaming *stream = handle->stream;
-
-	if (!uvc_has_privileges(handle))
-		return -EBUSY;
-
-	mutex_lock(&stream->mutex);
-	uvc_queue_streamoff(&stream->queue, type);
-	mutex_unlock(&stream->mutex);
-
-	return 0;
-}
-
 static int uvc_ioctl_enum_input(struct file *file, void *fh,
 				struct v4l2_input *input)
 {
@@ -929,13 +733,12 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input)
 static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
 {
 	struct uvc_fh *handle = fh;
+	struct uvc_streaming *stream = handle->stream;
 	struct uvc_video_chain *chain = handle->chain;
-	int ret;
 	u32 i;
 
-	ret = uvc_acquire_privileges(handle);
-	if (ret < 0)
-		return ret;
+	if (vb2_is_busy(&stream->queue.queue))
+		return -EBUSY;
 
 	if (chain->selector == NULL ||
 	    (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
@@ -1166,11 +969,6 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh,
 {
 	struct uvc_fh *handle = fh;
 	struct uvc_streaming *stream = handle->stream;
-	int ret;
-
-	ret = uvc_acquire_privileges(handle);
-	if (ret < 0)
-		return ret;
 
 	return uvc_v4l2_set_streamparm(stream, parm);
 }
@@ -1438,50 +1236,6 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
 }
 #endif
 
-static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
-		    size_t count, loff_t *ppos)
-{
-	struct uvc_fh *handle = file->private_data;
-	struct uvc_streaming *stream = handle->stream;
-
-	uvc_dbg(stream->dev, CALLS, "%s: not implemented\n", __func__);
-	return -EINVAL;
-}
-
-static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct uvc_fh *handle = file->private_data;
-	struct uvc_streaming *stream = handle->stream;
-
-	uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
-
-	return uvc_queue_mmap(&stream->queue, vma);
-}
-
-static __poll_t uvc_v4l2_poll(struct file *file, poll_table *wait)
-{
-	struct uvc_fh *handle = file->private_data;
-	struct uvc_streaming *stream = handle->stream;
-
-	uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
-
-	return uvc_queue_poll(&stream->queue, file, wait);
-}
-
-#ifndef CONFIG_MMU
-static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
-		unsigned long addr, unsigned long len, unsigned long pgoff,
-		unsigned long flags)
-{
-	struct uvc_fh *handle = file->private_data;
-	struct uvc_streaming *stream = handle->stream;
-
-	uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
-
-	return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
-}
-#endif
-
 const struct v4l2_ioctl_ops uvc_ioctl_ops = {
 	.vidioc_querycap = uvc_ioctl_querycap,
 	.vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt_vid_cap,
@@ -1492,14 +1246,15 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = {
 	.vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt_vid_out,
 	.vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt_vid_cap,
 	.vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt_vid_out,
-	.vidioc_reqbufs = uvc_ioctl_reqbufs,
-	.vidioc_querybuf = uvc_ioctl_querybuf,
-	.vidioc_qbuf = uvc_ioctl_qbuf,
-	.vidioc_expbuf = uvc_ioctl_expbuf,
-	.vidioc_dqbuf = uvc_ioctl_dqbuf,
-	.vidioc_create_bufs = uvc_ioctl_create_bufs,
-	.vidioc_streamon = uvc_ioctl_streamon,
-	.vidioc_streamoff = uvc_ioctl_streamoff,
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
 	.vidioc_enum_input = uvc_ioctl_enum_input,
 	.vidioc_g_input = uvc_ioctl_g_input,
 	.vidioc_s_input = uvc_ioctl_s_input,
@@ -1527,11 +1282,10 @@ const struct v4l2_file_operations uvc_fops = {
 #ifdef CONFIG_COMPAT
 	.compat_ioctl32	= uvc_v4l2_compat_ioctl32,
 #endif
-	.read		= uvc_v4l2_read,
-	.mmap		= uvc_v4l2_mmap,
-	.poll		= uvc_v4l2_poll,
+	.mmap		= vb2_fop_mmap,
+	.poll		= vb2_fop_poll,
 #ifndef CONFIG_MMU
-	.get_unmapped_area = uvc_v4l2_get_unmapped_area,
+	.get_unmapped_area = vb2_fop_get_unmapped_area,
 #endif
 };
 
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index fd4f5ef47dfb..a087d66d2105 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -474,7 +474,6 @@ struct uvc_video_chain {
 
 	struct mutex ctrl_mutex;		/* Protects ctrl.info */
 
-	struct v4l2_prio_state prio;		/* V4L2 priority state */
 	u32 caps;				/* V4L2 chain-wide caps */
 	u8 ctrl_class_bitmap;			/* Bitmap of valid classes */
 };
@@ -713,16 +712,10 @@ struct uvc_device {
 	struct uvc_entity *gpio_unit;
 };
 
-enum uvc_handle_state {
-	UVC_HANDLE_PASSIVE	= 0,
-	UVC_HANDLE_ACTIVE	= 1,
-};
-
 struct uvc_fh {
 	struct v4l2_fh vfh;
 	struct uvc_video_chain *chain;
 	struct uvc_streaming *stream;
-	enum uvc_handle_state state;
 };
 
 struct uvc_driver {
@@ -787,36 +780,11 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
 /* Video buffers queue management. */
 int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
 		   int drop_corrupted);
-void uvc_queue_release(struct uvc_video_queue *queue);
-int uvc_request_buffers(struct uvc_video_queue *queue,
-			struct v4l2_requestbuffers *rb);
-int uvc_query_buffer(struct uvc_video_queue *queue,
-		     struct v4l2_buffer *v4l2_buf);
-int uvc_create_buffers(struct uvc_video_queue *queue,
-		       struct v4l2_create_buffers *v4l2_cb);
-int uvc_queue_buffer(struct uvc_video_queue *queue,
-		     struct media_device *mdev,
-		     struct v4l2_buffer *v4l2_buf);
-int uvc_export_buffer(struct uvc_video_queue *queue,
-		      struct v4l2_exportbuffer *exp);
-int uvc_dequeue_buffer(struct uvc_video_queue *queue,
-		       struct v4l2_buffer *v4l2_buf, int nonblocking);
-int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type);
-int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type);
 void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
 struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
 					 struct uvc_buffer *buf);
 struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue);
 void uvc_queue_buffer_release(struct uvc_buffer *buf);
-int uvc_queue_mmap(struct uvc_video_queue *queue,
-		   struct vm_area_struct *vma);
-__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
-			poll_table *wait);
-#ifndef CONFIG_MMU
-unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
-					  unsigned long pgoff);
-#endif
-int uvc_queue_allocated(struct uvc_video_queue *queue);
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
 	return vb2_is_streaming(&queue->queue);
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls
  2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
                   ` (19 preceding siblings ...)
  2021-06-18 12:29 ` [PATCH v10 20/21] uvc: use vb2 ioctl and fop helpers Ricardo Ribalda
@ 2021-06-18 12:29 ` Ricardo Ribalda
  2021-06-25 10:29   ` Ricardo Ribalda
  20 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-18 12:29 UTC (permalink / raw)
  To: Laurent Pinchart, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga
  Cc: Ricardo Ribalda

If a control is inactive return -EACCES to let the userspace know that
the value will not be applied automatically when the control is active
again.

Also make sure that query_v4l2_ctrl doesn't return an error.

Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 73 +++++++++++++++++++++-----------
 1 file changed, 49 insertions(+), 24 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index da44d5c0b9ad..4f80c06d3c43 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1104,13 +1104,36 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
 	return "Unknown Control";
 }
 
+static bool uvc_ctrl_is_inactive(struct uvc_video_chain *chain,
+				 struct uvc_control *ctrl,
+				 struct uvc_control_mapping *mapping)
+{
+	struct uvc_control_mapping *master_map = NULL;
+	struct uvc_control *master_ctrl = NULL;
+	s32 val;
+	int ret;
+
+	if (!mapping->master_id)
+		return false;
+
+	__uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
+			   &master_ctrl, 0);
+
+	if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
+		return false;
+
+	ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
+	if (ret < 0 || val == mapping->master_manual)
+		return false;
+
+	return true;
+}
+
 static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 	struct uvc_control *ctrl,
 	struct uvc_control_mapping *mapping,
 	struct v4l2_queryctrl *v4l2_ctrl)
 {
-	struct uvc_control_mapping *master_map = NULL;
-	struct uvc_control *master_ctrl = NULL;
 	const struct uvc_menu_info *menu;
 	unsigned int i;
 
@@ -1126,18 +1149,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 	if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
 		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
-	if (mapping->master_id)
-		__uvc_find_control(ctrl->entity, mapping->master_id,
-				   &master_map, &master_ctrl, 0);
-	if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
-		s32 val;
-		int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
-		if (ret < 0)
-			return ret;
-
-		if (val != mapping->master_manual)
-				v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-	}
+	if (uvc_ctrl_is_inactive(chain, ctrl, mapping))
+		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 
 	if (!ctrl->cached) {
 		int ret = uvc_ctrl_populate_cache(chain, ctrl);
@@ -1660,25 +1673,37 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
 	return 0;
 }
 
-static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
-				  struct v4l2_ext_controls *ctrls,
-				  struct uvc_control *uvc_control)
+static int uvc_ctrl_commit_error(struct uvc_video_chain *chain,
+				 struct uvc_entity *entity,
+				 struct v4l2_ext_controls *ctrls,
+				 struct uvc_control *err_control,
+				 int ret)
 {
 	struct uvc_control_mapping *mapping;
 	struct uvc_control *ctrl_found;
 	unsigned int i;
 
-	if (!entity)
-		return ctrls->count;
+	if (!entity) {
+		ctrls->error_idx = ctrls->count;
+		return ret;
+	}
 
 	for (i = 0; i < ctrls->count; i++) {
 		__uvc_find_control(entity, ctrls->controls[i].id, &mapping,
 				   &ctrl_found, 0);
-		if (uvc_control == ctrl_found)
-			return i;
+		if (err_control == ctrl_found)
+			break;
 	}
+	ctrls->error_idx = i;
+
+	/* We could not find the control that failed. */
+	if (i == ctrls->count)
+		return ret;
+
+	if (uvc_ctrl_is_inactive(chain, err_control, mapping))
+		return -EACCES;
 
-	return ctrls->count;
+	return ret;
 }
 
 int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
@@ -1701,8 +1726,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
 		uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
 done:
 	if (ret < 0 && ctrls)
-		ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
-							  err_ctrl);
+		ret = uvc_ctrl_commit_error(chain, entity, ctrls, err_ctrl,
+					    ret);
 	mutex_unlock(&chain->ctrl_mutex);
 	return ret;
 }
-- 
2.32.0.288.g62a8d224e6-goog


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls
  2021-06-18 12:29 ` [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls Ricardo Ribalda
@ 2021-06-25 10:29   ` Ricardo Ribalda
  2021-06-25 11:06     ` Hans Verkuil
  0 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-25 10:29 UTC (permalink / raw)
  To: Hans Verkuil, Hans Verkuil
  Cc: Laurent Pinchart, Mauro Carvalho Chehab, linux-media, tfiga,
	Sergey Senozhatsky, linux-kernel

Hi Hans

Did you have some hardware that did not work fine without this patch?
Am I remembering correctly?

Thanks!

On Fri, 18 Jun 2021 at 14:29, Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> If a control is inactive return -EACCES to let the userspace know that
> the value will not be applied automatically when the control is active
> again.
>
> Also make sure that query_v4l2_ctrl doesn't return an error.
>
> Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 73 +++++++++++++++++++++-----------
>  1 file changed, 49 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index da44d5c0b9ad..4f80c06d3c43 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1104,13 +1104,36 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
>         return "Unknown Control";
>  }
>
> +static bool uvc_ctrl_is_inactive(struct uvc_video_chain *chain,
> +                                struct uvc_control *ctrl,
> +                                struct uvc_control_mapping *mapping)
> +{
> +       struct uvc_control_mapping *master_map = NULL;
> +       struct uvc_control *master_ctrl = NULL;
> +       s32 val;
> +       int ret;
> +
> +       if (!mapping->master_id)
> +               return false;
> +
> +       __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
> +                          &master_ctrl, 0);
> +
> +       if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> +               return false;
> +
> +       ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> +       if (ret < 0 || val == mapping->master_manual)
> +               return false;
> +
> +       return true;
> +}
> +
>  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>         struct uvc_control *ctrl,
>         struct uvc_control_mapping *mapping,
>         struct v4l2_queryctrl *v4l2_ctrl)
>  {
> -       struct uvc_control_mapping *master_map = NULL;
> -       struct uvc_control *master_ctrl = NULL;
>         const struct uvc_menu_info *menu;
>         unsigned int i;
>
> @@ -1126,18 +1149,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>         if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
>                 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
> -       if (mapping->master_id)
> -               __uvc_find_control(ctrl->entity, mapping->master_id,
> -                                  &master_map, &master_ctrl, 0);
> -       if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> -               s32 val;
> -               int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> -               if (ret < 0)
> -                       return ret;
> -
> -               if (val != mapping->master_manual)
> -                               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> -       }
> +       if (uvc_ctrl_is_inactive(chain, ctrl, mapping))
> +               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
>
>         if (!ctrl->cached) {
>                 int ret = uvc_ctrl_populate_cache(chain, ctrl);
> @@ -1660,25 +1673,37 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
>         return 0;
>  }
>
> -static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
> -                                 struct v4l2_ext_controls *ctrls,
> -                                 struct uvc_control *uvc_control)
> +static int uvc_ctrl_commit_error(struct uvc_video_chain *chain,
> +                                struct uvc_entity *entity,
> +                                struct v4l2_ext_controls *ctrls,
> +                                struct uvc_control *err_control,
> +                                int ret)
>  {
>         struct uvc_control_mapping *mapping;
>         struct uvc_control *ctrl_found;
>         unsigned int i;
>
> -       if (!entity)
> -               return ctrls->count;
> +       if (!entity) {
> +               ctrls->error_idx = ctrls->count;
> +               return ret;
> +       }
>
>         for (i = 0; i < ctrls->count; i++) {
>                 __uvc_find_control(entity, ctrls->controls[i].id, &mapping,
>                                    &ctrl_found, 0);
> -               if (uvc_control == ctrl_found)
> -                       return i;
> +               if (err_control == ctrl_found)
> +                       break;
>         }
> +       ctrls->error_idx = i;
> +
> +       /* We could not find the control that failed. */
> +       if (i == ctrls->count)
> +               return ret;
> +
> +       if (uvc_ctrl_is_inactive(chain, err_control, mapping))
> +               return -EACCES;
>
> -       return ctrls->count;
> +       return ret;
>  }
>
>  int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> @@ -1701,8 +1726,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
>                 uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
>  done:
>         if (ret < 0 && ctrls)
> -               ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
> -                                                         err_ctrl);
> +               ret = uvc_ctrl_commit_error(chain, entity, ctrls, err_ctrl,
> +                                           ret);
>         mutex_unlock(&chain->ctrl_mutex);
>         return ret;
>  }
> --
> 2.32.0.288.g62a8d224e6-goog
>


-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls
  2021-06-25 10:29   ` Ricardo Ribalda
@ 2021-06-25 11:06     ` Hans Verkuil
  2021-06-25 13:55       ` Ricardo Ribalda
  0 siblings, 1 reply; 39+ messages in thread
From: Hans Verkuil @ 2021-06-25 11:06 UTC (permalink / raw)
  To: Ricardo Ribalda, Hans Verkuil
  Cc: Laurent Pinchart, Mauro Carvalho Chehab, linux-media, tfiga,
	Sergey Senozhatsky, linux-kernel

On 25/06/2021 12:29, Ricardo Ribalda wrote:
> Hi Hans
> 
> Did you have some hardware that did not work fine without this patch?
> Am I remembering correctly?

Yes, that's correct. It's one of my webcams, but I can't remember which one
it is. You probably want me to test this v10?

Regards,

	Hans

> 
> Thanks!
> 
> On Fri, 18 Jun 2021 at 14:29, Ricardo Ribalda <ribalda@chromium.org> wrote:
>>
>> If a control is inactive return -EACCES to let the userspace know that
>> the value will not be applied automatically when the control is active
>> again.
>>
>> Also make sure that query_v4l2_ctrl doesn't return an error.
>>
>> Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
>> ---
>>  drivers/media/usb/uvc/uvc_ctrl.c | 73 +++++++++++++++++++++-----------
>>  1 file changed, 49 insertions(+), 24 deletions(-)
>>
>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
>> index da44d5c0b9ad..4f80c06d3c43 100644
>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>> @@ -1104,13 +1104,36 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
>>         return "Unknown Control";
>>  }
>>
>> +static bool uvc_ctrl_is_inactive(struct uvc_video_chain *chain,
>> +                                struct uvc_control *ctrl,
>> +                                struct uvc_control_mapping *mapping)
>> +{
>> +       struct uvc_control_mapping *master_map = NULL;
>> +       struct uvc_control *master_ctrl = NULL;
>> +       s32 val;
>> +       int ret;
>> +
>> +       if (!mapping->master_id)
>> +               return false;
>> +
>> +       __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
>> +                          &master_ctrl, 0);
>> +
>> +       if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
>> +               return false;
>> +
>> +       ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
>> +       if (ret < 0 || val == mapping->master_manual)
>> +               return false;
>> +
>> +       return true;
>> +}
>> +
>>  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>>         struct uvc_control *ctrl,
>>         struct uvc_control_mapping *mapping,
>>         struct v4l2_queryctrl *v4l2_ctrl)
>>  {
>> -       struct uvc_control_mapping *master_map = NULL;
>> -       struct uvc_control *master_ctrl = NULL;
>>         const struct uvc_menu_info *menu;
>>         unsigned int i;
>>
>> @@ -1126,18 +1149,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>>         if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
>>                 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>>
>> -       if (mapping->master_id)
>> -               __uvc_find_control(ctrl->entity, mapping->master_id,
>> -                                  &master_map, &master_ctrl, 0);
>> -       if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
>> -               s32 val;
>> -               int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
>> -               if (ret < 0)
>> -                       return ret;
>> -
>> -               if (val != mapping->master_manual)
>> -                               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
>> -       }
>> +       if (uvc_ctrl_is_inactive(chain, ctrl, mapping))
>> +               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
>>
>>         if (!ctrl->cached) {
>>                 int ret = uvc_ctrl_populate_cache(chain, ctrl);
>> @@ -1660,25 +1673,37 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
>>         return 0;
>>  }
>>
>> -static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
>> -                                 struct v4l2_ext_controls *ctrls,
>> -                                 struct uvc_control *uvc_control)
>> +static int uvc_ctrl_commit_error(struct uvc_video_chain *chain,
>> +                                struct uvc_entity *entity,
>> +                                struct v4l2_ext_controls *ctrls,
>> +                                struct uvc_control *err_control,
>> +                                int ret)
>>  {
>>         struct uvc_control_mapping *mapping;
>>         struct uvc_control *ctrl_found;
>>         unsigned int i;
>>
>> -       if (!entity)
>> -               return ctrls->count;
>> +       if (!entity) {
>> +               ctrls->error_idx = ctrls->count;
>> +               return ret;
>> +       }
>>
>>         for (i = 0; i < ctrls->count; i++) {
>>                 __uvc_find_control(entity, ctrls->controls[i].id, &mapping,
>>                                    &ctrl_found, 0);
>> -               if (uvc_control == ctrl_found)
>> -                       return i;
>> +               if (err_control == ctrl_found)
>> +                       break;
>>         }
>> +       ctrls->error_idx = i;
>> +
>> +       /* We could not find the control that failed. */
>> +       if (i == ctrls->count)
>> +               return ret;
>> +
>> +       if (uvc_ctrl_is_inactive(chain, err_control, mapping))
>> +               return -EACCES;
>>
>> -       return ctrls->count;
>> +       return ret;
>>  }
>>
>>  int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
>> @@ -1701,8 +1726,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
>>                 uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
>>  done:
>>         if (ret < 0 && ctrls)
>> -               ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
>> -                                                         err_ctrl);
>> +               ret = uvc_ctrl_commit_error(chain, entity, ctrls, err_ctrl,
>> +                                           ret);
>>         mutex_unlock(&chain->ctrl_mutex);
>>         return ret;
>>  }
>> --
>> 2.32.0.288.g62a8d224e6-goog
>>
> 
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls
  2021-06-25 11:06     ` Hans Verkuil
@ 2021-06-25 13:55       ` Ricardo Ribalda
  2021-06-30  9:02         ` Hans Verkuil
  0 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-25 13:55 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Hans Verkuil, Laurent Pinchart, Mauro Carvalho Chehab,
	linux-media, tfiga, Sergey Senozhatsky, linux-kernel

Hi Hans

On Fri, 25 Jun 2021 at 13:07, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>
> On 25/06/2021 12:29, Ricardo Ribalda wrote:
> > Hi Hans
> >
> > Did you have some hardware that did not work fine without this patch?
> > Am I remembering correctly?
>
> Yes, that's correct. It's one of my webcams, but I can't remember which one
> it is. You probably want me to test this v10?
>
> Regards,

That would be awesome. Thanks!

>
>         Hans
>
> >
> > Thanks!
> >
> > On Fri, 18 Jun 2021 at 14:29, Ricardo Ribalda <ribalda@chromium.org> wrote:
> >>
> >> If a control is inactive return -EACCES to let the userspace know that
> >> the value will not be applied automatically when the control is active
> >> again.
> >>
> >> Also make sure that query_v4l2_ctrl doesn't return an error.
> >>
> >> Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> >> ---
> >>  drivers/media/usb/uvc/uvc_ctrl.c | 73 +++++++++++++++++++++-----------
> >>  1 file changed, 49 insertions(+), 24 deletions(-)
> >>
> >> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> >> index da44d5c0b9ad..4f80c06d3c43 100644
> >> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> >> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> >> @@ -1104,13 +1104,36 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
> >>         return "Unknown Control";
> >>  }
> >>
> >> +static bool uvc_ctrl_is_inactive(struct uvc_video_chain *chain,
> >> +                                struct uvc_control *ctrl,
> >> +                                struct uvc_control_mapping *mapping)
> >> +{
> >> +       struct uvc_control_mapping *master_map = NULL;
> >> +       struct uvc_control *master_ctrl = NULL;
> >> +       s32 val;
> >> +       int ret;
> >> +
> >> +       if (!mapping->master_id)
> >> +               return false;
> >> +
> >> +       __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
> >> +                          &master_ctrl, 0);
> >> +
> >> +       if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> >> +               return false;
> >> +
> >> +       ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> >> +       if (ret < 0 || val == mapping->master_manual)
> >> +               return false;
> >> +
> >> +       return true;
> >> +}
> >> +
> >>  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> >>         struct uvc_control *ctrl,
> >>         struct uvc_control_mapping *mapping,
> >>         struct v4l2_queryctrl *v4l2_ctrl)
> >>  {
> >> -       struct uvc_control_mapping *master_map = NULL;
> >> -       struct uvc_control *master_ctrl = NULL;
> >>         const struct uvc_menu_info *menu;
> >>         unsigned int i;
> >>
> >> @@ -1126,18 +1149,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> >>         if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> >>                 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> >>
> >> -       if (mapping->master_id)
> >> -               __uvc_find_control(ctrl->entity, mapping->master_id,
> >> -                                  &master_map, &master_ctrl, 0);
> >> -       if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> >> -               s32 val;
> >> -               int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> >> -               if (ret < 0)
> >> -                       return ret;
> >> -
> >> -               if (val != mapping->master_manual)
> >> -                               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> >> -       }
> >> +       if (uvc_ctrl_is_inactive(chain, ctrl, mapping))
> >> +               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> >>
> >>         if (!ctrl->cached) {
> >>                 int ret = uvc_ctrl_populate_cache(chain, ctrl);
> >> @@ -1660,25 +1673,37 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
> >>         return 0;
> >>  }
> >>
> >> -static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
> >> -                                 struct v4l2_ext_controls *ctrls,
> >> -                                 struct uvc_control *uvc_control)
> >> +static int uvc_ctrl_commit_error(struct uvc_video_chain *chain,
> >> +                                struct uvc_entity *entity,
> >> +                                struct v4l2_ext_controls *ctrls,
> >> +                                struct uvc_control *err_control,
> >> +                                int ret)
> >>  {
> >>         struct uvc_control_mapping *mapping;
> >>         struct uvc_control *ctrl_found;
> >>         unsigned int i;
> >>
> >> -       if (!entity)
> >> -               return ctrls->count;
> >> +       if (!entity) {
> >> +               ctrls->error_idx = ctrls->count;
> >> +               return ret;
> >> +       }
> >>
> >>         for (i = 0; i < ctrls->count; i++) {
> >>                 __uvc_find_control(entity, ctrls->controls[i].id, &mapping,
> >>                                    &ctrl_found, 0);
> >> -               if (uvc_control == ctrl_found)
> >> -                       return i;
> >> +               if (err_control == ctrl_found)
> >> +                       break;
> >>         }
> >> +       ctrls->error_idx = i;
> >> +
> >> +       /* We could not find the control that failed. */
> >> +       if (i == ctrls->count)
> >> +               return ret;
> >> +
> >> +       if (uvc_ctrl_is_inactive(chain, err_control, mapping))
> >> +               return -EACCES;
> >>
> >> -       return ctrls->count;
> >> +       return ret;
> >>  }
> >>
> >>  int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> >> @@ -1701,8 +1726,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> >>                 uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
> >>  done:
> >>         if (ret < 0 && ctrls)
> >> -               ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
> >> -                                                         err_ctrl);
> >> +               ret = uvc_ctrl_commit_error(chain, entity, ctrls, err_ctrl,
> >> +                                           ret);
> >>         mutex_unlock(&chain->ctrl_mutex);
> >>         return ret;
> >>  }
> >> --
> >> 2.32.0.288.g62a8d224e6-goog
> >>
> >
> >
>


-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls
  2021-06-25 13:55       ` Ricardo Ribalda
@ 2021-06-30  9:02         ` Hans Verkuil
  2021-06-30 12:51           ` Ricardo Ribalda
  0 siblings, 1 reply; 39+ messages in thread
From: Hans Verkuil @ 2021-06-30  9:02 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Hans Verkuil, Laurent Pinchart, Mauro Carvalho Chehab,
	linux-media, tfiga, Sergey Senozhatsky, linux-kernel

Hi Ricardo,

On 25/06/2021 15:55, Ricardo Ribalda wrote:
> Hi Hans
> 
> On Fri, 25 Jun 2021 at 13:07, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>>
>> On 25/06/2021 12:29, Ricardo Ribalda wrote:
>>> Hi Hans
>>>
>>> Did you have some hardware that did not work fine without this patch?
>>> Am I remembering correctly?
>>
>> Yes, that's correct. It's one of my webcams, but I can't remember which one
>> it is. You probably want me to test this v10?
>>
>> Regards,
> 
> That would be awesome. Thanks!

You can add my:

Tested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>

to this series.

I do get these warnings (depends on the webcam model, though, some do, some don't):

Streaming ioctls:
        test read/write: OK (Not Supported)
        test blocking wait: OK
                warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
        test MMAP (no poll): OK
                warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
        test MMAP (select): OK
                warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
        test MMAP (epoll): OK
                warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
        test USERPTR (no poll): OK
                warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
        test USERPTR (select): OK
        test DMABUF: Cannot test, specify --expbuf-device

It's something to do with the Field ID, but I'm not sure if this is really correctly
reporting a dropped frame, or if it is a false report and the sequence counter was
wrongly incremented.

This is a separate issue, though, and doesn't block this series.

Regards,

	Hans

> 
>>
>>         Hans
>>
>>>
>>> Thanks!
>>>
>>> On Fri, 18 Jun 2021 at 14:29, Ricardo Ribalda <ribalda@chromium.org> wrote:
>>>>
>>>> If a control is inactive return -EACCES to let the userspace know that
>>>> the value will not be applied automatically when the control is active
>>>> again.
>>>>
>>>> Also make sure that query_v4l2_ctrl doesn't return an error.
>>>>
>>>> Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>>>> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>>>> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
>>>> ---
>>>>  drivers/media/usb/uvc/uvc_ctrl.c | 73 +++++++++++++++++++++-----------
>>>>  1 file changed, 49 insertions(+), 24 deletions(-)
>>>>
>>>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
>>>> index da44d5c0b9ad..4f80c06d3c43 100644
>>>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>>>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>>>> @@ -1104,13 +1104,36 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
>>>>         return "Unknown Control";
>>>>  }
>>>>
>>>> +static bool uvc_ctrl_is_inactive(struct uvc_video_chain *chain,
>>>> +                                struct uvc_control *ctrl,
>>>> +                                struct uvc_control_mapping *mapping)
>>>> +{
>>>> +       struct uvc_control_mapping *master_map = NULL;
>>>> +       struct uvc_control *master_ctrl = NULL;
>>>> +       s32 val;
>>>> +       int ret;
>>>> +
>>>> +       if (!mapping->master_id)
>>>> +               return false;
>>>> +
>>>> +       __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
>>>> +                          &master_ctrl, 0);
>>>> +
>>>> +       if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
>>>> +               return false;
>>>> +
>>>> +       ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
>>>> +       if (ret < 0 || val == mapping->master_manual)
>>>> +               return false;
>>>> +
>>>> +       return true;
>>>> +}
>>>> +
>>>>  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>>>>         struct uvc_control *ctrl,
>>>>         struct uvc_control_mapping *mapping,
>>>>         struct v4l2_queryctrl *v4l2_ctrl)
>>>>  {
>>>> -       struct uvc_control_mapping *master_map = NULL;
>>>> -       struct uvc_control *master_ctrl = NULL;
>>>>         const struct uvc_menu_info *menu;
>>>>         unsigned int i;
>>>>
>>>> @@ -1126,18 +1149,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>>>>         if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
>>>>                 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>>>>
>>>> -       if (mapping->master_id)
>>>> -               __uvc_find_control(ctrl->entity, mapping->master_id,
>>>> -                                  &master_map, &master_ctrl, 0);
>>>> -       if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
>>>> -               s32 val;
>>>> -               int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
>>>> -               if (ret < 0)
>>>> -                       return ret;
>>>> -
>>>> -               if (val != mapping->master_manual)
>>>> -                               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
>>>> -       }
>>>> +       if (uvc_ctrl_is_inactive(chain, ctrl, mapping))
>>>> +               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
>>>>
>>>>         if (!ctrl->cached) {
>>>>                 int ret = uvc_ctrl_populate_cache(chain, ctrl);
>>>> @@ -1660,25 +1673,37 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
>>>>         return 0;
>>>>  }
>>>>
>>>> -static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
>>>> -                                 struct v4l2_ext_controls *ctrls,
>>>> -                                 struct uvc_control *uvc_control)
>>>> +static int uvc_ctrl_commit_error(struct uvc_video_chain *chain,
>>>> +                                struct uvc_entity *entity,
>>>> +                                struct v4l2_ext_controls *ctrls,
>>>> +                                struct uvc_control *err_control,
>>>> +                                int ret)
>>>>  {
>>>>         struct uvc_control_mapping *mapping;
>>>>         struct uvc_control *ctrl_found;
>>>>         unsigned int i;
>>>>
>>>> -       if (!entity)
>>>> -               return ctrls->count;
>>>> +       if (!entity) {
>>>> +               ctrls->error_idx = ctrls->count;
>>>> +               return ret;
>>>> +       }
>>>>
>>>>         for (i = 0; i < ctrls->count; i++) {
>>>>                 __uvc_find_control(entity, ctrls->controls[i].id, &mapping,
>>>>                                    &ctrl_found, 0);
>>>> -               if (uvc_control == ctrl_found)
>>>> -                       return i;
>>>> +               if (err_control == ctrl_found)
>>>> +                       break;
>>>>         }
>>>> +       ctrls->error_idx = i;
>>>> +
>>>> +       /* We could not find the control that failed. */
>>>> +       if (i == ctrls->count)
>>>> +               return ret;
>>>> +
>>>> +       if (uvc_ctrl_is_inactive(chain, err_control, mapping))
>>>> +               return -EACCES;
>>>>
>>>> -       return ctrls->count;
>>>> +       return ret;
>>>>  }
>>>>
>>>>  int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
>>>> @@ -1701,8 +1726,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
>>>>                 uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
>>>>  done:
>>>>         if (ret < 0 && ctrls)
>>>> -               ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
>>>> -                                                         err_ctrl);
>>>> +               ret = uvc_ctrl_commit_error(chain, entity, ctrls, err_ctrl,
>>>> +                                           ret);
>>>>         mutex_unlock(&chain->ctrl_mutex);
>>>>         return ret;
>>>>  }
>>>> --
>>>> 2.32.0.288.g62a8d224e6-goog
>>>>
>>>
>>>
>>
> 
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls
  2021-06-30  9:02         ` Hans Verkuil
@ 2021-06-30 12:51           ` Ricardo Ribalda
  2021-07-06 14:18             ` Hans Verkuil
  0 siblings, 1 reply; 39+ messages in thread
From: Ricardo Ribalda @ 2021-06-30 12:51 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Hans Verkuil, Laurent Pinchart, Mauro Carvalho Chehab,
	linux-media, tfiga, Sergey Senozhatsky, linux-kernel

Hi Hans


On Wed, 30 Jun 2021 at 11:03, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>
> Hi Ricardo,
>
> On 25/06/2021 15:55, Ricardo Ribalda wrote:
> > Hi Hans
> >
> > On Fri, 25 Jun 2021 at 13:07, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> >>
> >> On 25/06/2021 12:29, Ricardo Ribalda wrote:
> >>> Hi Hans
> >>>
> >>> Did you have some hardware that did not work fine without this patch?
> >>> Am I remembering correctly?
> >>
> >> Yes, that's correct. It's one of my webcams, but I can't remember which one
> >> it is. You probably want me to test this v10?
> >>
> >> Regards,
> >
> > That would be awesome. Thanks!
>
> You can add my:
>
> Tested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>

Thanks a lot for testing it!

Sorry to bother you, but could I ask you to try again, but with this
patch reverted? This is v10 1-20, without 21/21


Thanks!
>
> to this series.
>
> I do get these warnings (depends on the webcam model, though, some do, some don't):
>
> Streaming ioctls:
>         test read/write: OK (Not Supported)
>         test blocking wait: OK
>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>         test MMAP (no poll): OK
>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>         test MMAP (select): OK
>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>         test MMAP (epoll): OK
>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>         test USERPTR (no poll): OK
>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>         test USERPTR (select): OK
>         test DMABUF: Cannot test, specify --expbuf-device
>
> It's something to do with the Field ID, but I'm not sure if this is really correctly
> reporting a dropped frame, or if it is a false report and the sequence counter was
> wrongly incremented.
>
> This is a separate issue, though, and doesn't block this series.
>
> Regards,
>
>         Hans
>
> >
> >>
> >>         Hans
> >>
> >>>
> >>> Thanks!
> >>>
> >>> On Fri, 18 Jun 2021 at 14:29, Ricardo Ribalda <ribalda@chromium.org> wrote:
> >>>>
> >>>> If a control is inactive return -EACCES to let the userspace know that
> >>>> the value will not be applied automatically when the control is active
> >>>> again.
> >>>>
> >>>> Also make sure that query_v4l2_ctrl doesn't return an error.
> >>>>
> >>>> Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >>>> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >>>> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> >>>> ---
> >>>>  drivers/media/usb/uvc/uvc_ctrl.c | 73 +++++++++++++++++++++-----------
> >>>>  1 file changed, 49 insertions(+), 24 deletions(-)
> >>>>
> >>>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> >>>> index da44d5c0b9ad..4f80c06d3c43 100644
> >>>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> >>>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> >>>> @@ -1104,13 +1104,36 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
> >>>>         return "Unknown Control";
> >>>>  }
> >>>>
> >>>> +static bool uvc_ctrl_is_inactive(struct uvc_video_chain *chain,
> >>>> +                                struct uvc_control *ctrl,
> >>>> +                                struct uvc_control_mapping *mapping)
> >>>> +{
> >>>> +       struct uvc_control_mapping *master_map = NULL;
> >>>> +       struct uvc_control *master_ctrl = NULL;
> >>>> +       s32 val;
> >>>> +       int ret;
> >>>> +
> >>>> +       if (!mapping->master_id)
> >>>> +               return false;
> >>>> +
> >>>> +       __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
> >>>> +                          &master_ctrl, 0);
> >>>> +
> >>>> +       if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> >>>> +               return false;
> >>>> +
> >>>> +       ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> >>>> +       if (ret < 0 || val == mapping->master_manual)
> >>>> +               return false;
> >>>> +
> >>>> +       return true;
> >>>> +}
> >>>> +
> >>>>  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> >>>>         struct uvc_control *ctrl,
> >>>>         struct uvc_control_mapping *mapping,
> >>>>         struct v4l2_queryctrl *v4l2_ctrl)
> >>>>  {
> >>>> -       struct uvc_control_mapping *master_map = NULL;
> >>>> -       struct uvc_control *master_ctrl = NULL;
> >>>>         const struct uvc_menu_info *menu;
> >>>>         unsigned int i;
> >>>>
> >>>> @@ -1126,18 +1149,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> >>>>         if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> >>>>                 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> >>>>
> >>>> -       if (mapping->master_id)
> >>>> -               __uvc_find_control(ctrl->entity, mapping->master_id,
> >>>> -                                  &master_map, &master_ctrl, 0);
> >>>> -       if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> >>>> -               s32 val;
> >>>> -               int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> >>>> -               if (ret < 0)
> >>>> -                       return ret;
> >>>> -
> >>>> -               if (val != mapping->master_manual)
> >>>> -                               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> >>>> -       }
> >>>> +       if (uvc_ctrl_is_inactive(chain, ctrl, mapping))
> >>>> +               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> >>>>
> >>>>         if (!ctrl->cached) {
> >>>>                 int ret = uvc_ctrl_populate_cache(chain, ctrl);
> >>>> @@ -1660,25 +1673,37 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
> >>>>         return 0;
> >>>>  }
> >>>>
> >>>> -static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
> >>>> -                                 struct v4l2_ext_controls *ctrls,
> >>>> -                                 struct uvc_control *uvc_control)
> >>>> +static int uvc_ctrl_commit_error(struct uvc_video_chain *chain,
> >>>> +                                struct uvc_entity *entity,
> >>>> +                                struct v4l2_ext_controls *ctrls,
> >>>> +                                struct uvc_control *err_control,
> >>>> +                                int ret)
> >>>>  {
> >>>>         struct uvc_control_mapping *mapping;
> >>>>         struct uvc_control *ctrl_found;
> >>>>         unsigned int i;
> >>>>
> >>>> -       if (!entity)
> >>>> -               return ctrls->count;
> >>>> +       if (!entity) {
> >>>> +               ctrls->error_idx = ctrls->count;
> >>>> +               return ret;
> >>>> +       }
> >>>>
> >>>>         for (i = 0; i < ctrls->count; i++) {
> >>>>                 __uvc_find_control(entity, ctrls->controls[i].id, &mapping,
> >>>>                                    &ctrl_found, 0);
> >>>> -               if (uvc_control == ctrl_found)
> >>>> -                       return i;
> >>>> +               if (err_control == ctrl_found)
> >>>> +                       break;
> >>>>         }
> >>>> +       ctrls->error_idx = i;
> >>>> +
> >>>> +       /* We could not find the control that failed. */
> >>>> +       if (i == ctrls->count)
> >>>> +               return ret;
> >>>> +
> >>>> +       if (uvc_ctrl_is_inactive(chain, err_control, mapping))
> >>>> +               return -EACCES;
> >>>>
> >>>> -       return ctrls->count;
> >>>> +       return ret;
> >>>>  }
> >>>>
> >>>>  int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> >>>> @@ -1701,8 +1726,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> >>>>                 uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
> >>>>  done:
> >>>>         if (ret < 0 && ctrls)
> >>>> -               ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
> >>>> -                                                         err_ctrl);
> >>>> +               ret = uvc_ctrl_commit_error(chain, entity, ctrls, err_ctrl,
> >>>> +                                           ret);
> >>>>         mutex_unlock(&chain->ctrl_mutex);
> >>>>         return ret;
> >>>>  }
> >>>> --
> >>>> 2.32.0.288.g62a8d224e6-goog
> >>>>
> >>>
> >>>
> >>
> >
> >
>


-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls
  2021-06-30 12:51           ` Ricardo Ribalda
@ 2021-07-06 14:18             ` Hans Verkuil
  2021-07-07  9:07               ` Ricardo Ribalda
  0 siblings, 1 reply; 39+ messages in thread
From: Hans Verkuil @ 2021-07-06 14:18 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Hans Verkuil, Laurent Pinchart, Mauro Carvalho Chehab,
	linux-media, tfiga, Sergey Senozhatsky, linux-kernel

On 30/06/2021 14:51, Ricardo Ribalda wrote:
> Hi Hans
> 
> 
> On Wed, 30 Jun 2021 at 11:03, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>>
>> Hi Ricardo,
>>
>> On 25/06/2021 15:55, Ricardo Ribalda wrote:
>>> Hi Hans
>>>
>>> On Fri, 25 Jun 2021 at 13:07, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>>>>
>>>> On 25/06/2021 12:29, Ricardo Ribalda wrote:
>>>>> Hi Hans
>>>>>
>>>>> Did you have some hardware that did not work fine without this patch?
>>>>> Am I remembering correctly?
>>>>
>>>> Yes, that's correct. It's one of my webcams, but I can't remember which one
>>>> it is. You probably want me to test this v10?
>>>>
>>>> Regards,
>>>
>>> That would be awesome. Thanks!
>>
>> You can add my:
>>
>> Tested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> 
> Thanks a lot for testing it!
> 
> Sorry to bother you, but could I ask you to try again, but with this
> patch reverted? This is v10 1-20, without 21/21

I tried with and without this patch and I didn't see any difference. Unfortunately,
I don't remember the exact details of what I tested last time and with which hardware.

I would drop this patch, it can always be added later.

Regards,

	Hans

> 
> 
> Thanks!
>>
>> to this series.
>>
>> I do get these warnings (depends on the webcam model, though, some do, some don't):
>>
>> Streaming ioctls:
>>         test read/write: OK (Not Supported)
>>         test blocking wait: OK
>>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>>         test MMAP (no poll): OK
>>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>>         test MMAP (select): OK
>>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>>         test MMAP (epoll): OK
>>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>>         test USERPTR (no poll): OK
>>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
>>         test USERPTR (select): OK
>>         test DMABUF: Cannot test, specify --expbuf-device
>>
>> It's something to do with the Field ID, but I'm not sure if this is really correctly
>> reporting a dropped frame, or if it is a false report and the sequence counter was
>> wrongly incremented.
>>
>> This is a separate issue, though, and doesn't block this series.
>>
>> Regards,
>>
>>         Hans
>>
>>>
>>>>
>>>>         Hans
>>>>
>>>>>
>>>>> Thanks!
>>>>>
>>>>> On Fri, 18 Jun 2021 at 14:29, Ricardo Ribalda <ribalda@chromium.org> wrote:
>>>>>>
>>>>>> If a control is inactive return -EACCES to let the userspace know that
>>>>>> the value will not be applied automatically when the control is active
>>>>>> again.
>>>>>>
>>>>>> Also make sure that query_v4l2_ctrl doesn't return an error.
>>>>>>
>>>>>> Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>>>>>> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>>>>>> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
>>>>>> ---
>>>>>>  drivers/media/usb/uvc/uvc_ctrl.c | 73 +++++++++++++++++++++-----------
>>>>>>  1 file changed, 49 insertions(+), 24 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
>>>>>> index da44d5c0b9ad..4f80c06d3c43 100644
>>>>>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>>>>>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>>>>>> @@ -1104,13 +1104,36 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
>>>>>>         return "Unknown Control";
>>>>>>  }
>>>>>>
>>>>>> +static bool uvc_ctrl_is_inactive(struct uvc_video_chain *chain,
>>>>>> +                                struct uvc_control *ctrl,
>>>>>> +                                struct uvc_control_mapping *mapping)
>>>>>> +{
>>>>>> +       struct uvc_control_mapping *master_map = NULL;
>>>>>> +       struct uvc_control *master_ctrl = NULL;
>>>>>> +       s32 val;
>>>>>> +       int ret;
>>>>>> +
>>>>>> +       if (!mapping->master_id)
>>>>>> +               return false;
>>>>>> +
>>>>>> +       __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
>>>>>> +                          &master_ctrl, 0);
>>>>>> +
>>>>>> +       if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
>>>>>> +               return false;
>>>>>> +
>>>>>> +       ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
>>>>>> +       if (ret < 0 || val == mapping->master_manual)
>>>>>> +               return false;
>>>>>> +
>>>>>> +       return true;
>>>>>> +}
>>>>>> +
>>>>>>  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>>>>>>         struct uvc_control *ctrl,
>>>>>>         struct uvc_control_mapping *mapping,
>>>>>>         struct v4l2_queryctrl *v4l2_ctrl)
>>>>>>  {
>>>>>> -       struct uvc_control_mapping *master_map = NULL;
>>>>>> -       struct uvc_control *master_ctrl = NULL;
>>>>>>         const struct uvc_menu_info *menu;
>>>>>>         unsigned int i;
>>>>>>
>>>>>> @@ -1126,18 +1149,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>>>>>>         if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
>>>>>>                 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>>>>>>
>>>>>> -       if (mapping->master_id)
>>>>>> -               __uvc_find_control(ctrl->entity, mapping->master_id,
>>>>>> -                                  &master_map, &master_ctrl, 0);
>>>>>> -       if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
>>>>>> -               s32 val;
>>>>>> -               int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
>>>>>> -               if (ret < 0)
>>>>>> -                       return ret;
>>>>>> -
>>>>>> -               if (val != mapping->master_manual)
>>>>>> -                               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
>>>>>> -       }
>>>>>> +       if (uvc_ctrl_is_inactive(chain, ctrl, mapping))
>>>>>> +               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
>>>>>>
>>>>>>         if (!ctrl->cached) {
>>>>>>                 int ret = uvc_ctrl_populate_cache(chain, ctrl);
>>>>>> @@ -1660,25 +1673,37 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
>>>>>>         return 0;
>>>>>>  }
>>>>>>
>>>>>> -static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
>>>>>> -                                 struct v4l2_ext_controls *ctrls,
>>>>>> -                                 struct uvc_control *uvc_control)
>>>>>> +static int uvc_ctrl_commit_error(struct uvc_video_chain *chain,
>>>>>> +                                struct uvc_entity *entity,
>>>>>> +                                struct v4l2_ext_controls *ctrls,
>>>>>> +                                struct uvc_control *err_control,
>>>>>> +                                int ret)
>>>>>>  {
>>>>>>         struct uvc_control_mapping *mapping;
>>>>>>         struct uvc_control *ctrl_found;
>>>>>>         unsigned int i;
>>>>>>
>>>>>> -       if (!entity)
>>>>>> -               return ctrls->count;
>>>>>> +       if (!entity) {
>>>>>> +               ctrls->error_idx = ctrls->count;
>>>>>> +               return ret;
>>>>>> +       }
>>>>>>
>>>>>>         for (i = 0; i < ctrls->count; i++) {
>>>>>>                 __uvc_find_control(entity, ctrls->controls[i].id, &mapping,
>>>>>>                                    &ctrl_found, 0);
>>>>>> -               if (uvc_control == ctrl_found)
>>>>>> -                       return i;
>>>>>> +               if (err_control == ctrl_found)
>>>>>> +                       break;
>>>>>>         }
>>>>>> +       ctrls->error_idx = i;
>>>>>> +
>>>>>> +       /* We could not find the control that failed. */
>>>>>> +       if (i == ctrls->count)
>>>>>> +               return ret;
>>>>>> +
>>>>>> +       if (uvc_ctrl_is_inactive(chain, err_control, mapping))
>>>>>> +               return -EACCES;
>>>>>>
>>>>>> -       return ctrls->count;
>>>>>> +       return ret;
>>>>>>  }
>>>>>>
>>>>>>  int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
>>>>>> @@ -1701,8 +1726,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
>>>>>>                 uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
>>>>>>  done:
>>>>>>         if (ret < 0 && ctrls)
>>>>>> -               ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
>>>>>> -                                                         err_ctrl);
>>>>>> +               ret = uvc_ctrl_commit_error(chain, entity, ctrls, err_ctrl,
>>>>>> +                                           ret);
>>>>>>         mutex_unlock(&chain->ctrl_mutex);
>>>>>>         return ret;
>>>>>>  }
>>>>>> --
>>>>>> 2.32.0.288.g62a8d224e6-goog
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>
> 
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls
  2021-07-06 14:18             ` Hans Verkuil
@ 2021-07-07  9:07               ` Ricardo Ribalda
  0 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-07-07  9:07 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Hans Verkuil, Laurent Pinchart, Mauro Carvalho Chehab,
	linux-media, tfiga, Sergey Senozhatsky, linux-kernel

Hi Hans

On Tue, 6 Jul 2021 at 16:19, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>
> On 30/06/2021 14:51, Ricardo Ribalda wrote:
> > Hi Hans
> >
> >
> > On Wed, 30 Jun 2021 at 11:03, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> >>
> >> Hi Ricardo,
> >>
> >> On 25/06/2021 15:55, Ricardo Ribalda wrote:
> >>> Hi Hans
> >>>
> >>> On Fri, 25 Jun 2021 at 13:07, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> >>>>
> >>>> On 25/06/2021 12:29, Ricardo Ribalda wrote:
> >>>>> Hi Hans
> >>>>>
> >>>>> Did you have some hardware that did not work fine without this patch?
> >>>>> Am I remembering correctly?
> >>>>
> >>>> Yes, that's correct. It's one of my webcams, but I can't remember which one
> >>>> it is. You probably want me to test this v10?
> >>>>
> >>>> Regards,
> >>>
> >>> That would be awesome. Thanks!
> >>
> >> You can add my:
> >>
> >> Tested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >
> > Thanks a lot for testing it!
> >
> > Sorry to bother you, but could I ask you to try again, but with this
> > patch reverted? This is v10 1-20, without 21/21
>
> I tried with and without this patch and I didn't see any difference. Unfortunately,
> I don't remember the exact details of what I tested last time and with which hardware.
>
> I would drop this patch, it can always be added later.

Thank you very much for testing.  I think there were no more comments
in this set.

Laurent: Shall I resend the series without this last patch, or can you
take it as is ignoring the last one?

Thanks!

>
> Regards,
>
>         Hans
>
> >
> >
> > Thanks!
> >>
> >> to this series.
> >>
> >> I do get these warnings (depends on the webcam model, though, some do, some don't):
> >>
> >> Streaming ioctls:
> >>         test read/write: OK (Not Supported)
> >>         test blocking wait: OK
> >>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
> >>         test MMAP (no poll): OK
> >>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
> >>         test MMAP (select): OK
> >>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
> >>         test MMAP (epoll): OK
> >>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
> >>         test USERPTR (no poll): OK
> >>                 warn: v4l2-test-buffers.cpp(438): got sequence number 1, expected 0
> >>         test USERPTR (select): OK
> >>         test DMABUF: Cannot test, specify --expbuf-device
> >>
> >> It's something to do with the Field ID, but I'm not sure if this is really correctly
> >> reporting a dropped frame, or if it is a false report and the sequence counter was
> >> wrongly incremented.
> >>
> >> This is a separate issue, though, and doesn't block this series.
> >>
> >> Regards,
> >>
> >>         Hans
> >>
> >>>
> >>>>
> >>>>         Hans
> >>>>
> >>>>>
> >>>>> Thanks!
> >>>>>
> >>>>> On Fri, 18 Jun 2021 at 14:29, Ricardo Ribalda <ribalda@chromium.org> wrote:
> >>>>>>
> >>>>>> If a control is inactive return -EACCES to let the userspace know that
> >>>>>> the value will not be applied automatically when the control is active
> >>>>>> again.
> >>>>>>
> >>>>>> Also make sure that query_v4l2_ctrl doesn't return an error.
> >>>>>>
> >>>>>> Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >>>>>> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >>>>>> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> >>>>>> ---
> >>>>>>  drivers/media/usb/uvc/uvc_ctrl.c | 73 +++++++++++++++++++++-----------
> >>>>>>  1 file changed, 49 insertions(+), 24 deletions(-)
> >>>>>>
> >>>>>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> >>>>>> index da44d5c0b9ad..4f80c06d3c43 100644
> >>>>>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> >>>>>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> >>>>>> @@ -1104,13 +1104,36 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
> >>>>>>         return "Unknown Control";
> >>>>>>  }
> >>>>>>
> >>>>>> +static bool uvc_ctrl_is_inactive(struct uvc_video_chain *chain,
> >>>>>> +                                struct uvc_control *ctrl,
> >>>>>> +                                struct uvc_control_mapping *mapping)
> >>>>>> +{
> >>>>>> +       struct uvc_control_mapping *master_map = NULL;
> >>>>>> +       struct uvc_control *master_ctrl = NULL;
> >>>>>> +       s32 val;
> >>>>>> +       int ret;
> >>>>>> +
> >>>>>> +       if (!mapping->master_id)
> >>>>>> +               return false;
> >>>>>> +
> >>>>>> +       __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
> >>>>>> +                          &master_ctrl, 0);
> >>>>>> +
> >>>>>> +       if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> >>>>>> +               return false;
> >>>>>> +
> >>>>>> +       ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> >>>>>> +       if (ret < 0 || val == mapping->master_manual)
> >>>>>> +               return false;
> >>>>>> +
> >>>>>> +       return true;
> >>>>>> +}
> >>>>>> +
> >>>>>>  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> >>>>>>         struct uvc_control *ctrl,
> >>>>>>         struct uvc_control_mapping *mapping,
> >>>>>>         struct v4l2_queryctrl *v4l2_ctrl)
> >>>>>>  {
> >>>>>> -       struct uvc_control_mapping *master_map = NULL;
> >>>>>> -       struct uvc_control *master_ctrl = NULL;
> >>>>>>         const struct uvc_menu_info *menu;
> >>>>>>         unsigned int i;
> >>>>>>
> >>>>>> @@ -1126,18 +1149,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> >>>>>>         if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> >>>>>>                 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> >>>>>>
> >>>>>> -       if (mapping->master_id)
> >>>>>> -               __uvc_find_control(ctrl->entity, mapping->master_id,
> >>>>>> -                                  &master_map, &master_ctrl, 0);
> >>>>>> -       if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> >>>>>> -               s32 val;
> >>>>>> -               int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> >>>>>> -               if (ret < 0)
> >>>>>> -                       return ret;
> >>>>>> -
> >>>>>> -               if (val != mapping->master_manual)
> >>>>>> -                               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> >>>>>> -       }
> >>>>>> +       if (uvc_ctrl_is_inactive(chain, ctrl, mapping))
> >>>>>> +               v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> >>>>>>
> >>>>>>         if (!ctrl->cached) {
> >>>>>>                 int ret = uvc_ctrl_populate_cache(chain, ctrl);
> >>>>>> @@ -1660,25 +1673,37 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
> >>>>>>         return 0;
> >>>>>>  }
> >>>>>>
> >>>>>> -static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
> >>>>>> -                                 struct v4l2_ext_controls *ctrls,
> >>>>>> -                                 struct uvc_control *uvc_control)
> >>>>>> +static int uvc_ctrl_commit_error(struct uvc_video_chain *chain,
> >>>>>> +                                struct uvc_entity *entity,
> >>>>>> +                                struct v4l2_ext_controls *ctrls,
> >>>>>> +                                struct uvc_control *err_control,
> >>>>>> +                                int ret)
> >>>>>>  {
> >>>>>>         struct uvc_control_mapping *mapping;
> >>>>>>         struct uvc_control *ctrl_found;
> >>>>>>         unsigned int i;
> >>>>>>
> >>>>>> -       if (!entity)
> >>>>>> -               return ctrls->count;
> >>>>>> +       if (!entity) {
> >>>>>> +               ctrls->error_idx = ctrls->count;
> >>>>>> +               return ret;
> >>>>>> +       }
> >>>>>>
> >>>>>>         for (i = 0; i < ctrls->count; i++) {
> >>>>>>                 __uvc_find_control(entity, ctrls->controls[i].id, &mapping,
> >>>>>>                                    &ctrl_found, 0);
> >>>>>> -               if (uvc_control == ctrl_found)
> >>>>>> -                       return i;
> >>>>>> +               if (err_control == ctrl_found)
> >>>>>> +                       break;
> >>>>>>         }
> >>>>>> +       ctrls->error_idx = i;
> >>>>>> +
> >>>>>> +       /* We could not find the control that failed. */
> >>>>>> +       if (i == ctrls->count)
> >>>>>> +               return ret;
> >>>>>> +
> >>>>>> +       if (uvc_ctrl_is_inactive(chain, err_control, mapping))
> >>>>>> +               return -EACCES;
> >>>>>>
> >>>>>> -       return ctrls->count;
> >>>>>> +       return ret;
> >>>>>>  }
> >>>>>>
> >>>>>>  int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> >>>>>> @@ -1701,8 +1726,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> >>>>>>                 uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
> >>>>>>  done:
> >>>>>>         if (ret < 0 && ctrls)
> >>>>>> -               ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
> >>>>>> -                                                         err_ctrl);
> >>>>>> +               ret = uvc_ctrl_commit_error(chain, entity, ctrls, err_ctrl,
> >>>>>> +                                           ret);
> >>>>>>         mutex_unlock(&chain->ctrl_mutex);
> >>>>>>         return ret;
> >>>>>>  }
> >>>>>> --
> >>>>>> 2.32.0.288.g62a8d224e6-goog
> >>>>>>
> >>>>>
> >>>>>
> >>>>
> >>>
> >>>
> >>
> >
> >
>


-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values()
  2021-06-18 12:29 ` [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values() Ricardo Ribalda
@ 2021-08-22 23:23   ` Laurent Pinchart
  2021-08-23  0:17   ` Laurent Pinchart
  1 sibling, 0 replies; 39+ messages in thread
From: Laurent Pinchart @ 2021-08-22 23:23 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Hans Verkuil, Mauro Carvalho Chehab, Sergey Senozhatsky,
	linux-media, linux-kernel, tfiga, Hans Verkuil

Hello,

A quick note, I'll update the subject with a "media: ".

On Fri, Jun 18, 2021 at 02:29:21PM +0200, Ricardo Ribalda wrote:
> From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> 
> Don't report the restored controls with dev_info, use dev_dbg instead.
> This prevents a lot of noise in the kernel log.
> 
> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 11c25d4b5c20..da44d5c0b9ad 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -2153,10 +2153,10 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
>  			if (!ctrl->initialized || !ctrl->modified ||
>  			    (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
>  				continue;
> -			dev_info(&dev->udev->dev,
> -				 "restoring control %pUl/%u/%u\n",
> -				 ctrl->info.entity, ctrl->info.index,
> -				 ctrl->info.selector);
> +			dev_dbg(&dev->udev->dev,
> +				"restoring control %pUl/%u/%u\n",
> +				ctrl->info.entity, ctrl->info.index,
> +				ctrl->info.selector);
>  			ctrl->dirty = 1;
>  		}
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 17/21] uvcvideo: uvc_ctrl_is_accessible: check for INACTIVE
  2021-06-18 12:29 ` [PATCH v10 17/21] uvcvideo: uvc_ctrl_is_accessible: check for INACTIVE Ricardo Ribalda
@ 2021-08-22 23:40   ` Laurent Pinchart
  0 siblings, 0 replies; 39+ messages in thread
From: Laurent Pinchart @ 2021-08-22 23:40 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Hans Verkuil, Mauro Carvalho Chehab, Sergey Senozhatsky,
	linux-media, linux-kernel, tfiga, Hans Verkuil, Hans Verkuil

Hi Ricardo and Hans,

Thank you for the patch.

On Fri, Jun 18, 2021 at 02:29:19PM +0200, Ricardo Ribalda wrote:
> From: Hans Verkuil <hverkuil@xs4all.nl>
> 
> Check for inactive controls in uvc_ctrl_is_accessible().
> Use the new value for the master_id controls if present,
> otherwise use the existing value to determine if it is OK
> to set the control. Doing this here avoids attempting to
> set an inactive control, which will return an error from the
> USB device.

Could you please explain in the commit message why this is better than
handling the error ?

> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 28 +++++++++++++++++++++++++++-
>  drivers/media/usb/uvc/uvc_v4l2.c |  4 ++--
>  drivers/media/usb/uvc/uvcvideo.h |  3 ++-
>  3 files changed, 31 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index dd6ebcc7344a..11c25d4b5c20 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1043,10 +1043,18 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
>  }
>  

As this function is starting to get large and do many things, a short
comment here to document it would be useful (it doesn't need to be
kerneldoc).

>  int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
> -			   bool read)
> +			   const struct v4l2_ext_controls *ctrls,
> +			   unsigned long ioctl)
>  {
> +	struct uvc_control_mapping *master_map = NULL;
> +	struct uvc_control *master_ctrl = NULL;
>  	struct uvc_control_mapping *mapping;
>  	struct uvc_control *ctrl;
> +	bool read = ioctl == VIDIOC_G_EXT_CTRLS;
> +	bool try = ioctl == VIDIOC_TRY_EXT_CTRLS;
> +	s32 val;
> +	int ret;
> +	int i;
>  
>  	if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0)
>  		return -EACCES;
> @@ -1061,6 +1069,24 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
>  	if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read)
>  		return -EACCES;
>  
> +	if (read || try || !mapping->master_id)
> +		return 0;
> +
> +	for (i = ctrls->count - 1; i >= 0; i--)

Is there a particular reason to iterate backwards ? If so, please add a
comment to explain why.

> +		if (ctrls->controls[i].id == mapping->master_id)
> +			return ctrls->controls[i].value ==
> +					mapping->master_manual ? 0 : -EACCES;

Curly braces for the for loop would be nice.

If I understand this correctly, this allows setting a manual control if
the same VIDIOC_S_EXT_CTRLS call sets the master control to manual mode,
regardless of the current value. Does the driver guarantee that the
master control will be set in the device before the manual control ?
Otherwise the device will still return an error.

> +
> +	__uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
> +			   &master_ctrl, 0);
> +
> +	if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> +		return 0;
> +
> +	ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> +	if (ret >= 0 && val != mapping->master_manual)
> +		return -EACCES;
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 8d8b12a4db34..0f4d893eff46 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1000,8 +1000,8 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain,
>  	int ret = 0;
>  
>  	for (i = 0; i < ctrls->count; ++ctrl, ++i) {
> -		ret = uvc_ctrl_is_accessible(chain, ctrl->id,
> -					    ioctl == VIDIOC_G_EXT_CTRLS);
> +		ret = uvc_ctrl_is_accessible(chain, ctrl->id, ctrls,
> +					    ioctl);
>  		if (ret)
>  			break;
>  	}
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 2e5366143b81..fd4f5ef47dfb 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -900,7 +900,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
>  int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
>  int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
>  int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
> -			   bool read);
> +			   const struct v4l2_ext_controls *ctrls,
> +			   unsigned long ioctl);
>  
>  int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
>  		      struct uvc_xu_control_query *xqry);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 18/21] uvcvideo: improve error handling in uvc_query_ctrl()
  2021-06-18 12:29 ` [PATCH v10 18/21] uvcvideo: improve error handling in uvc_query_ctrl() Ricardo Ribalda
@ 2021-08-22 23:52   ` Laurent Pinchart
  0 siblings, 0 replies; 39+ messages in thread
From: Laurent Pinchart @ 2021-08-22 23:52 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Hans Verkuil, Mauro Carvalho Chehab, Sergey Senozhatsky,
	linux-media, linux-kernel, tfiga, Hans Verkuil

Hi Ricardo and Hans,

Thank you for the patch.

Please add a "media: " prefix to the subject line. Same for the other
patches in the series that are missing this.

On Fri, Jun 18, 2021 at 02:29:20PM +0200, Ricardo Ribalda wrote:
> From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> 
> - If __uvc_query_ctrl() failed with a non-EPIPE error, then
>   report that with dev_err. If an error code is obtained, then
>   report that with dev_dbg.
> 
> - For error 2 (Wrong state) return -EACCES instead of -EILSEQ.
>   EACCES is a much more appropriate error code. EILSEQ will return
>   "Invalid or incomplete multibyte or wide character." in strerror(),
>   which is a *very* confusing message.

I would still have split the patch in two :-)

> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  drivers/media/usb/uvc/uvc_video.c | 38 ++++++++++++++++++-------------
>  1 file changed, 22 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
> index daba5fe352ea..00488f15cdbf 100644
> --- a/drivers/media/usb/uvc/uvc_video.c
> +++ b/drivers/media/usb/uvc/uvc_video.c
> @@ -79,15 +79,11 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
>  	if (likely(ret == size))
>  		return 0;
>  
> -	dev_err(&dev->udev->dev,
> -		"Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n",
> -		uvc_query_name(query), cs, unit, ret, size);
> -
> -	if (ret != -EPIPE)
> -		return ret;
> +	if (ret < 0 && ret != -EPIPE)

What if ret >= 0 ? There's a change of behaviour here that isn't
documented in the commit message. It shouldn't happen, but it would be
nice to handle it correctly.

> +		goto err;
>  
> +	/* reuse data[0] to request the error code. */
>  	tmp = *(u8 *)data;
> -
>  	ret = __uvc_query_ctrl(dev, UVC_GET_CUR, 0, intfnum,
>  			       UVC_VC_REQUEST_ERROR_CODE_CONTROL, data, 1,
>  			       UVC_CTRL_CONTROL_TIMEOUT);
> @@ -95,19 +91,21 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
>  	error = *(u8 *)data;
>  	*(u8 *)data = tmp;
>  
> -	if (ret != 1)
> -		return ret < 0 ? ret : -EPIPE;
> +	if (ret != 1) {
> +		ret = ret < 0 ? ret : -EPIPE;
> +		goto err;

This will print an error message that doesn't match the error.

> +	}
>  
> -	uvc_dbg(dev, CONTROL, "Control error %u\n", error);
> +	if (error >=1 && error <=8)

Missing space before 1 and 8.

> +		uvc_dbg(dev, CONTROL,
> +			"Failed to query (%s) UVC control %u on unit %u: got error %u.\n",
> +			uvc_query_name(query), cs, unit, error);
>  
>  	switch (error) {
> -	case 0:
> -		/* Cannot happen - we received a STALL */
> -		return -EPIPE;
>  	case 1: /* Not ready */
>  		return -EBUSY;
>  	case 2: /* Wrong state */
> -		return -EILSEQ;
> +		return -EACCES;
>  	case 3: /* Power */
>  		return -EREMOTE;
>  	case 4: /* Out of range */
> @@ -123,10 +121,18 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
>  	case 8: /* Invalid value within range */
>  		return -EINVAL;
>  	default: /* reserved or unknown */
> -		break;
> +		dev_err(&dev->udev->dev,
> +			"Failed to query (%s) UVC control %u on unit %u: got error %u.\n",
> +			uvc_query_name(query), cs, unit, error);
> +		return -EPIPE;
>  	}
>  
> -	return -EPIPE;
> +err:
> +	dev_err(&dev->udev->dev,
> +		"Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n",
> +		uvc_query_name(query), cs, unit, ret, size);
> +
> +	return ret;
>  }
>  
>  static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 20/21] uvc: use vb2 ioctl and fop helpers
  2021-06-18 12:29 ` [PATCH v10 20/21] uvc: use vb2 ioctl and fop helpers Ricardo Ribalda
@ 2021-08-23  0:00   ` Laurent Pinchart
  0 siblings, 0 replies; 39+ messages in thread
From: Laurent Pinchart @ 2021-08-23  0:00 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Hans Verkuil, Mauro Carvalho Chehab, Sergey Senozhatsky,
	linux-media, linux-kernel, tfiga, Hans Verkuil

Hi Ricardo and Hans,

Thank you for the patch.

I'll repeat the comments I sent for v2 as they seem to have been
unnoticed.

On Fri, Jun 18, 2021 at 02:29:22PM +0200, Ricardo Ribalda wrote:
> From: Hans Verkuil <hverkuil@xs4all.nl>
> 
> When uvc was written the vb2 ioctl and file operation helpers didn't exist.
> 
> This patch switches uvc over to those helpers, which removes a lot of boilerplate
> code and simplifies VIDIOC_G/S_PRIORITY handling and allows us to drop the
> 'privileges' scheme, since that's now handled inside the vb2 helpers.
> 
> This makes it possible for uvc to pass the v4l2-compliance streaming tests.
> 
> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> ---
>  drivers/media/usb/uvc/uvc_driver.c   |   7 +-
>  drivers/media/usb/uvc/uvc_metadata.c |   8 +-
>  drivers/media/usb/uvc/uvc_queue.c    | 143 -------------
>  drivers/media/usb/uvc/uvc_v4l2.c     | 288 ++-------------------------
>  drivers/media/usb/uvc/uvcvideo.h     |  32 ---
>  5 files changed, 25 insertions(+), 453 deletions(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index 037bf80d1100..9416e80fe392 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -1943,7 +1943,6 @@ static struct uvc_video_chain *uvc_alloc_chain(struct uvc_device *dev)
>  	INIT_LIST_HEAD(&chain->entities);
>  	mutex_init(&chain->ctrl_mutex);
>  	chain->dev = dev;
> -	v4l2_prio_init(&chain->prio);
>  
>  	return chain;
>  }
> @@ -2213,7 +2212,7 @@ int uvc_register_video_device(struct uvc_device *dev,
>  	vdev->fops = fops;
>  	vdev->ioctl_ops = ioctl_ops;
>  	vdev->release = uvc_release;
> -	vdev->prio = &stream->chain->prio;
> +	vdev->queue = &queue->queue;
>  	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
>  		vdev->vfl_dir = VFL_DIR_TX;
>  	else
> @@ -2578,8 +2577,8 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
>  		if (stream->intf == intf) {
>  			ret = uvc_video_resume(stream, reset);
>  			if (ret < 0)
> -				uvc_queue_streamoff(&stream->queue,
> -						    stream->queue.queue.type);
> +				vb2_streamoff(&stream->queue.queue,
> +					      stream->queue.queue.type);
>  			return ret;
>  		}
>  	}
> diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c
> index 82de7781f5b6..d3aab22f91ce 100644
> --- a/drivers/media/usb/uvc/uvc_metadata.c
> +++ b/drivers/media/usb/uvc/uvc_metadata.c
> @@ -96,7 +96,7 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh,
>  	 */
>  	mutex_lock(&stream->mutex);
>  
> -	if (uvc_queue_allocated(&stream->queue))
> +	if (vb2_is_busy(&stream->meta.queue.queue))
>  		ret = -EBUSY;
>  	else
>  		stream->meta.format = fmt->dataformat;
> @@ -164,12 +164,6 @@ int uvc_meta_register(struct uvc_streaming *stream)
>  
>  	stream->meta.format = V4L2_META_FMT_UVC;
>  
> -	/*
> -	 * The video interface queue uses manual locking and thus does not set
> -	 * the queue pointer. Set it manually here.
> -	 */
> -	vdev->queue = &queue->queue;
> -
>  	return uvc_register_video_device(dev, stream, vdev, queue,
>  					 V4L2_BUF_TYPE_META_CAPTURE,
>  					 &uvc_meta_fops, &uvc_meta_ioctl_ops);
> diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
> index 21a907d32bb7..437e48b32480 100644
> --- a/drivers/media/usb/uvc/uvc_queue.c
> +++ b/drivers/media/usb/uvc/uvc_queue.c
> @@ -247,153 +247,10 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
>  	return 0;
>  }
>  
> -void uvc_queue_release(struct uvc_video_queue *queue)
> -{
> -	mutex_lock(&queue->mutex);
> -	vb2_queue_release(&queue->queue);
> -	mutex_unlock(&queue->mutex);
> -}
> -
> -/* -----------------------------------------------------------------------------
> - * V4L2 queue operations
> - */
> -
> -int uvc_request_buffers(struct uvc_video_queue *queue,
> -			struct v4l2_requestbuffers *rb)
> -{
> -	int ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_reqbufs(&queue->queue, rb);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret ? ret : rb->count;
> -}
> -
> -int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
> -{
> -	int ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_querybuf(&queue->queue, buf);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret;
> -}
> -
> -int uvc_create_buffers(struct uvc_video_queue *queue,
> -		       struct v4l2_create_buffers *cb)
> -{
> -	int ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_create_bufs(&queue->queue, cb);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret;
> -}
> -
> -int uvc_queue_buffer(struct uvc_video_queue *queue,
> -		     struct media_device *mdev, struct v4l2_buffer *buf)
> -{
> -	int ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_qbuf(&queue->queue, mdev, buf);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret;
> -}
> -
> -int uvc_export_buffer(struct uvc_video_queue *queue,
> -		      struct v4l2_exportbuffer *exp)
> -{
> -	int ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_expbuf(&queue->queue, exp);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret;
> -}
> -
> -int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
> -		       int nonblocking)
> -{
> -	int ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret;
> -}
> -
> -int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type)
> -{
> -	int ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_streamon(&queue->queue, type);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret;
> -}
> -
> -int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type)
> -{
> -	int ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_streamoff(&queue->queue, type);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret;
> -}
> -
> -int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
> -{
> -	return vb2_mmap(&queue->queue, vma);
> -}
> -
> -#ifndef CONFIG_MMU
> -unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
> -		unsigned long pgoff)
> -{
> -	return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
> -}
> -#endif
> -
> -__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
> -			    poll_table *wait)
> -{
> -	__poll_t ret;
> -
> -	mutex_lock(&queue->mutex);
> -	ret = vb2_poll(&queue->queue, file, wait);
> -	mutex_unlock(&queue->mutex);
> -
> -	return ret;
> -}
> -
>  /* -----------------------------------------------------------------------------
>   *
>   */
>  
> -/*
> - * Check if buffers have been allocated.
> - */
> -int uvc_queue_allocated(struct uvc_video_queue *queue)
> -{
> -	int allocated;
> -
> -	mutex_lock(&queue->mutex);
> -	allocated = vb2_is_busy(&queue->queue);
> -	mutex_unlock(&queue->mutex);
> -
> -	return allocated;
> -}
> -
>  /*
>   * Cancel the video buffers queue.
>   *
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 0f4d893eff46..e40db7ae18b1 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -352,17 +352,13 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
>  		return ret;
>  
>  	mutex_lock(&stream->mutex);
> -
> -	if (uvc_queue_allocated(&stream->queue)) {
> +	if (vb2_is_busy(&stream->queue.queue)) {
>  		ret = -EBUSY;
> -		goto done;
> +	} else {
> +		stream->ctrl = probe;
> +		stream->cur_format = format;
> +		stream->cur_frame = frame;
>  	}

That's probably a matter of personal preferences, but I prefer the goto
done style.

> -
> -	stream->ctrl = probe;
> -	stream->cur_format = format;
> -	stream->cur_frame = frame;
> -
> -done:
>  	mutex_unlock(&stream->mutex);
>  	return ret;
>  }
> @@ -489,62 +485,6 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
>  	return 0;
>  }
>  
> -/* ------------------------------------------------------------------------
> - * Privilege management
> - */
> -
> -/*
> - * Privilege management is the multiple-open implementation basis. The current
> - * implementation is completely transparent for the end-user and doesn't
> - * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls.
> - * Those ioctls enable finer control on the device (by making possible for a
> - * user to request exclusive access to a device), but are not mature yet.
> - * Switching to the V4L2 priority mechanism might be considered in the future
> - * if this situation changes.
> - *
> - * Each open instance of a UVC device can either be in a privileged or
> - * unprivileged state. Only a single instance can be in a privileged state at
> - * a given time. Trying to perform an operation that requires privileges will
> - * automatically acquire the required privileges if possible, or return -EBUSY
> - * otherwise. Privileges are dismissed when closing the instance or when
> - * freeing the video buffers using VIDIOC_REQBUFS.
> - *
> - * Operations that require privileges are:
> - *
> - * - VIDIOC_S_INPUT
> - * - VIDIOC_S_PARM
> - * - VIDIOC_S_FMT
> - * - VIDIOC_REQBUFS

This is an important change in behaviour, as the V4L2 core doesn't grant
exclusive ownership of the device when any of those three ioctls are
called. Only VIDIOC_REQBUFS does so.

> - */
> -static int uvc_acquire_privileges(struct uvc_fh *handle)
> -{
> -	/* Always succeed if the handle is already privileged. */
> -	if (handle->state == UVC_HANDLE_ACTIVE)
> -		return 0;
> -
> -	/* Check if the device already has a privileged handle. */
> -	if (atomic_inc_return(&handle->stream->active) != 1) {
> -		atomic_dec(&handle->stream->active);
> -		return -EBUSY;
> -	}
> -
> -	handle->state = UVC_HANDLE_ACTIVE;
> -	return 0;
> -}
> -
> -static void uvc_dismiss_privileges(struct uvc_fh *handle)
> -{
> -	if (handle->state == UVC_HANDLE_ACTIVE)
> -		atomic_dec(&handle->stream->active);
> -
> -	handle->state = UVC_HANDLE_PASSIVE;
> -}
> -
> -static int uvc_has_privileges(struct uvc_fh *handle)
> -{
> -	return handle->state == UVC_HANDLE_ACTIVE;
> -}
> -
>  /* ------------------------------------------------------------------------
>   * V4L2 file operations
>   */
> @@ -587,7 +527,6 @@ static int uvc_v4l2_open(struct file *file)
>  	v4l2_fh_add(&handle->vfh);
>  	handle->chain = stream->chain;
>  	handle->stream = stream;
> -	handle->state = UVC_HANDLE_PASSIVE;
>  	file->private_data = handle;
>  
>  	return 0;
> @@ -600,15 +539,8 @@ static int uvc_v4l2_release(struct file *file)
>  
>  	uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
>  
> -	/* Only free resources if this is a privileged handle. */
> -	if (uvc_has_privileges(handle))
> -		uvc_queue_release(&stream->queue);
> -
>  	/* Release the file handle. */
> -	uvc_dismiss_privileges(handle);
> -	v4l2_fh_del(&handle->vfh);
> -	v4l2_fh_exit(&handle->vfh);
> -	kfree(handle);
> +	vb2_fop_release(file);
>  	file->private_data = NULL;
>  
>  	mutex_lock(&stream->dev->lock);
> @@ -701,11 +633,6 @@ static int uvc_ioctl_s_fmt_vid_cap(struct file *file, void *fh,
>  {
>  	struct uvc_fh *handle = fh;
>  	struct uvc_streaming *stream = handle->stream;
> -	int ret;
> -
> -	ret = uvc_acquire_privileges(handle);
> -	if (ret < 0)
> -		return ret;
>  
>  	return uvc_v4l2_set_format(stream, fmt);
>  }
> @@ -715,11 +642,6 @@ static int uvc_ioctl_s_fmt_vid_out(struct file *file, void *fh,
>  {
>  	struct uvc_fh *handle = fh;
>  	struct uvc_streaming *stream = handle->stream;
> -	int ret;
> -
> -	ret = uvc_acquire_privileges(handle);
> -	if (ret < 0)
> -		return ret;
>  
>  	return uvc_v4l2_set_format(stream, fmt);
>  }
> @@ -744,124 +666,6 @@ static int uvc_ioctl_try_fmt_vid_out(struct file *file, void *fh,
>  	return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL);
>  }
>  
> -static int uvc_ioctl_reqbufs(struct file *file, void *fh,
> -			     struct v4l2_requestbuffers *rb)
> -{
> -	struct uvc_fh *handle = fh;
> -	struct uvc_streaming *stream = handle->stream;
> -	int ret;
> -
> -	ret = uvc_acquire_privileges(handle);
> -	if (ret < 0)
> -		return ret;
> -
> -	mutex_lock(&stream->mutex);
> -	ret = uvc_request_buffers(&stream->queue, rb);
> -	mutex_unlock(&stream->mutex);

This (and most of the other changes) introduce a race condition, as you
now only use the queue mutex to serialize the buffer-related ioctls,
while the other ioctls are protected by the stream mutex. Those are two
different mutexes.

> -	if (ret < 0)
> -		return ret;
> -
> -	if (ret == 0)
> -		uvc_dismiss_privileges(handle);
> -
> -	return 0;
> -}
> -
> -static int uvc_ioctl_querybuf(struct file *file, void *fh,
> -			      struct v4l2_buffer *buf)
> -{
> -	struct uvc_fh *handle = fh;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	if (!uvc_has_privileges(handle))
> -		return -EBUSY;
> -
> -	return uvc_query_buffer(&stream->queue, buf);
> -}
> -
> -static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
> -{
> -	struct uvc_fh *handle = fh;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	if (!uvc_has_privileges(handle))
> -		return -EBUSY;
> -
> -	return uvc_queue_buffer(&stream->queue,
> -				stream->vdev.v4l2_dev->mdev, buf);
> -}
> -
> -static int uvc_ioctl_expbuf(struct file *file, void *fh,
> -			    struct v4l2_exportbuffer *exp)
> -{
> -	struct uvc_fh *handle = fh;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	if (!uvc_has_privileges(handle))
> -		return -EBUSY;
> -
> -	return uvc_export_buffer(&stream->queue, exp);
> -}
> -
> -static int uvc_ioctl_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
> -{
> -	struct uvc_fh *handle = fh;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	if (!uvc_has_privileges(handle))
> -		return -EBUSY;
> -
> -	return uvc_dequeue_buffer(&stream->queue, buf,
> -				  file->f_flags & O_NONBLOCK);
> -}
> -
> -static int uvc_ioctl_create_bufs(struct file *file, void *fh,
> -				  struct v4l2_create_buffers *cb)
> -{
> -	struct uvc_fh *handle = fh;
> -	struct uvc_streaming *stream = handle->stream;
> -	int ret;
> -
> -	ret = uvc_acquire_privileges(handle);
> -	if (ret < 0)
> -		return ret;
> -
> -	return uvc_create_buffers(&stream->queue, cb);
> -}
> -
> -static int uvc_ioctl_streamon(struct file *file, void *fh,
> -			      enum v4l2_buf_type type)
> -{
> -	struct uvc_fh *handle = fh;
> -	struct uvc_streaming *stream = handle->stream;
> -	int ret;
> -
> -	if (!uvc_has_privileges(handle))
> -		return -EBUSY;
> -
> -	mutex_lock(&stream->mutex);
> -	ret = uvc_queue_streamon(&stream->queue, type);
> -	mutex_unlock(&stream->mutex);
> -
> -	return ret;
> -}
> -
> -static int uvc_ioctl_streamoff(struct file *file, void *fh,
> -			       enum v4l2_buf_type type)
> -{
> -	struct uvc_fh *handle = fh;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	if (!uvc_has_privileges(handle))
> -		return -EBUSY;
> -
> -	mutex_lock(&stream->mutex);
> -	uvc_queue_streamoff(&stream->queue, type);
> -	mutex_unlock(&stream->mutex);
> -
> -	return 0;
> -}
> -
>  static int uvc_ioctl_enum_input(struct file *file, void *fh,
>  				struct v4l2_input *input)
>  {
> @@ -929,13 +733,12 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input)
>  static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
>  {
>  	struct uvc_fh *handle = fh;
> +	struct uvc_streaming *stream = handle->stream;
>  	struct uvc_video_chain *chain = handle->chain;
> -	int ret;
>  	u32 i;
>  
> -	ret = uvc_acquire_privileges(handle);
> -	if (ret < 0)
> -		return ret;
> +	if (vb2_is_busy(&stream->queue.queue))
> +		return -EBUSY;
>  
>  	if (chain->selector == NULL ||
>  	    (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
> @@ -1166,11 +969,6 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh,
>  {
>  	struct uvc_fh *handle = fh;
>  	struct uvc_streaming *stream = handle->stream;
> -	int ret;
> -
> -	ret = uvc_acquire_privileges(handle);
> -	if (ret < 0)
> -		return ret;
>  
>  	return uvc_v4l2_set_streamparm(stream, parm);
>  }
> @@ -1438,50 +1236,6 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
>  }
>  #endif
>  
> -static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
> -		    size_t count, loff_t *ppos)
> -{
> -	struct uvc_fh *handle = file->private_data;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	uvc_dbg(stream->dev, CALLS, "%s: not implemented\n", __func__);
> -	return -EINVAL;
> -}
> -
> -static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
> -{
> -	struct uvc_fh *handle = file->private_data;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
> -
> -	return uvc_queue_mmap(&stream->queue, vma);
> -}
> -
> -static __poll_t uvc_v4l2_poll(struct file *file, poll_table *wait)
> -{
> -	struct uvc_fh *handle = file->private_data;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
> -
> -	return uvc_queue_poll(&stream->queue, file, wait);
> -}
> -
> -#ifndef CONFIG_MMU
> -static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
> -		unsigned long addr, unsigned long len, unsigned long pgoff,
> -		unsigned long flags)
> -{
> -	struct uvc_fh *handle = file->private_data;
> -	struct uvc_streaming *stream = handle->stream;
> -
> -	uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
> -
> -	return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
> -}
> -#endif
> -
>  const struct v4l2_ioctl_ops uvc_ioctl_ops = {
>  	.vidioc_querycap = uvc_ioctl_querycap,
>  	.vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt_vid_cap,
> @@ -1492,14 +1246,15 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = {
>  	.vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt_vid_out,
>  	.vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt_vid_cap,
>  	.vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt_vid_out,
> -	.vidioc_reqbufs = uvc_ioctl_reqbufs,
> -	.vidioc_querybuf = uvc_ioctl_querybuf,
> -	.vidioc_qbuf = uvc_ioctl_qbuf,
> -	.vidioc_expbuf = uvc_ioctl_expbuf,
> -	.vidioc_dqbuf = uvc_ioctl_dqbuf,
> -	.vidioc_create_bufs = uvc_ioctl_create_bufs,
> -	.vidioc_streamon = uvc_ioctl_streamon,
> -	.vidioc_streamoff = uvc_ioctl_streamoff,
> +	.vidioc_reqbufs = vb2_ioctl_reqbufs,
> +	.vidioc_querybuf = vb2_ioctl_querybuf,
> +	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
> +	.vidioc_qbuf = vb2_ioctl_qbuf,
> +	.vidioc_expbuf = vb2_ioctl_expbuf,
> +	.vidioc_dqbuf = vb2_ioctl_dqbuf,
> +	.vidioc_create_bufs = vb2_ioctl_create_bufs,
> +	.vidioc_streamon = vb2_ioctl_streamon,
> +	.vidioc_streamoff = vb2_ioctl_streamoff,
>  	.vidioc_enum_input = uvc_ioctl_enum_input,
>  	.vidioc_g_input = uvc_ioctl_g_input,
>  	.vidioc_s_input = uvc_ioctl_s_input,
> @@ -1527,11 +1282,10 @@ const struct v4l2_file_operations uvc_fops = {
>  #ifdef CONFIG_COMPAT
>  	.compat_ioctl32	= uvc_v4l2_compat_ioctl32,
>  #endif
> -	.read		= uvc_v4l2_read,
> -	.mmap		= uvc_v4l2_mmap,
> -	.poll		= uvc_v4l2_poll,
> +	.mmap		= vb2_fop_mmap,
> +	.poll		= vb2_fop_poll,
>  #ifndef CONFIG_MMU
> -	.get_unmapped_area = uvc_v4l2_get_unmapped_area,
> +	.get_unmapped_area = vb2_fop_get_unmapped_area,
>  #endif
>  };
>  
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index fd4f5ef47dfb..a087d66d2105 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -474,7 +474,6 @@ struct uvc_video_chain {
>  
>  	struct mutex ctrl_mutex;		/* Protects ctrl.info */
>  
> -	struct v4l2_prio_state prio;		/* V4L2 priority state */
>  	u32 caps;				/* V4L2 chain-wide caps */
>  	u8 ctrl_class_bitmap;			/* Bitmap of valid classes */
>  };
> @@ -713,16 +712,10 @@ struct uvc_device {
>  	struct uvc_entity *gpio_unit;
>  };
>  
> -enum uvc_handle_state {
> -	UVC_HANDLE_PASSIVE	= 0,
> -	UVC_HANDLE_ACTIVE	= 1,
> -};
> -
>  struct uvc_fh {
>  	struct v4l2_fh vfh;
>  	struct uvc_video_chain *chain;
>  	struct uvc_streaming *stream;
> -	enum uvc_handle_state state;
>  };
>  
>  struct uvc_driver {
> @@ -787,36 +780,11 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
>  /* Video buffers queue management. */
>  int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
>  		   int drop_corrupted);
> -void uvc_queue_release(struct uvc_video_queue *queue);
> -int uvc_request_buffers(struct uvc_video_queue *queue,
> -			struct v4l2_requestbuffers *rb);
> -int uvc_query_buffer(struct uvc_video_queue *queue,
> -		     struct v4l2_buffer *v4l2_buf);
> -int uvc_create_buffers(struct uvc_video_queue *queue,
> -		       struct v4l2_create_buffers *v4l2_cb);
> -int uvc_queue_buffer(struct uvc_video_queue *queue,
> -		     struct media_device *mdev,
> -		     struct v4l2_buffer *v4l2_buf);
> -int uvc_export_buffer(struct uvc_video_queue *queue,
> -		      struct v4l2_exportbuffer *exp);
> -int uvc_dequeue_buffer(struct uvc_video_queue *queue,
> -		       struct v4l2_buffer *v4l2_buf, int nonblocking);
> -int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type);
> -int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type);
>  void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
>  struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
>  					 struct uvc_buffer *buf);
>  struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue);
>  void uvc_queue_buffer_release(struct uvc_buffer *buf);
> -int uvc_queue_mmap(struct uvc_video_queue *queue,
> -		   struct vm_area_struct *vma);
> -__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
> -			poll_table *wait);
> -#ifndef CONFIG_MMU
> -unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
> -					  unsigned long pgoff);
> -#endif
> -int uvc_queue_allocated(struct uvc_video_queue *queue);
>  static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
>  {
>  	return vb2_is_streaming(&queue->queue);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values()
  2021-06-18 12:29 ` [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values() Ricardo Ribalda
  2021-08-22 23:23   ` Laurent Pinchart
@ 2021-08-23  0:17   ` Laurent Pinchart
  2021-08-23  7:32     ` Hans Verkuil
  1 sibling, 1 reply; 39+ messages in thread
From: Laurent Pinchart @ 2021-08-23  0:17 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Hans Verkuil, Mauro Carvalho Chehab, Sergey Senozhatsky,
	linux-media, linux-kernel, tfiga, Hans Verkuil

Hi Hans,

On Fri, Jun 18, 2021 at 02:29:21PM +0200, Ricardo Ribalda wrote:
> From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> 
> Don't report the restored controls with dev_info, use dev_dbg instead.
> This prevents a lot of noise in the kernel log.
> 
> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>

The author and SoB line don't match. Which one should I update ?

> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 11c25d4b5c20..da44d5c0b9ad 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -2153,10 +2153,10 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
>  			if (!ctrl->initialized || !ctrl->modified ||
>  			    (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
>  				continue;
> -			dev_info(&dev->udev->dev,
> -				 "restoring control %pUl/%u/%u\n",
> -				 ctrl->info.entity, ctrl->info.index,
> -				 ctrl->info.selector);
> +			dev_dbg(&dev->udev->dev,
> +				"restoring control %pUl/%u/%u\n",
> +				ctrl->info.entity, ctrl->info.index,
> +				ctrl->info.selector);
>  			ctrl->dirty = 1;
>  		}
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values()
  2021-08-23  0:17   ` Laurent Pinchart
@ 2021-08-23  7:32     ` Hans Verkuil
  0 siblings, 0 replies; 39+ messages in thread
From: Hans Verkuil @ 2021-08-23  7:32 UTC (permalink / raw)
  To: Laurent Pinchart, Ricardo Ribalda
  Cc: Mauro Carvalho Chehab, Sergey Senozhatsky, linux-media,
	linux-kernel, tfiga, Hans Verkuil

On 23/08/2021 02:17, Laurent Pinchart wrote:
> Hi Hans,
> 
> On Fri, Jun 18, 2021 at 02:29:21PM +0200, Ricardo Ribalda wrote:
>> From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>>
>> Don't report the restored controls with dev_info, use dev_dbg instead.
>> This prevents a lot of noise in the kernel log.
>>
>> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> 
> The author and SoB line don't match. Which one should I update ?

SoB should use <hverkuil-cisco@xs4all.nl>

Regards,

	Hans

> 
>> ---
>>  drivers/media/usb/uvc/uvc_ctrl.c | 8 ++++----
>>  1 file changed, 4 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
>> index 11c25d4b5c20..da44d5c0b9ad 100644
>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>> @@ -2153,10 +2153,10 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
>>  			if (!ctrl->initialized || !ctrl->modified ||
>>  			    (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
>>  				continue;
>> -			dev_info(&dev->udev->dev,
>> -				 "restoring control %pUl/%u/%u\n",
>> -				 ctrl->info.entity, ctrl->info.index,
>> -				 ctrl->info.selector);
>> +			dev_dbg(&dev->udev->dev,
>> +				"restoring control %pUl/%u/%u\n",
>> +				ctrl->info.entity, ctrl->info.index,
>> +				ctrl->info.selector);
>>  			ctrl->dirty = 1;
>>  		}
>>  
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 13/21] media: uvcvideo: Use control names from framework
  2021-06-18 12:29 ` [PATCH v10 13/21] media: uvcvideo: Use control names from framework Ricardo Ribalda
@ 2021-09-03 10:10   ` Mauro Carvalho Chehab
  2021-09-03 10:33     ` Ricardo Ribalda
  0 siblings, 1 reply; 39+ messages in thread
From: Mauro Carvalho Chehab @ 2021-09-03 10:10 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Laurent Pinchart, Hans Verkuil, Sergey Senozhatsky, linux-media,
	linux-kernel, tfiga, Hans Verkuil

Em Fri, 18 Jun 2021 14:29:15 +0200
Ricardo Ribalda <ribalda@chromium.org> escreveu:

> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 9cdd30eff495..28ccaa8b9e42 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -40,7 +40,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
>  		return -ENOMEM;
>  
>  	map->id = xmap->id;
> -	memcpy(map->name, xmap->name, sizeof(map->name));
> +	/* Non standard control id. */
> +	if (v4l2_ctrl_get_name(map->id) == NULL) {
> +		map->name = kmemdup(xmap->name, sizeof(xmap->name),
> +				    GFP_KERNEL);

Where are you de-allocating it at driver removal/unbind?

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v10 13/21] media: uvcvideo: Use control names from framework
  2021-09-03 10:10   ` Mauro Carvalho Chehab
@ 2021-09-03 10:33     ` Ricardo Ribalda
  0 siblings, 0 replies; 39+ messages in thread
From: Ricardo Ribalda @ 2021-09-03 10:33 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Laurent Pinchart, Hans Verkuil, Sergey Senozhatsky, linux-media,
	linux-kernel, tfiga, Hans Verkuil

Hi Mauro

On Fri, 3 Sept 2021 at 12:11, Mauro Carvalho Chehab <mchehab@kernel.org> wrote:
>
> Em Fri, 18 Jun 2021 14:29:15 +0200
> Ricardo Ribalda <ribalda@chromium.org> escreveu:
>
> > diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> > index 9cdd30eff495..28ccaa8b9e42 100644
> > --- a/drivers/media/usb/uvc/uvc_v4l2.c
> > +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> > @@ -40,7 +40,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
> >               return -ENOMEM;
> >
> >       map->id = xmap->id;
> > -     memcpy(map->name, xmap->name, sizeof(map->name));
> > +     /* Non standard control id. */
> > +     if (v4l2_ctrl_get_name(map->id) == NULL) {
> > +             map->name = kmemdup(xmap->name, sizeof(xmap->name),
> > +                                 GFP_KERNEL);
>
> Where are you de-allocating it at driver removal/unbind?

It is also in this patch:

@@ -2462,6 +2448,7 @@ static void uvc_ctrl_cleanup_mappings(struct
uvc_device *dev,
        list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
                list_del(&mapping->list);
                kfree(mapping->menu_info);
+               kfree(mapping->name);
                kfree(mapping);
        }
 }

If there is a standard name mapping->name will be NULL, but kfree
checks for that.

Thanks


>
>
> Thanks,
> Mauro



-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [REGRESSION] Re: [PATCH v10 11/21] media: uvcvideo: Set unique vdev name based in type
  2021-06-18 12:29 ` [PATCH v10 11/21] media: uvcvideo: Set unique vdev name based in type Ricardo Ribalda
@ 2021-12-06 19:05   ` Nicolas Dufresne
  2021-12-06 19:15     ` Laurent Pinchart
  0 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dufresne @ 2021-12-06 19:05 UTC (permalink / raw)
  To: Ricardo Ribalda, Laurent Pinchart, Hans Verkuil,
	Mauro Carvalho Chehab, Sergey Senozhatsky, linux-media,
	linux-kernel, tfiga
  Cc: linux-kernel, stable

Hi Ricard, 

Le vendredi 18 juin 2021 à 14:29 +0200, Ricardo Ribalda a écrit :
> All the entities must have a unique name. We can have a descriptive and
> unique name by appending the function and the entity->id.

Thanks for your work. The only issue is that unfortunately this change cause an
important regression for users. All UVC cameras in all UIs seems to no longer
include any information about the camera. As an example, I have two cameras on
my system and Firefox, Chrome, Cheese, Zoom and MS Team all agree that my camera
are now:

  Video Capture 4
  Video Capture 5

Previously they would be shown as something like:

  StreamCam
  Integrated

We should probably revert this change quickly before it get deployed more
widely, I have notice the backport being sent for 5.4, 5.10 and 5.14. I'm using
5.15 shipped by Fedora team.

As a proper solution, maybe I could suggest to keep using dev->name, but trim it
enough to fit the " N" string to guaranty that you have enough space in this
limited 32 char string and use that instead ? This should fit the uniqueness
requirement without the sacrifice of the only possibly useful information we had
in that limited string.

regards,
Nicolas

> 
> This is even resilent to multi chain devices.
> 
> Fixes v4l2-compliance:
> Media Controller ioctls:
>                 fail: v4l2-test-media.cpp(205): v2_entity_names_set.find(key) != v2_entity_names_set.end()
>         test MEDIA_IOC_G_TOPOLOGY: FAIL
>                 fail: v4l2-test-media.cpp(394): num_data_links != num_links
> 	test MEDIA_IOC_ENUM_ENTITIES/LINKS: FAIL
> 
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> ---
>  drivers/media/usb/uvc/uvc_driver.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index 14b60792ffab..037bf80d1100 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -2194,6 +2194,7 @@ int uvc_register_video_device(struct uvc_device *dev,
>  			      const struct v4l2_file_operations *fops,
>  			      const struct v4l2_ioctl_ops *ioctl_ops)
>  {
> +	const char *name;
>  	int ret;
>  
>  	/* Initialize the video buffers queue. */
> @@ -2222,16 +2223,20 @@ int uvc_register_video_device(struct uvc_device *dev,
>  	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
>  	default:
>  		vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> +		name = "Video Capture";
>  		break;
>  	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
>  		vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
> +		name = "Video Output";
>  		break;
>  	case V4L2_BUF_TYPE_META_CAPTURE:
>  		vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
> +		name = "Metadata";
>  		break;
>  	}
>  
> -	strscpy(vdev->name, dev->name, sizeof(vdev->name));
> +	snprintf(vdev->name, sizeof(vdev->name), "%s %u", name,
> +		 stream->header.bTerminalLink);
>  
>  	/*
>  	 * Set the driver data before calling video_register_device, otherwise


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [REGRESSION] Re: [PATCH v10 11/21] media: uvcvideo: Set unique vdev name based in type
  2021-12-06 19:05   ` [REGRESSION] " Nicolas Dufresne
@ 2021-12-06 19:15     ` Laurent Pinchart
  0 siblings, 0 replies; 39+ messages in thread
From: Laurent Pinchart @ 2021-12-06 19:15 UTC (permalink / raw)
  To: Nicolas Dufresne
  Cc: Ricardo Ribalda, Hans Verkuil, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel, tfiga, stable

Hi Nicolas,

On Mon, Dec 06, 2021 at 02:05:06PM -0500, Nicolas Dufresne wrote:
> Le vendredi 18 juin 2021 à 14:29 +0200, Ricardo Ribalda a écrit :
> > All the entities must have a unique name. We can have a descriptive and
> > unique name by appending the function and the entity->id.
> 
> Thanks for your work. The only issue is that unfortunately this change cause an
> important regression for users. All UVC cameras in all UIs seems to no longer
> include any information about the camera. As an example, I have two cameras on
> my system and Firefox, Chrome, Cheese, Zoom and MS Team all agree that my camera
> are now:
> 
>   Video Capture 4
>   Video Capture 5
> 
> Previously they would be shown as something like:
> 
>   StreamCam
>   Integrated
> 
> We should probably revert this change quickly before it get deployed more
> widely, I have notice the backport being sent for 5.4, 5.10 and 5.14. I'm using
> 5.15 shipped by Fedora team.

Ack.

> As a proper solution, maybe I could suggest to keep using dev->name, but trim it
> enough to fit the " N" string to guaranty that you have enough space in this
> limited 32 char string and use that instead ? This should fit the uniqueness
> requirement without the sacrifice of the only possibly useful information we had
> in that limited string.

That would polute the device name a bit, which isn't very nice for
users. I wonder if we could instead decouple the entity name from the
video device name.

> > This is even resilent to multi chain devices.
> > 
> > Fixes v4l2-compliance:
> > Media Controller ioctls:
> >                 fail: v4l2-test-media.cpp(205): v2_entity_names_set.find(key) != v2_entity_names_set.end()
> >         test MEDIA_IOC_G_TOPOLOGY: FAIL
> >                 fail: v4l2-test-media.cpp(394): num_data_links != num_links
> > 	test MEDIA_IOC_ENUM_ENTITIES/LINKS: FAIL
> > 
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> > ---
> >  drivers/media/usb/uvc/uvc_driver.c | 7 ++++++-
> >  1 file changed, 6 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> > index 14b60792ffab..037bf80d1100 100644
> > --- a/drivers/media/usb/uvc/uvc_driver.c
> > +++ b/drivers/media/usb/uvc/uvc_driver.c
> > @@ -2194,6 +2194,7 @@ int uvc_register_video_device(struct uvc_device *dev,
> >  			      const struct v4l2_file_operations *fops,
> >  			      const struct v4l2_ioctl_ops *ioctl_ops)
> >  {
> > +	const char *name;
> >  	int ret;
> >  
> >  	/* Initialize the video buffers queue. */
> > @@ -2222,16 +2223,20 @@ int uvc_register_video_device(struct uvc_device *dev,
> >  	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
> >  	default:
> >  		vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> > +		name = "Video Capture";
> >  		break;
> >  	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
> >  		vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
> > +		name = "Video Output";
> >  		break;
> >  	case V4L2_BUF_TYPE_META_CAPTURE:
> >  		vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
> > +		name = "Metadata";
> >  		break;
> >  	}
> >  
> > -	strscpy(vdev->name, dev->name, sizeof(vdev->name));
> > +	snprintf(vdev->name, sizeof(vdev->name), "%s %u", name,
> > +		 stream->header.bTerminalLink);
> >  
> >  	/*
> >  	 * Set the driver data before calling video_register_device, otherwise

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2021-12-06 19:16 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-18 12:29 [PATCH v10 00/21] Fix v4l2-compliance errors Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 01/21] media: v4l2-ioctl: Fix check_ext_ctrls Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 02/21] media: pvrusb2: Do not check for V4L2_CTRL_WHICH_DEF_VAL Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 03/21] media: uvcvideo: " Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 04/21] media: v4l2-ioctl: S_CTRL output the right value Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 05/21] media: uvcvideo: Remove s_ctrl and g_ctrl Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 06/21] media: uvcvideo: Set capability in s_param Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 07/21] media: uvcvideo: Return -EIO for control errors Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 08/21] media: uvcvideo: refactor __uvc_ctrl_add_mapping Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 09/21] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 10/21] media: uvcvideo: Use dev->name for querycap() Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 11/21] media: uvcvideo: Set unique vdev name based in type Ricardo Ribalda
2021-12-06 19:05   ` [REGRESSION] " Nicolas Dufresne
2021-12-06 19:15     ` Laurent Pinchart
2021-06-18 12:29 ` [PATCH v10 12/21] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 13/21] media: uvcvideo: Use control names from framework Ricardo Ribalda
2021-09-03 10:10   ` Mauro Carvalho Chehab
2021-09-03 10:33     ` Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 14/21] media: uvcvideo: Check controls flags before accessing them Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 15/21] media: uvcvideo: Set error_idx during ctrl_commit errors Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 16/21] media: docs: Document the behaviour of uvcvideo driver Ricardo Ribalda
2021-06-18 12:29 ` [PATCH v10 17/21] uvcvideo: uvc_ctrl_is_accessible: check for INACTIVE Ricardo Ribalda
2021-08-22 23:40   ` Laurent Pinchart
2021-06-18 12:29 ` [PATCH v10 18/21] uvcvideo: improve error handling in uvc_query_ctrl() Ricardo Ribalda
2021-08-22 23:52   ` Laurent Pinchart
2021-06-18 12:29 ` [PATCH v10 19/21] uvcvideo: don't spam the log in uvc_ctrl_restore_values() Ricardo Ribalda
2021-08-22 23:23   ` Laurent Pinchart
2021-08-23  0:17   ` Laurent Pinchart
2021-08-23  7:32     ` Hans Verkuil
2021-06-18 12:29 ` [PATCH v10 20/21] uvc: use vb2 ioctl and fop helpers Ricardo Ribalda
2021-08-23  0:00   ` Laurent Pinchart
2021-06-18 12:29 ` [PATCH v10 21/21] media: uvcvideo: Return -EACCES to inactive controls Ricardo Ribalda
2021-06-25 10:29   ` Ricardo Ribalda
2021-06-25 11:06     ` Hans Verkuil
2021-06-25 13:55       ` Ricardo Ribalda
2021-06-30  9:02         ` Hans Verkuil
2021-06-30 12:51           ` Ricardo Ribalda
2021-07-06 14:18             ` Hans Verkuil
2021-07-07  9:07               ` Ricardo Ribalda

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.