linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors
@ 2021-03-15 17:35 Ricardo Ribalda
  2021-03-15 17:35 ` [PATCH v4 01/11] media: v4l2-ioctl: Fix check_ext_ctrls Ricardo Ribalda
                   ` (10 more replies)
  0 siblings, 11 replies; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:35 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  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: 3
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: 3

With Hans patch we can also pass v4l2-compliance -s, but it is a WIP.

Changelog v3 (Thanks to Hans and Laurent)

- Return -EACCES on inactive controls
- Change unique name of the entities
- Increase metadata buffer size

Hans Verkuil (1):
  uvc: use vb2 ioctl and fop helpers

Ricardo Ribalda (10):
  media: v4l2-ioctl: Fix check_ext_ctrls
  media: uvcvideo: Set capability in s_param
  media: uvcvideo: Return -EIO for control errors
  media: uvcvideo: set error_idx to count on EACCESS
  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: Return -EACCES to inactive controls

 drivers/media/usb/uvc/uvc_ctrl.c     | 154 +++++++++++++--
 drivers/media/usb/uvc/uvc_driver.c   |  22 ++-
 drivers/media/usb/uvc/uvc_metadata.c |   8 +-
 drivers/media/usb/uvc/uvc_queue.c    | 131 -------------
 drivers/media/usb/uvc/uvc_v4l2.c     | 283 +++------------------------
 drivers/media/usb/uvc/uvc_video.c    |   5 +
 drivers/media/usb/uvc/uvcvideo.h     |  36 +---
 drivers/media/v4l2-core/v4l2-ioctl.c |  25 ++-
 8 files changed, 210 insertions(+), 454 deletions(-)

-- 
2.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 01/11] media: v4l2-ioctl: Fix check_ext_ctrls
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
@ 2021-03-15 17:35 ` Ricardo Ribalda
  2021-03-15 17:36 ` [PATCH v4 02/11] media: uvcvideo: Set capability in s_param Ricardo Ribalda
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:35 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  Cc: Ricardo Ribalda, stable

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

- Return error when handling of REQUEST_VAL.
- Do not check for multiple classes when getting the DEF_VAL.

Fixes v4l2-compliance:
Control ioctls (Input 0):
		fail: v4l2-test-controls.cpp(813): doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls)
	test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL

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

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 31d1342e61e8..9406e90ff805 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -917,15 +917,24 @@ 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)
+	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 (!allow_priv)
+			return 0;
+		break;
+	case V4L2_CTRL_WHICH_DEF_VAL:
+	case V4L2_CTRL_WHICH_CUR_VAL:
 		return 1;
+	case V4L2_CTRL_WHICH_REQUEST_VAL:
+		return 0;
+	}
+
 	/* 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) {
-- 
2.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 02/11] media: uvcvideo: Set capability in s_param
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
  2021-03-15 17:35 ` [PATCH v4 01/11] media: v4l2-ioctl: Fix check_ext_ctrls Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-15 17:36 ` [PATCH v4 03/11] media: uvcvideo: Return -EIO for control errors Ricardo Ribalda
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  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 252136cc885c..157310c0ca87 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.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 03/11] media: uvcvideo: Return -EIO for control errors
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
  2021-03-15 17:35 ` [PATCH v4 01/11] media: v4l2-ioctl: Fix check_ext_ctrls Ricardo Ribalda
  2021-03-15 17:36 ` [PATCH v4 02/11] media: uvcvideo: Set capability in s_param Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-15 17:36 ` [PATCH v4 04/11] media: uvcvideo: set error_idx to count on EACCESS Ricardo Ribalda
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  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 f2f565281e63..25fd8aa23529 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -112,6 +112,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.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 04/11] media: uvcvideo: set error_idx to count on EACCESS
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
                   ` (2 preceding siblings ...)
  2021-03-15 17:36 ` [PATCH v4 03/11] media: uvcvideo: Return -EIO for control errors Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-16 11:20   ` Hans Verkuil
  2021-03-15 17:36 ` [PATCH v4 05/11] media: uvcvideo: refactor __uvc_ctrl_add_mapping Ricardo Ribalda
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  Cc: Ricardo Ribalda

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):
                fail: v4l2-test-controls.cpp(645): invalid error index write only control
        test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 drivers/media/usb/uvc/uvc_v4l2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 157310c0ca87..36eb48622d48 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1073,7 +1073,8 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
 		ret = uvc_ctrl_get(chain, ctrl);
 		if (ret < 0) {
 			uvc_ctrl_rollback(handle);
-			ctrls->error_idx = i;
+			ctrls->error_idx = (ret == -EACCES) ?
+						ctrls->count : i;
 			return ret;
 		}
 	}
-- 
2.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 05/11] media: uvcvideo: refactor __uvc_ctrl_add_mapping
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
                   ` (3 preceding siblings ...)
  2021-03-15 17:36 ` [PATCH v4 04/11] media: uvcvideo: set error_idx to count on EACCESS Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-15 17:36 ` [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS Ricardo Ribalda
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  Cc: Ricardo Ribalda

Pass the chain instead of the device. We want to keed 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>
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 30ef2a3110f7..35873cf2773d 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2423,14 +2423,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.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
                   ` (4 preceding siblings ...)
  2021-03-15 17:36 ` [PATCH v4 05/11] media: uvcvideo: refactor __uvc_ctrl_add_mapping Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-16  8:37   ` Hans Verkuil
  2021-03-15 17:36 ` [PATCH v4 07/11] media: uvcvideo: Use dev->name for querycap() Ricardo Ribalda
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  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

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 96 ++++++++++++++++++++++++++++++++
 drivers/media/usb/uvc/uvcvideo.h |  6 ++
 2 files changed, 102 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index b75da65115ef..be0fadaf414c 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
 	},
 };
 
+static const struct uvc_control_class uvc_control_class[] = {
+	{
+		.id		= V4L2_CID_CAMERA_CLASS,
+		.name		= "Camera Controls",
+	},
+	{
+		.id		= V4L2_CID_USER_CLASS,
+		.name		= "User Controls",
+	},
+};
+
 static const struct uvc_menu_info power_line_frequency_controls[] = {
 	{ 0, "Disabled" },
 	{ 1, "50 Hz" },
@@ -1024,6 +1035,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_class); i++) {
+		if (!(chain->ctrl_class_bitmap & BIT(i)))
+			continue;
+		if (!find_next) {
+			if (uvc_control_class[i].id == req_id)
+				return i;
+			continue;
+		}
+		if (uvc_control_class[i].id > req_id &&
+		    uvc_control_class[i].id < 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_class[idx].id;
+	strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
+		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 +1181,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 +1499,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 +1537,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 +1658,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 +1680,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 +2149,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 +2173,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_class); i++) {
+		if (V4L2_CTRL_ID2WHICH(uvc_control_class[i].id) ==
+						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 97df5ecd66c9..1f17e4253673 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -262,6 +262,11 @@ struct uvc_control_mapping {
 		    u8 *data);
 };
 
+struct uvc_control_class {
+	u32 id;
+	char name[32];
+};
+
 struct uvc_control {
 	struct uvc_entity *entity;
 	struct uvc_control_info info;
@@ -475,6 +480,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.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 07/11] media: uvcvideo: Use dev->name for querycap()
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
                   ` (5 preceding siblings ...)
  2021-03-15 17:36 ` [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-15 17:36 ` [PATCH v4 08/11] media: uvcvideo: Set unique vdev name based in type Ricardo Ribalda
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  Cc: Ricardo Ribalda

Use the device name for the card name instead of cap->card.

Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_v4l2.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 36eb48622d48..6c1b037a751b 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.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 08/11] media: uvcvideo: Set unique vdev name based in type
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
                   ` (6 preceding siblings ...)
  2021-03-15 17:36 ` [PATCH v4 07/11] media: uvcvideo: Use dev->name for querycap() Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-16 10:10   ` Hans Verkuil
  2021-03-15 17:36 ` [PATCH v4 09/11] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE Ricardo Ribalda
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  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>
---
 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 35873cf2773d..73ab30891845 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2163,6 +2163,7 @@ int uvc_register_video_device(struct uvc_device *dev,
 			      const struct v4l2_ioctl_ops *ioctl_ops)
 {
 	int ret;
+	const char *name;
 
 	/* Initialize the video buffers queue. */
 	ret = uvc_queue_init(queue, type, !uvc_no_drop_param);
@@ -2190,16 +2191,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.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 09/11] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
                   ` (7 preceding siblings ...)
  2021-03-15 17:36 ` [PATCH v4 08/11] media: uvcvideo: Set unique vdev name based in type Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-16  9:45   ` Hans Verkuil
  2021-03-15 17:36 ` [PATCH v4 10/11] media: uvcvideo: Return -EACCES to inactive controls Ricardo Ribalda
  2021-03-15 17:36 ` [PATCH v4 11/11] uvc: use vb2 ioctl and fop helpers Ricardo Ribalda
  10 siblings, 1 reply; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  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.

Credit-to: Hans Verkuil <hverkuil@xs4all.nl>
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 1f17e4253673..91fc00ff311b 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -528,7 +528,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.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 10/11] media: uvcvideo: Return -EACCES to inactive controls
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
                   ` (8 preceding siblings ...)
  2021-03-15 17:36 ` [PATCH v4 09/11] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-15 17:36 ` [PATCH v4 11/11] uvc: use vb2 ioctl and fop helpers Ricardo Ribalda
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  Cc: Ricardo Ribalda, Hans Verkuil

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.

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

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index be0fadaf414c..f1593dc2f1ef 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1580,6 +1580,18 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain)
 	return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0;
 }
 
+static bool uvc_ctrl_is_inactive(struct uvc_control *ctrl)
+{
+	struct uvc_control_mapping *map;
+
+	list_for_each_entry(map, &ctrl->info.mappings, list) {
+		if (map->master_id)
+			return true;
+	}
+
+	return false;
+}
+
 static int uvc_ctrl_commit_entity(struct uvc_device *dev,
 	struct uvc_entity *entity, int rollback)
 {
@@ -1623,8 +1635,11 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
 
 		ctrl->dirty = 0;
 
-		if (ret < 0)
+		if (ret < 0) {
+			if (uvc_ctrl_is_inactive(ctrl))
+				return -EACCES;
 			return ret;
+		}
 	}
 
 	return 0;
-- 
2.31.0.rc2.261.g7f71774620-goog


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

* [PATCH v4 11/11] uvc: use vb2 ioctl and fop helpers
  2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
                   ` (9 preceding siblings ...)
  2021-03-15 17:36 ` [PATCH v4 10/11] media: uvcvideo: Return -EACCES to inactive controls Ricardo Ribalda
@ 2021-03-15 17:36 ` Ricardo Ribalda
  2021-03-16 11:29   ` Hans Verkuil
  10 siblings, 1 reply; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-15 17:36 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
	Sergey Senozhatsky, linux-media, linux-kernel
  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    | 131 -------------
 drivers/media/usb/uvc/uvc_v4l2.c     | 272 ++-------------------------
 drivers/media/usb/uvc/uvcvideo.h     |  28 ---
 5 files changed, 24 insertions(+), 422 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 73ab30891845..507b90061bd3 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1911,7 +1911,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;
 }
@@ -2181,7 +2180,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
@@ -2546,8 +2545,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 b6279ad7ac84..849d8e5ab75d 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..fba9646c8ba5 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -247,115 +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)
@@ -364,36 +259,10 @@ unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
 }
 #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 6c1b037a751b..348a46637852 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -346,17 +346,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;
 }
@@ -483,62 +479,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
  */
@@ -581,7 +521,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;
@@ -594,15 +533,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);
@@ -695,11 +627,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);
 }
@@ -709,11 +636,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);
 }
@@ -738,124 +660,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)
 {
@@ -923,13 +727,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)) {
@@ -1190,11 +993,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);
 }
@@ -1462,36 +1260,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,
@@ -1516,14 +1284,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,
@@ -1553,9 +1322,8 @@ 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,
 #endif
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 91fc00ff311b..4e6f0a25b940 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -478,7 +478,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 */
 };
@@ -715,16 +714,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 {
@@ -789,36 +782,15 @@ 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.31.0.rc2.261.g7f71774620-goog


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

* Re: [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS
  2021-03-15 17:36 ` [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS Ricardo Ribalda
@ 2021-03-16  8:37   ` Hans Verkuil
  2021-03-16 10:08     ` Laurent Pinchart
  0 siblings, 1 reply; 20+ messages in thread
From: Hans Verkuil @ 2021-03-16  8:37 UTC (permalink / raw)
  To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel

On 15/03/2021 18:36, Ricardo Ribalda wrote:
> 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
> 
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 96 ++++++++++++++++++++++++++++++++
>  drivers/media/usb/uvc/uvcvideo.h |  6 ++
>  2 files changed, 102 insertions(+)
> 
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index b75da65115ef..be0fadaf414c 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
>  	},
>  };
>  
> +static const struct uvc_control_class uvc_control_class[] = {
> +	{
> +		.id		= V4L2_CID_CAMERA_CLASS,
> +		.name		= "Camera Controls",
> +	},
> +	{
> +		.id		= V4L2_CID_USER_CLASS,
> +		.name		= "User Controls",

I noticed that uvc_ctrl.c has hardcoded strings for the control names and
control menus.

It would be good to drop that from the code and instead use v4l2_ctrl_get_menu()
and v4l2_ctrl_get_name() to obtain the names. It ensures consistent naming and
saves a bit of memory.

This can be done in a separate patch before or after this one.

Regards,

	Hans

> +	},
> +};
> +
>  static const struct uvc_menu_info power_line_frequency_controls[] = {
>  	{ 0, "Disabled" },
>  	{ 1, "50 Hz" },
> @@ -1024,6 +1035,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_class); i++) {
> +		if (!(chain->ctrl_class_bitmap & BIT(i)))
> +			continue;
> +		if (!find_next) {
> +			if (uvc_control_class[i].id == req_id)
> +				return i;
> +			continue;
> +		}
> +		if (uvc_control_class[i].id > req_id &&
> +		    uvc_control_class[i].id < 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_class[idx].id;
> +	strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
> +		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 +1181,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 +1499,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 +1537,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 +1658,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 +1680,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 +2149,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 +2173,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_class); i++) {
> +		if (V4L2_CTRL_ID2WHICH(uvc_control_class[i].id) ==
> +						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 97df5ecd66c9..1f17e4253673 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -262,6 +262,11 @@ struct uvc_control_mapping {
>  		    u8 *data);
>  };
>  
> +struct uvc_control_class {
> +	u32 id;
> +	char name[32];
> +};
> +
>  struct uvc_control {
>  	struct uvc_entity *entity;
>  	struct uvc_control_info info;
> @@ -475,6 +480,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 {
> 


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

* Re: [PATCH v4 09/11] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE
  2021-03-15 17:36 ` [PATCH v4 09/11] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE Ricardo Ribalda
@ 2021-03-16  9:45   ` Hans Verkuil
  0 siblings, 0 replies; 20+ messages in thread
From: Hans Verkuil @ 2021-03-16  9:45 UTC (permalink / raw)
  To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel

Hi Ricardo, Laurent,

On 15/03/2021 18:36, Ricardo Ribalda wrote:
> 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.
> 
> Credit-to: Hans Verkuil <hverkuil@xs4all.nl>
> 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 1f17e4253673..91fc00ff311b 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -528,7 +528,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
> 

I've been doing some tests here, and this is tricky.

I think the core bug is in uvc_video_decode_meta():

        if (meta_buf->length - meta_buf->bytesused <
            length + sizeof(meta->ns) + sizeof(meta->sof)) {
                meta_buf->error = 1;
                return;
        }

This checks for a buffer overflow and by setting meta_buf->error to 1 it causes
the whole buffer to be discarded. But according to the V4L2_META_FMT_UVC docs here

https://hverkuil.home.xs4all.nl/spec/userspace-api/v4l/pixfmt-meta-uvc.html

it should "drop headers when the buffer is full", which suggests to me that
the 'meta_buf->error = 1;' is wrong and should be removed.

Looking at the number of headers I receive for various frame sizes and frame rates
when choosing YUYV as the pixelformat I see that the frame rate is the main input
to that: I get (very roughly) one header for every 150 microseconds. So that's
roughly 667 headers of 22 bytes for a 10 fps capture. The frame size has some
effect, but it is fairly small. This means that for slow captures (i.e. 2 fps)
you need about 75000 bytes, let's round it up to 102400.

I did tests with 1920x1080 at 5 fps for YUYV, H264 and MJPEG and saw the following:

Format		Video Size	Metadata Size

YUYV		4147200		29964
MJPG		130000		3608
H264 (P-frame)	70000		2600
H264 (I-frame)	150000		5500

The difference here is most likely due to YUYV being transmitted over time as
video lines arrive, so it is spread out over time, while H264 and MJPG are
bursty, i.e. the whole compressed frame is transferred in one go.

I think that 10240 is a good value for the metadata buffers since it is enough
for the worst-case for the compressed formats, and that if this is combined
with removing the 'meta_buf->error = 1;' it will also do its job for YUYV
even though data will be dropped, but that's better than not getting anything
at all.

Regards,

	Hans

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

* Re: [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS
  2021-03-16  8:37   ` Hans Verkuil
@ 2021-03-16 10:08     ` Laurent Pinchart
  2021-03-16 10:12       ` Ricardo Ribalda
  0 siblings, 1 reply; 20+ messages in thread
From: Laurent Pinchart @ 2021-03-16 10:08 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Ricardo Ribalda, Mauro Carvalho Chehab, Sergey Senozhatsky,
	linux-media, linux-kernel

Hi Hans,

On Tue, Mar 16, 2021 at 09:37:07AM +0100, Hans Verkuil wrote:
> On 15/03/2021 18:36, Ricardo Ribalda wrote:
> > 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
> > 
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> >  drivers/media/usb/uvc/uvc_ctrl.c | 96 ++++++++++++++++++++++++++++++++
> >  drivers/media/usb/uvc/uvcvideo.h |  6 ++
> >  2 files changed, 102 insertions(+)
> > 
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index b75da65115ef..be0fadaf414c 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
> >  	},
> >  };
> >  
> > +static const struct uvc_control_class uvc_control_class[] = {
> > +	{
> > +		.id		= V4L2_CID_CAMERA_CLASS,
> > +		.name		= "Camera Controls",
> > +	},
> > +	{
> > +		.id		= V4L2_CID_USER_CLASS,
> > +		.name		= "User Controls",
> 
> I noticed that uvc_ctrl.c has hardcoded strings for the control names and
> control menus.
> 
> It would be good to drop that from the code and instead use v4l2_ctrl_get_menu()
> and v4l2_ctrl_get_name() to obtain the names. It ensures consistent naming and
> saves a bit of memory.
> 
> This can be done in a separate patch before or after this one.

https://git.linuxtv.org/pinchartl/media.git/commit/?h=uvc/dev&id=16a7d79d67cdd06a448d8c4c20e270d1c21828b1

It's work in progress, the part that bothers me is the changes in
uvc_parse_format(). We lose the human-readable name in a debug message,
but maybe more importantly, we lose the distinction between different DV
formats. Maybe it's not a big deal.

> > +	},
> > +};
> > +
> >  static const struct uvc_menu_info power_line_frequency_controls[] = {
> >  	{ 0, "Disabled" },
> >  	{ 1, "50 Hz" },
> > @@ -1024,6 +1035,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_class); i++) {
> > +		if (!(chain->ctrl_class_bitmap & BIT(i)))
> > +			continue;
> > +		if (!find_next) {
> > +			if (uvc_control_class[i].id == req_id)
> > +				return i;
> > +			continue;
> > +		}
> > +		if (uvc_control_class[i].id > req_id &&
> > +		    uvc_control_class[i].id < 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_class[idx].id;
> > +	strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
> > +		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 +1181,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 +1499,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 +1537,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 +1658,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 +1680,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 +2149,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 +2173,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_class); i++) {
> > +		if (V4L2_CTRL_ID2WHICH(uvc_control_class[i].id) ==
> > +						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 97df5ecd66c9..1f17e4253673 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -262,6 +262,11 @@ struct uvc_control_mapping {
> >  		    u8 *data);
> >  };
> >  
> > +struct uvc_control_class {
> > +	u32 id;
> > +	char name[32];
> > +};
> > +
> >  struct uvc_control {
> >  	struct uvc_entity *entity;
> >  	struct uvc_control_info info;
> > @@ -475,6 +480,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 {
> > 
> 

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v4 08/11] media: uvcvideo: Set unique vdev name based in type
  2021-03-15 17:36 ` [PATCH v4 08/11] media: uvcvideo: Set unique vdev name based in type Ricardo Ribalda
@ 2021-03-16 10:10   ` Hans Verkuil
  0 siblings, 0 replies; 20+ messages in thread
From: Hans Verkuil @ 2021-03-16 10:10 UTC (permalink / raw)
  To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel

On 15/03/2021 18:36, Ricardo Ribalda wrote:
> 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>
> ---
>  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 35873cf2773d..73ab30891845 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -2163,6 +2163,7 @@ int uvc_register_video_device(struct uvc_device *dev,
>  			      const struct v4l2_ioctl_ops *ioctl_ops)
>  {
>  	int ret;
> +	const char *name;
>  
>  	/* Initialize the video buffers queue. */
>  	ret = uvc_queue_init(queue, type, !uvc_no_drop_param);
> @@ -2190,16 +2191,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";

capture -> Capture

>  		break;
>  	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
>  		vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
> +		name = "Video output";

output -> 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
> 

With those changes:

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

Regards,

	Hans

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

* Re: [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS
  2021-03-16 10:08     ` Laurent Pinchart
@ 2021-03-16 10:12       ` Ricardo Ribalda
  2021-03-16 11:04         ` Laurent Pinchart
  0 siblings, 1 reply; 20+ messages in thread
From: Ricardo Ribalda @ 2021-03-16 10:12 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Hans Verkuil, Mauro Carvalho Chehab, Sergey Senozhatsky,
	Linux Media Mailing List, Linux Kernel Mailing List

Hi Laurent

On Tue, Mar 16, 2021 at 11:08 AM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Hans,
>
> On Tue, Mar 16, 2021 at 09:37:07AM +0100, Hans Verkuil wrote:
> > On 15/03/2021 18:36, Ricardo Ribalda wrote:
> > > 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
> > >
> > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > ---
> > >  drivers/media/usb/uvc/uvc_ctrl.c | 96 ++++++++++++++++++++++++++++++++
> > >  drivers/media/usb/uvc/uvcvideo.h |  6 ++
> > >  2 files changed, 102 insertions(+)
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > index b75da65115ef..be0fadaf414c 100644
> > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > >     },
> > >  };
> > >
> > > +static const struct uvc_control_class uvc_control_class[] = {
> > > +   {
> > > +           .id             = V4L2_CID_CAMERA_CLASS,
> > > +           .name           = "Camera Controls",
> > > +   },
> > > +   {
> > > +           .id             = V4L2_CID_USER_CLASS,
> > > +           .name           = "User Controls",
> >
> > I noticed that uvc_ctrl.c has hardcoded strings for the control names and
> > control menus.
> >
> > It would be good to drop that from the code and instead use v4l2_ctrl_get_menu()
> > and v4l2_ctrl_get_name() to obtain the names. It ensures consistent naming and
> > saves a bit of memory.
> >
> > This can be done in a separate patch before or after this one.
>
> https://git.linuxtv.org/pinchartl/media.git/commit/?h=uvc/dev&id=16a7d79d67cdd06a448d8c4c20e270d1c21828b1
>
> It's work in progress, the part that bothers me is the changes in
> uvc_parse_format(). We lose the human-readable name in a debug message,
> but maybe more importantly, we lose the distinction between different DV
> formats. Maybe it's not a big deal.

That patch is for format descriptions. If you haven't started yet I
can implement the change for the control names.

Thanks!

>
> > > +   },
> > > +};
> > > +
> > >  static const struct uvc_menu_info power_line_frequency_controls[] = {
> > >     { 0, "Disabled" },
> > >     { 1, "50 Hz" },
> > > @@ -1024,6 +1035,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_class); i++) {
> > > +           if (!(chain->ctrl_class_bitmap & BIT(i)))
> > > +                   continue;
> > > +           if (!find_next) {
> > > +                   if (uvc_control_class[i].id == req_id)
> > > +                           return i;
> > > +                   continue;
> > > +           }
> > > +           if (uvc_control_class[i].id > req_id &&
> > > +               uvc_control_class[i].id < 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_class[idx].id;
> > > +   strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
> > > +           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 +1181,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 +1499,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 +1537,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 +1658,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 +1680,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 +2149,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 +2173,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_class); i++) {
> > > +           if (V4L2_CTRL_ID2WHICH(uvc_control_class[i].id) ==
> > > +                                           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 97df5ecd66c9..1f17e4253673 100644
> > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > @@ -262,6 +262,11 @@ struct uvc_control_mapping {
> > >                 u8 *data);
> > >  };
> > >
> > > +struct uvc_control_class {
> > > +   u32 id;
> > > +   char name[32];
> > > +};
> > > +
> > >  struct uvc_control {
> > >     struct uvc_entity *entity;
> > >     struct uvc_control_info info;
> > > @@ -475,6 +480,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 {
> > >
> >
>
> --
> Regards,
>
> Laurent Pinchart



-- 
Ricardo Ribalda

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

* Re: [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS
  2021-03-16 10:12       ` Ricardo Ribalda
@ 2021-03-16 11:04         ` Laurent Pinchart
  0 siblings, 0 replies; 20+ messages in thread
From: Laurent Pinchart @ 2021-03-16 11:04 UTC (permalink / raw)
  To: Ricardo Ribalda
  Cc: Hans Verkuil, Mauro Carvalho Chehab, Sergey Senozhatsky,
	Linux Media Mailing List, Linux Kernel Mailing List

Hi Ricardo,

On Tue, Mar 16, 2021 at 11:12:57AM +0100, Ricardo Ribalda wrote:
> On Tue, Mar 16, 2021 at 11:08 AM Laurent Pinchart wrote:
> > On Tue, Mar 16, 2021 at 09:37:07AM +0100, Hans Verkuil wrote:
> > > On 15/03/2021 18:36, Ricardo Ribalda wrote:
> > > > 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
> > > >
> > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > ---
> > > >  drivers/media/usb/uvc/uvc_ctrl.c | 96 ++++++++++++++++++++++++++++++++
> > > >  drivers/media/usb/uvc/uvcvideo.h |  6 ++
> > > >  2 files changed, 102 insertions(+)
> > > >
> > > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > index b75da65115ef..be0fadaf414c 100644
> > > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > > >     },
> > > >  };
> > > >
> > > > +static const struct uvc_control_class uvc_control_class[] = {
> > > > +   {
> > > > +           .id             = V4L2_CID_CAMERA_CLASS,
> > > > +           .name           = "Camera Controls",
> > > > +   },
> > > > +   {
> > > > +           .id             = V4L2_CID_USER_CLASS,
> > > > +           .name           = "User Controls",
> > >
> > > I noticed that uvc_ctrl.c has hardcoded strings for the control names and
> > > control menus.
> > >
> > > It would be good to drop that from the code and instead use v4l2_ctrl_get_menu()
> > > and v4l2_ctrl_get_name() to obtain the names. It ensures consistent naming and
> > > saves a bit of memory.
> > >
> > > This can be done in a separate patch before or after this one.
> >
> > https://git.linuxtv.org/pinchartl/media.git/commit/?h=uvc/dev&id=16a7d79d67cdd06a448d8c4c20e270d1c21828b1
> >
> > It's work in progress, the part that bothers me is the changes in
> > uvc_parse_format(). We lose the human-readable name in a debug message,
> > but maybe more importantly, we lose the distinction between different DV
> > formats. Maybe it's not a big deal.
> 
> That patch is for format descriptions. If you haven't started yet I
> can implement the change for the control names.

I should try to wake up before sending e-mails, to avoid making a fool
of myself :-S

I haven't done any work on control names in this area.

> > > > +   },
> > > > +};
> > > > +
> > > >  static const struct uvc_menu_info power_line_frequency_controls[] = {
> > > >     { 0, "Disabled" },
> > > >     { 1, "50 Hz" },
> > > > @@ -1024,6 +1035,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_class); i++) {
> > > > +           if (!(chain->ctrl_class_bitmap & BIT(i)))
> > > > +                   continue;
> > > > +           if (!find_next) {
> > > > +                   if (uvc_control_class[i].id == req_id)
> > > > +                           return i;
> > > > +                   continue;
> > > > +           }
> > > > +           if (uvc_control_class[i].id > req_id &&
> > > > +               uvc_control_class[i].id < 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_class[idx].id;
> > > > +   strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
> > > > +           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 +1181,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 +1499,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 +1537,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 +1658,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 +1680,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 +2149,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 +2173,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_class); i++) {
> > > > +           if (V4L2_CTRL_ID2WHICH(uvc_control_class[i].id) ==
> > > > +                                           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 97df5ecd66c9..1f17e4253673 100644
> > > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > > @@ -262,6 +262,11 @@ struct uvc_control_mapping {
> > > >                 u8 *data);
> > > >  };
> > > >
> > > > +struct uvc_control_class {
> > > > +   u32 id;
> > > > +   char name[32];
> > > > +};
> > > > +
> > > >  struct uvc_control {
> > > >     struct uvc_entity *entity;
> > > >     struct uvc_control_info info;
> > > > @@ -475,6 +480,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 {
> > > >

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v4 04/11] media: uvcvideo: set error_idx to count on EACCESS
  2021-03-15 17:36 ` [PATCH v4 04/11] media: uvcvideo: set error_idx to count on EACCESS Ricardo Ribalda
@ 2021-03-16 11:20   ` Hans Verkuil
  0 siblings, 0 replies; 20+ messages in thread
From: Hans Verkuil @ 2021-03-16 11:20 UTC (permalink / raw)
  To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel

On 15/03/2021 18:36, Ricardo Ribalda wrote:
> 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):
>                 fail: v4l2-test-controls.cpp(645): invalid error index write only control
>         test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
> 
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> ---
>  drivers/media/usb/uvc/uvc_v4l2.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 157310c0ca87..36eb48622d48 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1073,7 +1073,8 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
>  		ret = uvc_ctrl_get(chain, ctrl);
>  		if (ret < 0) {
>  			uvc_ctrl_rollback(handle);
> -			ctrls->error_idx = i;
> +			ctrls->error_idx = (ret == -EACCES) ?
> +						ctrls->count : i;

This isn't right.

For G_EXT_CTRLS error_idx should be set to either ctrls->count or the index of the
failing control depending on whether the hardware has been touched or not.

In the case of the 'if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {' the hardware
has not been touched, so there is should set error_idx to ctrls->count.

In the case where we obtain the actual values with uvc_ctrl_get() it must return
the index of the failing control.

According to the spec if VIDIOC_G_EXT_CTRLS returns an error and error_idx is equal
to the total count, then no hardware was touched, so it was during the validation
phase that some error was detected. If it returns an error and error_idx < count,
then the hardware was accessed and the contents of the controls at indices >= error_idx
is undefined.

So setting error_idx to i is the right thing to do, regardless of the EACCES test.

This does create a problem in v4l2-compliance, since it assumes that the control
framework is used, and that framework validates the control first in a separate step
before accessing the hardware. That's missing in uvc. I think v4l2-compliance should
be adjusted for uvcvideo since uvc isn't doing anything illegal by returning i here
since it really accessed hardware.

An alternative would be to introduce an initial validation phase in uvc_ioctl_g_ext_ctrls
as well, but I'm not sure that it worth the effort. It's quite difficult to get it really
right.

Relaxing the tests in v4l2-compliance for uvc is a better approach IMHO.

Or rewrite uvc to use the control framework :-) :-)

Regards,

	Hans

>  			return ret;
>  		}
>  	}
> 


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

* Re: [PATCH v4 11/11] uvc: use vb2 ioctl and fop helpers
  2021-03-15 17:36 ` [PATCH v4 11/11] uvc: use vb2 ioctl and fop helpers Ricardo Ribalda
@ 2021-03-16 11:29   ` Hans Verkuil
  0 siblings, 0 replies; 20+ messages in thread
From: Hans Verkuil @ 2021-03-16 11:29 UTC (permalink / raw)
  To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
	Sergey Senozhatsky, linux-media, linux-kernel
  Cc: Hans Verkuil

Hi Ricardo,

On 15/03/2021 18:36, 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>


You can merge this patch into 11/11. I analyzed the uvc get_unmapped_area
implementation and it is 100% identical to the vb2_fop_get_unmapped_area
implementation, so let's use that one instead.

Regards.

	Hans

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index fba9646c8ba5..437e48b32480 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -247,18 +247,6 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
 	return 0;
 }

-/* -----------------------------------------------------------------------------
- * V4L2 queue operations
- */
-
-#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
-
 /* -----------------------------------------------------------------------------
  *
  */
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 348a46637852..172336d6018c 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1260,20 +1260,6 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
 }
 #endif

-#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,
@@ -1325,7 +1311,7 @@ const struct v4l2_file_operations uvc_fops = {
 	.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 4e6f0a25b940..a83b16ba6e6a 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -787,10 +787,7 @@ 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);
-#ifndef CONFIG_MMU
-unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
-					  unsigned long pgoff);
-#endif
+
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
 	return vb2_is_streaming(&queue->queue);

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

end of thread, other threads:[~2021-03-16 11:30 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-15 17:35 [PATCH v4 00/11] uvcvideo: Fix v4l2-compliance errors Ricardo Ribalda
2021-03-15 17:35 ` [PATCH v4 01/11] media: v4l2-ioctl: Fix check_ext_ctrls Ricardo Ribalda
2021-03-15 17:36 ` [PATCH v4 02/11] media: uvcvideo: Set capability in s_param Ricardo Ribalda
2021-03-15 17:36 ` [PATCH v4 03/11] media: uvcvideo: Return -EIO for control errors Ricardo Ribalda
2021-03-15 17:36 ` [PATCH v4 04/11] media: uvcvideo: set error_idx to count on EACCESS Ricardo Ribalda
2021-03-16 11:20   ` Hans Verkuil
2021-03-15 17:36 ` [PATCH v4 05/11] media: uvcvideo: refactor __uvc_ctrl_add_mapping Ricardo Ribalda
2021-03-15 17:36 ` [PATCH v4 06/11] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS Ricardo Ribalda
2021-03-16  8:37   ` Hans Verkuil
2021-03-16 10:08     ` Laurent Pinchart
2021-03-16 10:12       ` Ricardo Ribalda
2021-03-16 11:04         ` Laurent Pinchart
2021-03-15 17:36 ` [PATCH v4 07/11] media: uvcvideo: Use dev->name for querycap() Ricardo Ribalda
2021-03-15 17:36 ` [PATCH v4 08/11] media: uvcvideo: Set unique vdev name based in type Ricardo Ribalda
2021-03-16 10:10   ` Hans Verkuil
2021-03-15 17:36 ` [PATCH v4 09/11] media: uvcvideo: Increase the size of UVC_METADATA_BUF_SIZE Ricardo Ribalda
2021-03-16  9:45   ` Hans Verkuil
2021-03-15 17:36 ` [PATCH v4 10/11] media: uvcvideo: Return -EACCES to inactive controls Ricardo Ribalda
2021-03-15 17:36 ` [PATCH v4 11/11] uvc: use vb2 ioctl and fop helpers Ricardo Ribalda
2021-03-16 11:29   ` Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).