* [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI
@ 2024-11-14 19:10 Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 01/19] media: uvcvideo: Fix event flags in uvc_ctrl_send_events Ricardo Ribalda
` (19 more replies)
0 siblings, 20 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, stable,
Yunke Cao, Sergey Senozhatsky, Daniel Scally, Hans Verkuil
This patchset implements UVC v1.5 region of interest using V4L2
control API.
ROI control is consisted two uvc specific controls.
1. A rectangle control with a newly added type V4L2_CTRL_TYPE_RECT.
2. An auto control with type bitmask.
V4L2_CTRL_WHICH_MIN/MAX_VAL is added to support the rectangle control.
The corresponding v4l-utils series can be found at
https://patchwork.linuxtv.org/project/linux-media/list/?series=11069 .
Tested with v4l2-compliance, v4l2-ctl, calling ioctls on usb cameras and
VIVID with a newly added V4L2_CTRL_TYPE_RECT control.
This set includes also the patch:
media: uvcvideo: Fix event flags in uvc_ctrl_send_events
It is not technically part of this change, but we conflict with it.
I am continuing the work that Yunke did.
Changes in v15:
- Modify mapping set/get to support any size
- Remove v4l2_size field. It is not needed, we can use the v4l2_type to
infer it.
- Improve documentation.
- Lots of refactoring, now adding compound and roi are very small
patches.
- Remove rectangle clamping, not supported by some firmware.
- Remove init, we can add it later.
- Move uvc_cid to USER_BASE
- Link to v14: https://lore.kernel.org/linux-media/20231201071907.3080126-1-yunkec@google.com/
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
Hans Verkuil (1):
media: v4l2-ctrls: add support for V4L2_CTRL_WHICH_MIN/MAX_VAL
Ricardo Ribalda (12):
media: uvcvideo: Fix event flags in uvc_ctrl_send_events
media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value
media: uvcvideo: Handle uvc menu translation inside uvc_set_le_value
media: uvcvideo: refactor uvc_ioctl_g_ext_ctrls
media: uvcvideo: uvc_ioctl_(g|s)_ext_ctrls: handle NoP case
media: uvcvideo: Support any size for mapping get/set
media: uvcvideo: Factor out clamping from uvc_ctrl_set
media: uvcvideo: Factor out query_boundaries from query_ctrl
media: uvcvideo: Use the camera to clamp compound controls
media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl
media: uvcvideo: Introduce uvc_mapping_v4l2_size
media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map
Yunke Cao (6):
media: v4l2_ctrl: Add V4L2_CTRL_TYPE_RECT
media: vivid: Add a rectangle control
media: uvcvideo: add support for compound controls
media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL
media: uvcvideo: implement UVC v1.5 ROI
media: uvcvideo: document UVC v1.5 ROI
.../userspace-api/media/drivers/uvcvideo.rst | 64 ++
.../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 26 +-
.../userspace-api/media/v4l/vidioc-queryctrl.rst | 14 +
.../userspace-api/media/videodev2.h.rst.exceptions | 4 +
drivers/media/i2c/imx214.c | 4 +-
drivers/media/platform/qcom/venus/venc_ctrls.c | 9 +-
drivers/media/test-drivers/vivid/vivid-ctrls.c | 34 +
drivers/media/usb/uvc/uvc_ctrl.c | 805 ++++++++++++++++-----
drivers/media/usb/uvc/uvc_v4l2.c | 77 +-
drivers/media/usb/uvc/uvcvideo.h | 25 +-
drivers/media/v4l2-core/v4l2-ctrls-api.c | 54 +-
drivers/media/v4l2-core/v4l2-ctrls-core.c | 167 ++++-
drivers/media/v4l2-core/v4l2-ioctl.c | 4 +-
include/media/v4l2-ctrls.h | 38 +-
include/uapi/linux/usb/video.h | 1 +
include/uapi/linux/uvcvideo.h | 13 +
include/uapi/linux/v4l2-controls.h | 9 +
include/uapi/linux/videodev2.h | 5 +
18 files changed, 1062 insertions(+), 291 deletions(-)
---
base-commit: 5516200c466f92954551406ea641376963c43a92
change-id: 20241113-uvc-roi-66bd6cfa1e64
Best regards,
--
Ricardo Ribalda <ribalda@chromium.org>
^ permalink raw reply [flat|nested] 62+ messages in thread
* [PATCH v15 01/19] media: uvcvideo: Fix event flags in uvc_ctrl_send_events
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 02/19] media: v4l2_ctrl: Add V4L2_CTRL_TYPE_RECT Ricardo Ribalda
` (18 subsequent siblings)
19 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, stable
If there is an event that needs the V4L2_EVENT_CTRL_CH_FLAGS flag, all
the following events will have that flag, regardless if they need it or
not.
This is because we keep using the same variable all the time and we do
not reset its original value.
Cc: stable@vger.kernel.org
Fixes: 805e9b4a06bf ("[media] uvcvideo: Send control change events for slave ctrls when the master changes")
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 4fe26e82e3d1..bab9fdac98e6 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1673,13 +1673,13 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
{
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl;
- u32 changes = V4L2_EVENT_CTRL_CH_VALUE;
unsigned int i;
unsigned int j;
for (i = 0; i < xctrls_count; ++i) {
- ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
+ u32 changes = V4L2_EVENT_CTRL_CH_VALUE;
+ ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
/* Notification will be sent from an Interrupt event. */
continue;
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 02/19] media: v4l2_ctrl: Add V4L2_CTRL_TYPE_RECT
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 01/19] media: uvcvideo: Fix event flags in uvc_ctrl_send_events Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 03/19] media: v4l2-ctrls: add support for V4L2_CTRL_WHICH_MIN/MAX_VAL Ricardo Ribalda
` (17 subsequent siblings)
19 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, Yunke Cao,
Sergey Senozhatsky, Daniel Scally, Hans Verkuil
From: Yunke Cao <yunkec@google.com>
Add p_rect to struct v4l2_ext_control with basic support in
v4l2-ctrls.
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Signed-off-by: Yunke Cao <yunkec@google.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
.../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 4 ++++
.../userspace-api/media/v4l/vidioc-queryctrl.rst | 7 +++++++
.../userspace-api/media/videodev2.h.rst.exceptions | 1 +
drivers/media/v4l2-core/v4l2-ctrls-core.c | 16 +++++++++++++++-
include/media/v4l2-ctrls.h | 2 ++
include/uapi/linux/videodev2.h | 2 ++
6 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
index 4d56c0528ad7..b74a74ac06fc 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
@@ -199,6 +199,10 @@ still cause this situation.
- ``p_area``
- A pointer to a struct :c:type:`v4l2_area`. Valid if this control is
of type ``V4L2_CTRL_TYPE_AREA``.
+ * - struct :c:type:`v4l2_rect` *
+ - ``p_rect``
+ - A pointer to a struct :c:type:`v4l2_rect`. Valid if this control is
+ of type ``V4L2_CTRL_TYPE_RECT``.
* - struct :c:type:`v4l2_ctrl_h264_sps` *
- ``p_h264_sps``
- A pointer to a struct :c:type:`v4l2_ctrl_h264_sps`. Valid if this control is
diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
index 4d38acafe8e1..56d5c8b0b88b 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
@@ -441,6 +441,13 @@ See also the examples in :ref:`control`.
- n/a
- A struct :c:type:`v4l2_area`, containing the width and the height
of a rectangular area. Units depend on the use case.
+ * - ``V4L2_CTRL_TYPE_RECT``
+ - n/a
+ - n/a
+ - n/a
+ - A struct :c:type:`v4l2_rect`, containing a rectangle described by
+ the position of its top-left corner, the width and the height. Units
+ depend on the use case.
* - ``V4L2_CTRL_TYPE_H264_SPS``
- n/a
- n/a
diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions
index 429b5cdf05c3..3cf1380b52b0 100644
--- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions
+++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions
@@ -150,6 +150,7 @@ replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_AREA :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_RECT :c:type:`v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_FWHT_PARAMS :c:type:`v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_VP8_FRAME :c:type:`v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR :c:type:`v4l2_ctrl_type`
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index eeab6a5eb7ba..4c8744c8cd96 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -370,7 +370,11 @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
case V4L2_CTRL_TYPE_AV1_FILM_GRAIN:
pr_cont("AV1_FILM_GRAIN");
break;
-
+ case V4L2_CTRL_TYPE_RECT:
+ pr_cont("%ux%u@%dx%d",
+ ptr.p_rect->width, ptr.p_rect->height,
+ ptr.p_rect->left, ptr.p_rect->top);
+ break;
default:
pr_cont("unknown type %d", ctrl->type);
break;
@@ -815,6 +819,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params;
struct v4l2_area *area;
+ struct v4l2_rect *rect;
void *p = ptr.p + idx * ctrl->elem_size;
unsigned int i;
@@ -1172,6 +1177,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
return -EINVAL;
break;
+ case V4L2_CTRL_TYPE_RECT:
+ rect = p;
+ if (!rect->width || !rect->height)
+ return -EINVAL;
+ break;
+
default:
return -EINVAL;
}
@@ -1872,6 +1883,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
case V4L2_CTRL_TYPE_AREA:
elem_size = sizeof(struct v4l2_area);
break;
+ case V4L2_CTRL_TYPE_RECT:
+ elem_size = sizeof(struct v4l2_rect);
+ break;
default:
if (type < V4L2_CTRL_COMPOUND_TYPES)
elem_size = sizeof(s32);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 59679a42b3e7..b0db167a3ac4 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -56,6 +56,7 @@ struct video_device;
* @p_av1_tile_group_entry: Pointer to an AV1 tile group entry structure.
* @p_av1_frame: Pointer to an AV1 frame structure.
* @p_av1_film_grain: Pointer to an AV1 film grain structure.
+ * @p_rect: Pointer to a rectangle.
* @p: Pointer to a compound value.
* @p_const: Pointer to a constant compound value.
*/
@@ -89,6 +90,7 @@ union v4l2_ctrl_ptr {
struct v4l2_ctrl_av1_tile_group_entry *p_av1_tile_group_entry;
struct v4l2_ctrl_av1_frame *p_av1_frame;
struct v4l2_ctrl_av1_film_grain *p_av1_film_grain;
+ struct v4l2_rect *p_rect;
void *p;
const void *p_const;
};
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index e7c4dce39007..c1c2ae150d30 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1859,6 +1859,7 @@ struct v4l2_ext_control {
__s32 __user *p_s32;
__s64 __user *p_s64;
struct v4l2_area __user *p_area;
+ struct v4l2_rect __user *p_rect;
struct v4l2_ctrl_h264_sps __user *p_h264_sps;
struct v4l2_ctrl_h264_pps __user *p_h264_pps;
struct v4l2_ctrl_h264_scaling_matrix __user *p_h264_scaling_matrix;
@@ -1929,6 +1930,7 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_U16 = 0x0101,
V4L2_CTRL_TYPE_U32 = 0x0102,
V4L2_CTRL_TYPE_AREA = 0x0106,
+ V4L2_CTRL_TYPE_RECT = 0x0107,
V4L2_CTRL_TYPE_HDR10_CLL_INFO = 0x0110,
V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY = 0x0111,
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 03/19] media: v4l2-ctrls: add support for V4L2_CTRL_WHICH_MIN/MAX_VAL
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 01/19] media: uvcvideo: Fix event flags in uvc_ctrl_send_events Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 02/19] media: v4l2_ctrl: Add V4L2_CTRL_TYPE_RECT Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 04/19] media: vivid: Add a rectangle control Ricardo Ribalda
` (16 subsequent siblings)
19 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, Yunke Cao,
Hans Verkuil
From: Hans Verkuil <hverkuil@xs4all.nl>
Add the capability of retrieving the min and max values of a
compound control.
[Ricardo: Added static to v4l2_ctrl_type_op_(maximum|minimum) proto]
[Ricardo: Fix documentation]
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Yunke Cao <yunkec@google.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
.../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 22 ++-
.../userspace-api/media/v4l/vidioc-queryctrl.rst | 9 +-
.../userspace-api/media/videodev2.h.rst.exceptions | 3 +
drivers/media/i2c/imx214.c | 4 +-
drivers/media/platform/qcom/venus/venc_ctrls.c | 9 +-
drivers/media/v4l2-core/v4l2-ctrls-api.c | 54 ++++++--
drivers/media/v4l2-core/v4l2-ctrls-core.c | 151 +++++++++++++++++----
drivers/media/v4l2-core/v4l2-ioctl.c | 4 +-
include/media/v4l2-ctrls.h | 36 ++++-
include/uapi/linux/videodev2.h | 3 +
10 files changed, 247 insertions(+), 48 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
index b74a74ac06fc..b8698b85bd80 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
@@ -338,14 +338,26 @@ still cause this situation.
- Which value of the control to get/set/try.
* - :cspan:`2` ``V4L2_CTRL_WHICH_CUR_VAL`` will return the current value of
the control, ``V4L2_CTRL_WHICH_DEF_VAL`` will return the default
- value of the control and ``V4L2_CTRL_WHICH_REQUEST_VAL`` indicates that
- these controls have to be retrieved from a request or tried/set for
- a request. In the latter case the ``request_fd`` field contains the
+ value of the control, ``V4L2_CTRL_WHICH_MIN_VAL`` will return the minimum
+ value of the control, and ``V4L2_CTRL_WHICH_MAX_VAL`` will return the maximum
+ value of the control. ``V4L2_CTRL_WHICH_REQUEST_VAL`` indicates that
+ the control value has to be retrieved from a request or tried/set for
+ a request. In that case the ``request_fd`` field contains the
file descriptor of the request that should be used. If the device
does not support requests, then ``EACCES`` will be returned.
- When using ``V4L2_CTRL_WHICH_DEF_VAL`` be aware that you can only
- get the default value of the control, you cannot set or try it.
+ When using ``V4L2_CTRL_WHICH_DEF_VAL``, ``V4L2_CTRL_WHICH_MIN_VAL``
+ or ``V4L2_CTRL_WHICH_MAX_VAL`` be aware that you can only get the
+ default/minimum/maximum value of the control, you cannot set or try it.
+
+ Whether a control supports querying the minimum and maximum values using
+ ``V4L2_CTRL_WHICH_MIN_VAL`` and ``V4L2_CTRL_WHICH_MAX_VAL`` is indicated
+ by the ``V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX`` flag. Most non-compound
+ control types support this. For controls with compound types, the
+ definition of minimum/maximum values are provided by
+ the control documentation. If a compound control does not document the
+ meaning of minimum/maximum value, then querying the minimum or maximum
+ value will result in the error code -EINVAL.
For backwards compatibility you can also use a control class here
(see :ref:`ctrl-class`). In that case all controls have to
diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
index 56d5c8b0b88b..3549417c7feb 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
@@ -447,7 +447,10 @@ See also the examples in :ref:`control`.
- n/a
- A struct :c:type:`v4l2_rect`, containing a rectangle described by
the position of its top-left corner, the width and the height. Units
- depend on the use case.
+ depend on the use case. Support for ``V4L2_CTRL_WHICH_MIN_VAL`` and
+ ``V4L2_CTRL_WHICH_MAX_VAL`` is optional and depends on the
+ ``V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX`` flag. See the documentation of
+ the specific control on how to interpret the minimum and maximum values.
* - ``V4L2_CTRL_TYPE_H264_SPS``
- n/a
- n/a
@@ -664,6 +667,10 @@ See also the examples in :ref:`control`.
``dims[0]``. So setting the control with a differently sized
array will change the ``elems`` field when the control is
queried afterwards.
+ * - ``V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX``
+ - 0x1000
+ - This control supports getting minimum and maximum values using
+ vidioc_g_ext_ctrls with V4L2_CTRL_WHICH_MIN/MAX_VAL.
Return Value
============
diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions
index 3cf1380b52b0..35d3456cc812 100644
--- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions
+++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions
@@ -396,6 +396,7 @@ replace define V4L2_CTRL_FLAG_HAS_PAYLOAD control-flags
replace define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE control-flags
replace define V4L2_CTRL_FLAG_MODIFY_LAYOUT control-flags
replace define V4L2_CTRL_FLAG_DYNAMIC_ARRAY control-flags
+replace define V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX control-flags
replace define V4L2_CTRL_FLAG_NEXT_CTRL control
replace define V4L2_CTRL_FLAG_NEXT_COMPOUND control
@@ -570,6 +571,8 @@ ignore define V4L2_CTRL_DRIVER_PRIV
ignore define V4L2_CTRL_MAX_DIMS
ignore define V4L2_CTRL_WHICH_CUR_VAL
ignore define V4L2_CTRL_WHICH_DEF_VAL
+ignore define V4L2_CTRL_WHICH_MIN_VAL
+ignore define V4L2_CTRL_WHICH_MAX_VAL
ignore define V4L2_CTRL_WHICH_REQUEST_VAL
ignore define V4L2_OUT_CAP_CUSTOM_TIMINGS
ignore define V4L2_CID_MAX_CTRLS
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 4962cfe7c83d..b0439005ec71 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -774,7 +774,9 @@ static int imx214_ctrls_init(struct imx214 *imx214)
imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
NULL,
V4L2_CID_UNIT_CELL_SIZE,
- v4l2_ctrl_ptr_create((void *)&unit_size));
+ v4l2_ctrl_ptr_create((void *)&unit_size),
+ v4l2_ctrl_ptr_create(NULL),
+ v4l2_ctrl_ptr_create(NULL));
v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx214_ctrl_ops, &props);
diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c
index 51801a962ed2..4d36c44f9d44 100644
--- a/drivers/media/platform/qcom/venus/venc_ctrls.c
+++ b/drivers/media/platform/qcom/venus/venc_ctrls.c
@@ -662,11 +662,16 @@ int venc_ctrl_init(struct venus_inst *inst)
v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_COLORIMETRY_HDR10_CLL_INFO,
- v4l2_ctrl_ptr_create(&p_hdr10_cll));
+ v4l2_ctrl_ptr_create(&p_hdr10_cll),
+ v4l2_ctrl_ptr_create(NULL),
+ v4l2_ctrl_ptr_create(NULL));
v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY,
- v4l2_ctrl_ptr_create((void *)&p_hdr10_mastering));
+ v4l2_ctrl_ptr_create((void *)&p_hdr10_mastering),
+ v4l2_ctrl_ptr_create(NULL),
+ v4l2_ctrl_ptr_create(NULL));
+
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c
index 95a2202879d8..c61f3ec09d24 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-api.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c
@@ -94,6 +94,22 @@ static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
return ptr_to_user(c, ctrl, ctrl->p_new);
}
+/* Helper function: copy the minimum control value back to the caller */
+static int min_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+ ctrl->type_ops->minimum(ctrl, 0, ctrl->p_new);
+
+ return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
+/* Helper function: copy the maximum control value back to the caller */
+static int max_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+ ctrl->type_ops->maximum(ctrl, 0, ctrl->p_new);
+
+ return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
/* Helper function: copy the caller-provider value as the new control value */
static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
{
@@ -229,8 +245,8 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
cs->error_idx = i;
if (cs->which &&
- cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
- cs->which != V4L2_CTRL_WHICH_REQUEST_VAL &&
+ (cs->which < V4L2_CTRL_WHICH_DEF_VAL ||
+ cs->which > V4L2_CTRL_WHICH_MAX_VAL) &&
V4L2_CTRL_ID2WHICH(id) != cs->which) {
dprintk(vdev,
"invalid which 0x%x or control id 0x%x\n",
@@ -259,6 +275,15 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
return -EINVAL;
}
+ if (!(ctrl->flags & V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX) &&
+ (cs->which == V4L2_CTRL_WHICH_MIN_VAL ||
+ cs->which == V4L2_CTRL_WHICH_MAX_VAL)) {
+ dprintk(vdev,
+ "invalid which 0x%x or control id 0x%x\n",
+ cs->which, id);
+ return -EINVAL;
+ }
+
if (ctrl->cluster[0]->ncontrols > 1)
have_clusters = true;
if (ctrl->cluster[0] != ctrl)
@@ -368,8 +393,8 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
*/
static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
{
- if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL ||
- which == V4L2_CTRL_WHICH_REQUEST_VAL)
+ if (which == 0 || (which >= V4L2_CTRL_WHICH_DEF_VAL &&
+ which <= V4L2_CTRL_WHICH_MAX_VAL))
return 0;
return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL;
}
@@ -389,10 +414,12 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl_helper *helpers = helper;
int ret;
int i, j;
- bool is_default, is_request;
+ bool is_default, is_request, is_min, is_max;
is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL);
is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL);
+ is_min = (cs->which == V4L2_CTRL_WHICH_MIN_VAL);
+ is_max = (cs->which == V4L2_CTRL_WHICH_MAX_VAL);
cs->error_idx = cs->count;
cs->which = V4L2_CTRL_ID2WHICH(cs->which);
@@ -432,13 +459,14 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
/*
* g_volatile_ctrl will update the new control values.
- * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and
+ * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL,
+ * V4L2_CTRL_WHICH_MIN_VAL, V4L2_CTRL_WHICH_MAX_VAL and
* V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests
* it is v4l2_ctrl_request_complete() that copies the
* volatile controls at the time of request completion
* to the request, so you don't want to do that again.
*/
- if (!is_default && !is_request &&
+ if (!is_default && !is_request && !is_min && !is_max &&
((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
(master->has_volatiles && !is_cur_manual(master)))) {
for (j = 0; j < master->ncontrols; j++)
@@ -467,6 +495,10 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
ret = -ENOMEM;
else if (is_request && ref->p_req_valid)
ret = req_to_user(cs->controls + idx, ref);
+ else if (is_min)
+ ret = min_to_user(cs->controls + idx, ref->ctrl);
+ else if (is_max)
+ ret = max_to_user(cs->controls + idx, ref->ctrl);
else if (is_volatile)
ret = new_to_user(cs->controls + idx, ref->ctrl);
else
@@ -564,9 +596,11 @@ int try_set_ext_ctrls_common(struct v4l2_fh *fh,
cs->error_idx = cs->count;
- /* Default value cannot be changed */
- if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) {
- dprintk(vdev, "%s: cannot change default value\n",
+ /* Default/minimum/maximum values cannot be changed */
+ if (cs->which == V4L2_CTRL_WHICH_DEF_VAL ||
+ cs->which == V4L2_CTRL_WHICH_MIN_VAL ||
+ cs->which == V4L2_CTRL_WHICH_MAX_VAL) {
+ dprintk(vdev, "%s: cannot change default/min/max value\n",
video_device_node_name(vdev));
return -EINVAL;
}
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 4c8744c8cd96..d510ca67e815 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -182,29 +182,66 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx,
}
}
-void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx,
+static void std_min_compound(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr)
+{
+ void *p = ptr.p + idx * ctrl->elem_size;
+
+ if (ctrl->p_min.p_const)
+ memcpy(p, ctrl->p_min.p_const, ctrl->elem_size);
+ else
+ memset(p, 0, ctrl->elem_size);
+}
+
+static void std_max_compound(const struct v4l2_ctrl *ctrl, u32 idx,
union v4l2_ctrl_ptr ptr)
+{
+ void *p = ptr.p + idx * ctrl->elem_size;
+
+ if (ctrl->p_max.p_const)
+ memcpy(p, ctrl->p_max.p_const, ctrl->elem_size);
+ else
+ memset(p, 0, ctrl->elem_size);
+}
+
+static void __v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx,
+ u32 which, union v4l2_ctrl_ptr ptr)
{
unsigned int i;
u32 tot_elems = ctrl->elems;
u32 elems = tot_elems - from_idx;
+ s64 value;
- if (from_idx >= tot_elems)
+ switch (which) {
+ case V4L2_CTRL_WHICH_DEF_VAL:
+ value = ctrl->default_value;
+ break;
+ case V4L2_CTRL_WHICH_MAX_VAL:
+ value = ctrl->maximum;
+ break;
+ case V4L2_CTRL_WHICH_MIN_VAL:
+ value = ctrl->minimum;
+ break;
+ default:
return;
+ }
switch (ctrl->type) {
case V4L2_CTRL_TYPE_STRING:
+ if (which == V4L2_CTRL_WHICH_DEF_VAL)
+ value = ctrl->minimum;
+
for (i = from_idx; i < tot_elems; i++) {
unsigned int offset = i * ctrl->elem_size;
- memset(ptr.p_char + offset, ' ', ctrl->minimum);
- ptr.p_char[offset + ctrl->minimum] = '\0';
+ memset(ptr.p_char + offset, ' ', value);
+ ptr.p_char[offset + value] = '\0';
}
break;
case V4L2_CTRL_TYPE_INTEGER64:
- if (ctrl->default_value) {
+ if (value) {
for (i = from_idx; i < tot_elems; i++)
- ptr.p_s64[i] = ctrl->default_value;
+ ptr.p_s64[i] = value;
} else {
memset(ptr.p_s64 + from_idx, 0, elems * sizeof(s64));
}
@@ -214,9 +251,9 @@ void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx,
case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_BITMASK:
case V4L2_CTRL_TYPE_BOOLEAN:
- if (ctrl->default_value) {
+ if (value) {
for (i = from_idx; i < tot_elems; i++)
- ptr.p_s32[i] = ctrl->default_value;
+ ptr.p_s32[i] = value;
} else {
memset(ptr.p_s32 + from_idx, 0, elems * sizeof(s32));
}
@@ -226,32 +263,61 @@ void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx,
memset(ptr.p_s32 + from_idx, 0, elems * sizeof(s32));
break;
case V4L2_CTRL_TYPE_U8:
- memset(ptr.p_u8 + from_idx, ctrl->default_value, elems);
+ memset(ptr.p_u8 + from_idx, value, elems);
break;
case V4L2_CTRL_TYPE_U16:
- if (ctrl->default_value) {
+ if (value) {
for (i = from_idx; i < tot_elems; i++)
- ptr.p_u16[i] = ctrl->default_value;
+ ptr.p_u16[i] = value;
} else {
memset(ptr.p_u16 + from_idx, 0, elems * sizeof(u16));
}
break;
case V4L2_CTRL_TYPE_U32:
- if (ctrl->default_value) {
+ if (value) {
for (i = from_idx; i < tot_elems; i++)
- ptr.p_u32[i] = ctrl->default_value;
+ ptr.p_u32[i] = value;
} else {
memset(ptr.p_u32 + from_idx, 0, elems * sizeof(u32));
}
break;
default:
- for (i = from_idx; i < tot_elems; i++)
- std_init_compound(ctrl, i, ptr);
+ for (i = from_idx; i < tot_elems; i++) {
+ switch (which) {
+ case V4L2_CTRL_WHICH_DEF_VAL:
+ std_init_compound(ctrl, i, ptr);
+ break;
+ case V4L2_CTRL_WHICH_MAX_VAL:
+ std_max_compound(ctrl, i, ptr);
+ break;
+ case V4L2_CTRL_WHICH_MIN_VAL:
+ std_min_compound(ctrl, i, ptr);
+ break;
+ }
+ }
break;
}
}
+
+void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx,
+ union v4l2_ctrl_ptr ptr)
+{
+ __v4l2_ctrl_type_op_init(ctrl, from_idx, V4L2_CTRL_WHICH_DEF_VAL, ptr);
+}
EXPORT_SYMBOL(v4l2_ctrl_type_op_init);
+static void v4l2_ctrl_type_op_minimum(const struct v4l2_ctrl *ctrl,
+ u32 from_idx, union v4l2_ctrl_ptr ptr)
+{
+ __v4l2_ctrl_type_op_init(ctrl, from_idx, V4L2_CTRL_WHICH_MIN_VAL, ptr);
+}
+
+static void v4l2_ctrl_type_op_maximum(const struct v4l2_ctrl *ctrl,
+ u32 from_idx, union v4l2_ctrl_ptr ptr)
+{
+ __v4l2_ctrl_type_op_init(ctrl, from_idx, V4L2_CTRL_WHICH_MAX_VAL, ptr);
+}
+
void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
{
union v4l2_ctrl_ptr ptr = ctrl->p_cur;
@@ -1296,6 +1362,8 @@ EXPORT_SYMBOL(v4l2_ctrl_type_op_validate);
static const struct v4l2_ctrl_type_ops std_type_ops = {
.equal = v4l2_ctrl_type_op_equal,
.init = v4l2_ctrl_type_op_init,
+ .minimum = v4l2_ctrl_type_op_minimum,
+ .maximum = v4l2_ctrl_type_op_maximum,
.log = v4l2_ctrl_type_op_log,
.validate = v4l2_ctrl_type_op_validate,
};
@@ -1768,7 +1836,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
s64 min, s64 max, u64 step, s64 def,
const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,
u32 flags, const char * const *qmenu,
- const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def,
+ const s64 *qmenu_int,
+ const union v4l2_ctrl_ptr p_def,
+ const union v4l2_ctrl_ptr p_min,
+ const union v4l2_ctrl_ptr p_max,
void *priv)
{
struct v4l2_ctrl *ctrl;
@@ -1892,6 +1963,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
break;
}
+ if (type < V4L2_CTRL_COMPOUND_TYPES &&
+ type != V4L2_CTRL_TYPE_BUTTON &&
+ type != V4L2_CTRL_TYPE_CTRL_CLASS &&
+ type != V4L2_CTRL_TYPE_STRING)
+ flags |= V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX;
+
/* Sanity checks */
if (id == 0 || name == NULL || !elem_size ||
id >= V4L2_CID_PRIVATE_BASE ||
@@ -1900,6 +1977,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
handler_set_err(hdl, -ERANGE);
return NULL;
}
+
err = check_range(type, min, max, step, def);
if (err) {
handler_set_err(hdl, err);
@@ -1941,6 +2019,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const)
sz_extra += elem_size;
+ if (type >= V4L2_CTRL_COMPOUND_TYPES && p_min.p_const)
+ sz_extra += elem_size;
+ if (type >= V4L2_CTRL_COMPOUND_TYPES && p_max.p_const)
+ sz_extra += elem_size;
ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
if (ctrl == NULL) {
@@ -2006,6 +2088,22 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
memcpy(ctrl->p_def.p, p_def.p_const, elem_size);
}
+ if (flags & V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX) {
+ void *ptr = ctrl->p_def.p;
+
+ if (p_min.p_const) {
+ ptr += elem_size;
+ ctrl->p_min.p = ptr;
+ memcpy(ctrl->p_min.p, p_min.p_const, elem_size);
+ }
+
+ if (p_max.p_const) {
+ ptr += elem_size;
+ ctrl->p_max.p = ptr;
+ memcpy(ctrl->p_max.p, p_max.p_const, elem_size);
+ }
+ }
+
ctrl->type_ops->init(ctrl, 0, ctrl->p_cur);
cur_to_new(ctrl);
@@ -2056,7 +2154,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
type, min, max,
is_menu ? cfg->menu_skip_mask : step, def,
cfg->dims, cfg->elem_size,
- flags, qmenu, qmenu_int, cfg->p_def, priv);
+ flags, qmenu, qmenu_int, cfg->p_def, cfg->p_min,
+ cfg->p_max, priv);
if (ctrl)
ctrl->is_private = cfg->is_private;
return ctrl;
@@ -2081,7 +2180,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
}
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
min, max, step, def, NULL, 0,
- flags, NULL, NULL, ptr_null, NULL);
+ flags, NULL, NULL, ptr_null, ptr_null,
+ ptr_null, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_std);
@@ -2114,7 +2214,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
}
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
0, max, mask, def, NULL, 0,
- flags, qmenu, qmenu_int, ptr_null, NULL);
+ flags, qmenu, qmenu_int, ptr_null, ptr_null,
+ ptr_null, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
@@ -2146,7 +2247,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
}
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
0, max, mask, def, NULL, 0,
- flags, qmenu, NULL, ptr_null, NULL);
+ flags, qmenu, NULL, ptr_null, ptr_null,
+ ptr_null, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
@@ -2154,7 +2256,9 @@ EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
/* Helper function for standard compound controls */
struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops, u32 id,
- const union v4l2_ctrl_ptr p_def)
+ const union v4l2_ctrl_ptr p_def,
+ const union v4l2_ctrl_ptr p_min,
+ const union v4l2_ctrl_ptr p_max)
{
const char *name;
enum v4l2_ctrl_type type;
@@ -2168,7 +2272,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
}
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
min, max, step, def, NULL, 0,
- flags, NULL, NULL, p_def, NULL);
+ flags, NULL, NULL, p_def, p_min, p_max, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_std_compound);
@@ -2192,7 +2296,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
}
return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
0, max, 0, def, NULL, 0,
- flags, NULL, qmenu_int, ptr_null, NULL);
+ flags, NULL, qmenu_int, ptr_null, ptr_null,
+ ptr_null, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 0304daa8471d..bfdba96e938c 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -893,7 +893,9 @@ static bool check_ext_ctrls(struct v4l2_ext_controls *c, unsigned long ioctl)
return false;
break;
case V4L2_CTRL_WHICH_DEF_VAL:
- /* Default value cannot be changed */
+ case V4L2_CTRL_WHICH_MIN_VAL:
+ case V4L2_CTRL_WHICH_MAX_VAL:
+ /* Default, minimum or maximum value cannot be changed */
if (ioctl == VIDIOC_S_EXT_CTRLS ||
ioctl == VIDIOC_TRY_EXT_CTRLS) {
c->error_idx = c->count;
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index b0db167a3ac4..9ed7be1e696f 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -133,6 +133,8 @@ struct v4l2_ctrl_ops {
*
* @equal: return true if all ctrl->elems array elements are equal.
* @init: initialize the value for array elements from from_idx to ctrl->elems.
+ * @minimum: set the value to the minimum value of the control.
+ * @maximum: set the value to the maximum value of the control.
* @log: log the value.
* @validate: validate the value for ctrl->new_elems array elements.
* Return 0 on success and a negative value otherwise.
@@ -142,6 +144,10 @@ struct v4l2_ctrl_type_ops {
union v4l2_ctrl_ptr ptr1, union v4l2_ctrl_ptr ptr2);
void (*init)(const struct v4l2_ctrl *ctrl, u32 from_idx,
union v4l2_ctrl_ptr ptr);
+ void (*minimum)(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr);
+ void (*maximum)(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr);
void (*log)(const struct v4l2_ctrl *ctrl);
int (*validate)(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr);
};
@@ -247,6 +253,12 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
* @p_def: The control's default value represented via a union which
* provides a standard way of accessing control types
* through a pointer (for compound controls only).
+ * @p_min: The control's minimum value represented via a union which
+ * provides a standard way of accessing control types
+ * through a pointer (for compound controls only).
+ * @p_max: The control's maximum value represented via a union which
+ * provides a standard way of accessing control types
+ * through a pointer (for compound controls only).
* @p_cur: The control's current value represented via a union which
* provides a standard way of accessing control types
* through a pointer.
@@ -306,6 +318,8 @@ struct v4l2_ctrl {
} cur;
union v4l2_ctrl_ptr p_def;
+ union v4l2_ctrl_ptr p_min;
+ union v4l2_ctrl_ptr p_max;
union v4l2_ctrl_ptr p_new;
union v4l2_ctrl_ptr p_cur;
};
@@ -425,6 +439,8 @@ struct v4l2_ctrl_handler {
* @step: The control's step value for non-menu controls.
* @def: The control's default value.
* @p_def: The control's default value for compound controls.
+ * @p_min: The control's minimum value for compound controls.
+ * @p_max: The control's maximum value for compound controls.
* @dims: The size of each dimension.
* @elem_size: The size in bytes of the control.
* @flags: The control's flags.
@@ -454,6 +470,8 @@ struct v4l2_ctrl_config {
u64 step;
s64 def;
union v4l2_ctrl_ptr p_def;
+ union v4l2_ctrl_ptr p_min;
+ union v4l2_ctrl_ptr p_max;
u32 dims[V4L2_CTRL_MAX_DIMS];
u32 elem_size;
u32 flags;
@@ -723,17 +741,25 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
* @ops: The control ops.
* @id: The control ID.
* @p_def: The control's default value.
+ * @p_min: The control's minimum value.
+ * @p_max: The control's maximum value.
*
- * Sames as v4l2_ctrl_new_std(), but with support to compound controls, thanks
- * to the @p_def field. Use v4l2_ctrl_ptr_create() to create @p_def from a
- * pointer. Use v4l2_ctrl_ptr_create(NULL) if the default value of the
- * compound control should be all zeroes.
+ * Same as v4l2_ctrl_new_std(), but with support for compound controls.
+ * To fill in the @p_def, @p_min and @p_max fields, use v4l2_ctrl_ptr_create()
+ * to convert a pointer to a const union v4l2_ctrl_ptr.
+ * Use v4l2_ctrl_ptr_create(NULL) if you want the default, minimum or maximum
+ * value of the compound control to be all zeroes.
+ * If the compound control does not set the ``V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX``
+ * flag, then it does not has minimum and maximum values. In that case just use
+ * v4l2_ctrl_ptr_create(NULL) for the @p_min and @p_max arguments.
*
*/
struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops,
u32 id,
- const union v4l2_ctrl_ptr p_def);
+ const union v4l2_ctrl_ptr p_def,
+ const union v4l2_ctrl_ptr p_min,
+ const union v4l2_ctrl_ptr p_max);
/**
* v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control.
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index c1c2ae150d30..c8cb2796130f 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1912,6 +1912,8 @@ struct v4l2_ext_controls {
#define V4L2_CTRL_WHICH_CUR_VAL 0
#define V4L2_CTRL_WHICH_DEF_VAL 0x0f000000
#define V4L2_CTRL_WHICH_REQUEST_VAL 0x0f010000
+#define V4L2_CTRL_WHICH_MIN_VAL 0x0f020000
+#define V4L2_CTRL_WHICH_MAX_VAL 0x0f030000
enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_INTEGER = 1,
@@ -2019,6 +2021,7 @@ struct v4l2_querymenu {
#define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE 0x0200
#define V4L2_CTRL_FLAG_MODIFY_LAYOUT 0x0400
#define V4L2_CTRL_FLAG_DYNAMIC_ARRAY 0x0800
+#define V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX 0x1000
/* Query flags, to be ORed with the control ID */
#define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 04/19] media: vivid: Add a rectangle control
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (2 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 03/19] media: v4l2-ctrls: add support for V4L2_CTRL_WHICH_MIN/MAX_VAL Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 05/19] media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value Ricardo Ribalda
` (15 subsequent siblings)
19 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, Yunke Cao,
Hans Verkuil
From: Yunke Cao <yunkec@google.com>
This control represents a generic read/write rectangle.
It supports V4L2_CTRL_WHICH_MIN/MAX_VAL.
Signed-off-by: Yunke Cao <yunkec@google.com>
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/test-drivers/vivid/vivid-ctrls.c | 34 ++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c
index 2b5c8fbcd0a2..57346b714534 100644
--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c
+++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c
@@ -37,6 +37,7 @@
#define VIVID_CID_U8_PIXEL_ARRAY (VIVID_CID_CUSTOM_BASE + 14)
#define VIVID_CID_S32_ARRAY (VIVID_CID_CUSTOM_BASE + 15)
#define VIVID_CID_S64_ARRAY (VIVID_CID_CUSTOM_BASE + 16)
+#define VIVID_CID_RECT (VIVID_CID_CUSTOM_BASE + 17)
#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000)
#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1)
@@ -360,6 +361,38 @@ static const struct v4l2_ctrl_config vivid_ctrl_ro_int32 = {
.step = 1,
};
+static const struct v4l2_rect rect_def = {
+ .top = 100,
+ .left = 200,
+ .width = 300,
+ .height = 400,
+};
+
+static const struct v4l2_rect rect_min = {
+ .top = 0,
+ .left = 0,
+ .width = 1,
+ .height = 1,
+};
+
+static const struct v4l2_rect rect_max = {
+ .top = 0,
+ .left = 0,
+ .width = 1000,
+ .height = 2000,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_rect = {
+ .ops = &vivid_user_gen_ctrl_ops,
+ .id = VIVID_CID_RECT,
+ .name = "Rect",
+ .type = V4L2_CTRL_TYPE_RECT,
+ .flags = V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX,
+ .p_def.p_const = &rect_def,
+ .p_min.p_const = &rect_min,
+ .p_max.p_const = &rect_max,
+};
+
/* Framebuffer Controls */
static int vivid_fb_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -1685,6 +1718,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL);
dev->ro_int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_ro_int32, NULL);
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL);
+ v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_rect, NULL);
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL);
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_dyn_array, NULL);
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL);
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 05/19] media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (3 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 04/19] media: vivid: Add a rectangle control Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-25 15:50 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 06/19] media: uvcvideo: Handle uvc menu translation inside uvc_set_le_value Ricardo Ribalda
` (14 subsequent siblings)
19 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
map->get() gets a value from an uvc_control in "UVC format" and converts
it to a value that can be consumed by v4l2.
Instead of using a special get function for V4L2_CTRL_TYPE_MENU, we
were converting from uvc_get_le_value in two different places.
Move the conversion to uvc_get_le_value().
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 77 +++++++++++++++++-----------------------
1 file changed, 32 insertions(+), 45 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index bab9fdac98e6..77f7058ec966 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -862,6 +862,25 @@ static inline void uvc_clear_bit(u8 *data, int bit)
data[bit >> 3] &= ~(1 << (bit & 7));
}
+static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val)
+{
+ unsigned int i;
+
+ for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
+ u32 menu_value;
+
+ if (!test_bit(i, &mapping->menu_mask))
+ continue;
+
+ menu_value = uvc_mapping_get_menu_value(mapping, i);
+
+ if (menu_value == val)
+ return i;
+ }
+
+ return val;
+}
+
/*
* Extract the bit string specified by mapping->offset and mapping->size
* from the little-endian data stored at 'data' and return the result as
@@ -896,6 +915,16 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
value |= -(value & (1 << (mapping->size - 1)));
+ /* If it is a menu, convert from uvc to v4l2. */
+ if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
+ return value;
+
+ switch (query) {
+ case UVC_GET_CUR:
+ case UVC_GET_DEF:
+ return uvc_menu_to_v4l2_menu(mapping, value);
+ }
+
return value;
}
@@ -1060,32 +1089,6 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
return 0;
}
-static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping,
- const u8 *data)
-{
- s32 value = mapping->get(mapping, UVC_GET_CUR, data);
-
- if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
- unsigned int i;
-
- for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
- u32 menu_value;
-
- if (!test_bit(i, &mapping->menu_mask))
- continue;
-
- menu_value = uvc_mapping_get_menu_value(mapping, i);
-
- if (menu_value == value) {
- value = i;
- break;
- }
- }
- }
-
- return value;
-}
-
static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
struct uvc_control *ctrl)
{
@@ -1136,8 +1139,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
if (ret < 0)
return ret;
- *value = __uvc_ctrl_get_value(mapping,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+ *value = mapping->get(mapping, UVC_GET_CUR,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
return 0;
}
@@ -1287,7 +1290,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
{
struct uvc_control_mapping *master_map = NULL;
struct uvc_control *master_ctrl = NULL;
- unsigned int i;
memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
v4l2_ctrl->id = mapping->id;
@@ -1330,21 +1332,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1;
v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1;
v4l2_ctrl->step = 1;
-
- for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
- u32 menu_value;
-
- if (!test_bit(i, &mapping->menu_mask))
- continue;
-
- menu_value = uvc_mapping_get_menu_value(mapping, i);
-
- if (menu_value == v4l2_ctrl->default_value) {
- v4l2_ctrl->default_value = i;
- break;
- }
- }
-
return 0;
case V4L2_CTRL_TYPE_BOOLEAN:
@@ -1592,7 +1579,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
ctrl->handle = NULL;
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
- s32 value = __uvc_ctrl_get_value(mapping, data);
+ s32 value = mapping->get(mapping, UVC_GET_CUR, data);
/*
* handle may be NULL here if the device sends auto-update
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 06/19] media: uvcvideo: Handle uvc menu translation inside uvc_set_le_value
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (4 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 05/19] media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-25 15:58 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 07/19] media: uvcvideo: refactor uvc_ioctl_g_ext_ctrls Ricardo Ribalda
` (13 subsequent siblings)
19 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
Be consistent with uvc_get_le_value() and do the menu translation there.
Note that in this case, the refactor does not provide much... but
consistency is a nice feature.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 77f7058ec966..c975e0ab479b 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -939,6 +939,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
int offset = mapping->offset;
u8 mask;
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU)
+ value = uvc_mapping_get_menu_value(mapping, value);
/*
* According to the v4l2 spec, writing any value to a button control
* should result in the action belonging to the button control being
@@ -1988,23 +1990,23 @@ int uvc_ctrl_set(struct uvc_fh *handle,
if (!test_bit(xctrl->value, &mapping->menu_mask))
return -EINVAL;
- value = uvc_mapping_get_menu_value(mapping, xctrl->value);
-
/*
* Valid menu indices are reported by the GET_RES request for
* UVC controls that support it.
*/
if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) {
+ int val = uvc_mapping_get_menu_value(mapping,
+ xctrl->value);
if (!ctrl->cached) {
ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
return ret;
}
- if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & value))
+ if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & val))
return -EINVAL;
}
-
+ value = xctrl->value;
break;
default:
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 07/19] media: uvcvideo: refactor uvc_ioctl_g_ext_ctrls
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (5 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 06/19] media: uvcvideo: Handle uvc menu translation inside uvc_set_le_value Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-25 16:01 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 08/19] media: uvcvideo: uvc_ioctl_(g|s)_ext_ctrls: handle NoP case Ricardo Ribalda
` (12 subsequent siblings)
19 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
We want to support fetching the min and max values with g_ext_ctrls,
this patch is a preparation for that.
Instead of abusing uvc_query_v4l2_ctrl(), add an extra parameter to
uvc_ctrl_get, so it can support fetching the default value.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 21 ++++++++++++++++++---
drivers/media/usb/uvc/uvc_v4l2.c | 28 +++++++++++-----------------
drivers/media/usb/uvc/uvcvideo.h | 3 ++-
3 files changed, 31 insertions(+), 21 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index c975e0ab479b..d6afa131a5e1 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1902,8 +1902,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
return ret;
}
-int uvc_ctrl_get(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl)
+int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
+ struct v4l2_ext_control *xctrl)
{
struct uvc_control *ctrl;
struct uvc_control_mapping *mapping;
@@ -1915,7 +1915,22 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
if (ctrl == NULL)
return -EINVAL;
- return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
+ switch (which) {
+ case V4L2_CTRL_WHICH_CUR_VAL:
+ return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
+ case V4L2_CTRL_WHICH_DEF_VAL:
+ if (!ctrl->cached) {
+ int ret = uvc_ctrl_populate_cache(chain, ctrl);
+
+ if (ret < 0)
+ return ret;
+ }
+ xctrl->value = mapping->get(mapping, UVC_GET_DEF,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
+ return 0;
+ }
+
+ return -EINVAL;
}
int uvc_ctrl_set(struct uvc_fh *handle,
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 97c5407f6603..02fd5cbc3474 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1078,34 +1078,28 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
struct uvc_video_chain *chain = handle->chain;
struct v4l2_ext_control *ctrl = ctrls->controls;
unsigned int i;
+ u32 which;
int ret;
+ switch (ctrls->which) {
+ case V4L2_CTRL_WHICH_DEF_VAL:
+ case V4L2_CTRL_WHICH_CUR_VAL:
+ which = ctrls->which;
+ break;
+ default:
+ which = V4L2_CTRL_WHICH_CUR_VAL;
+ }
+
ret = uvc_ctrl_check_access(chain, ctrls, VIDIOC_G_EXT_CTRLS);
if (ret < 0)
return ret;
- if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
- for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- struct v4l2_queryctrl qc = { .id = ctrl->id };
-
- ret = uvc_query_v4l2_ctrl(chain, &qc);
- if (ret < 0) {
- ctrls->error_idx = i;
- return ret;
- }
-
- ctrl->value = qc.default_value;
- }
-
- return 0;
- }
-
ret = uvc_ctrl_begin(chain);
if (ret < 0)
return ret;
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- ret = uvc_ctrl_get(chain, ctrl);
+ ret = uvc_ctrl_get(chain, which, ctrl);
if (ret < 0) {
uvc_ctrl_rollback(handle);
ctrls->error_idx = i;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 07f9921d83f2..6ebaabd11443 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -788,7 +788,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
return __uvc_ctrl_commit(handle, 1, NULL);
}
-int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
+int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
+ struct v4l2_ext_control *xctrl);
int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
const struct v4l2_ext_controls *ctrls,
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 08/19] media: uvcvideo: uvc_ioctl_(g|s)_ext_ctrls: handle NoP case
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (6 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 07/19] media: uvcvideo: refactor uvc_ioctl_g_ext_ctrls Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-25 16:01 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 09/19] media: uvcvideo: Support any size for mapping get/set Ricardo Ribalda
` (11 subsequent siblings)
19 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
If nothing needs to be done. Exit early.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_v4l2.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 02fd5cbc3474..65dbb53b1e75 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1081,6 +1081,9 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
u32 which;
int ret;
+ if (!ctrls->count)
+ return 0;
+
switch (ctrls->which) {
case V4L2_CTRL_WHICH_DEF_VAL:
case V4L2_CTRL_WHICH_CUR_VAL:
@@ -1121,6 +1124,9 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
unsigned int i;
int ret;
+ if (!ctrls->count)
+ return 0;
+
ret = uvc_ctrl_check_access(chain, ctrls, ioctl);
if (ret < 0)
return ret;
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 09/19] media: uvcvideo: Support any size for mapping get/set
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (7 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 08/19] media: uvcvideo: uvc_ioctl_(g|s)_ext_ctrls: handle NoP case Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 8:56 ` Yunke Cao
2024-12-09 12:49 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 10/19] media: uvcvideo: Factor out clamping from uvc_ctrl_set Ricardo Ribalda
` (10 subsequent siblings)
19 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
Right now, we only support mappings for v4l2 controls with a max size of
s32. This patch modifies the prototype of get/set so it can support any
size.
This is done to prepare for compound controls.
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 183 +++++++++++++++++++++++++++------------
drivers/media/usb/uvc/uvcvideo.h | 8 +-
2 files changed, 130 insertions(+), 61 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index d6afa131a5e1..6d5167eb368d 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -367,6 +367,22 @@ static const u32 uvc_control_classes[] = {
static const int exposure_auto_mapping[] = { 2, 1, 4, 8 };
+static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping,
+ u8 query, const void *data_in)
+{
+ s32 data_out;
+
+ mapping->get(mapping, query, data_in, sizeof(data_out), &data_out);
+
+ return data_out;
+}
+
+static void uvc_mapping_set_s32(struct uvc_control_mapping *mapping,
+ s32 data_in, void *data_out)
+{
+ mapping->set(mapping, sizeof(data_in), &data_in, data_out);
+}
+
/*
* This function translates the V4L2 menu index @idx, as exposed to userspace as
* the V4L2 control value, to the corresponding UVC control value used by the
@@ -405,58 +421,93 @@ uvc_mapping_get_menu_name(const struct uvc_control_mapping *mapping, u32 idx)
return v4l2_ctrl_get_menu(mapping->id)[idx];
}
-static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
- u8 query, const u8 *data)
+static int uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query,
+ const void *uvc_in, size_t v4l2_size,
+ void *v4l2_out)
{
- s8 zoom = (s8)data[0];
+ u8 value = ((u8 *)uvc_in)[2];
+ s8 sign = ((s8 *)uvc_in)[0];
+ s32 *out = v4l2_out;
+
+ if (WARN_ON(v4l2_size != sizeof(s32)))
+ return -EINVAL;
switch (query) {
case UVC_GET_CUR:
- return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
+ *out = (sign == 0) ? 0 : (sign > 0 ? value : -value);
+ return 0;
case UVC_GET_MIN:
case UVC_GET_MAX:
case UVC_GET_RES:
case UVC_GET_DEF:
default:
- return data[2];
+ *out = value;
+ return 0;
}
}
-static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
- s32 value, u8 *data)
+static int uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
+ size_t v4l2_size, const void *v4l2_in,
+ void *uvc_out)
{
- data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
- data[2] = min((int)abs(value), 0xff);
+ u8 *out = uvc_out;
+ s32 value;
+
+ if (WARN_ON(v4l2_size != sizeof(s32)))
+ return -EINVAL;
+
+ value = *(u32 *)v4l2_in;
+ out[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
+ out[2] = min_t(int, abs(value), 0xff);
+
+ return 0;
}
-static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
- u8 query, const u8 *data)
+static int uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
+ u8 query, const void *uvc_in,
+ size_t v4l2_size, void *v4l2_out)
{
unsigned int first = mapping->offset / 8;
- s8 rel = (s8)data[first];
+ u8 value = ((u8 *)uvc_in)[first + 1];
+ s8 sign = ((s8 *)uvc_in)[first];
+ s32 *out = v4l2_out;
+
+ if (WARN_ON(v4l2_size != sizeof(s32)))
+ return -EINVAL;
switch (query) {
case UVC_GET_CUR:
- return (rel == 0) ? 0 : (rel > 0 ? data[first+1]
- : -data[first+1]);
+ *out = (sign == 0) ? 0 : (sign > 0 ? value : -value);
+ return 0;
case UVC_GET_MIN:
- return -data[first+1];
+ *out = -value;
+ return 0;
case UVC_GET_MAX:
case UVC_GET_RES:
case UVC_GET_DEF:
default:
- return data[first+1];
+ *out = value;
+ return 0;
}
}
-static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
- s32 value, u8 *data)
+static int uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
+ size_t v4l2_size, const void *v4l2_in,
+ void *uvc_out)
{
unsigned int first = mapping->offset / 8;
+ u8 *out = uvc_out;
+ s32 value;
+
+ if (WARN_ON(v4l2_size != sizeof(s32)))
+ return -EINVAL;
- data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
- data[first+1] = min_t(int, abs(value), 0xff);
+ value = *(u32 *)v4l2_in;
+ out[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
+ out[first + 1] = min_t(int, abs(value), 0xff);
+
+ return 0;
}
static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
@@ -887,14 +938,20 @@ static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val)
* a signed 32bit integer. Sign extension will be performed if the mapping
* references a signed data type.
*/
-static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
- u8 query, const u8 *data)
+static int uvc_get_le_value(struct uvc_control_mapping *mapping,
+ u8 query, const void *uvc_in, size_t v4l2_size,
+ void *v4l2_out)
{
- int bits = mapping->size;
int offset = mapping->offset;
+ int bits = mapping->size;
+ const u8 *data = uvc_in;
+ s32 *out = v4l2_out;
s32 value = 0;
u8 mask;
+ if (WARN_ON(v4l2_size != sizeof(s32)))
+ return -EINVAL;
+
data += offset / 8;
offset &= 7;
mask = ((1LL << bits) - 1) << offset;
@@ -916,29 +973,40 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
value |= -(value & (1 << (mapping->size - 1)));
/* If it is a menu, convert from uvc to v4l2. */
- if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
- return value;
+ if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
+ *out = value;
+ return 0;
+ }
switch (query) {
case UVC_GET_CUR:
case UVC_GET_DEF:
- return uvc_menu_to_v4l2_menu(mapping, value);
+ *out = uvc_menu_to_v4l2_menu(mapping, value);
+ return 0;
}
- return value;
+ *out = value;
+ return 0;
}
/*
* Set the bit string specified by mapping->offset and mapping->size
* in the little-endian data stored at 'data' to the value 'value'.
*/
-static void uvc_set_le_value(struct uvc_control_mapping *mapping,
- s32 value, u8 *data)
+static int uvc_set_le_value(struct uvc_control_mapping *mapping,
+ size_t v4l2_size, const void *v4l2_in,
+ void *uvc_out)
{
- int bits = mapping->size;
int offset = mapping->offset;
+ int bits = mapping->size;
+ u8 *data = uvc_out;
+ s32 value;
u8 mask;
+ if (WARN_ON(v4l2_size != sizeof(s32)))
+ return -EINVAL;
+
+ value = *(s32 *)v4l2_in;
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU)
value = uvc_mapping_get_menu_value(mapping, value);
/*
@@ -960,6 +1028,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
bits -= 8 - offset;
offset = 0;
}
+
+ return 0;
}
/* ------------------------------------------------------------------------
@@ -1141,8 +1211,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
if (ret < 0)
return ret;
- *value = mapping->get(mapping, UVC_GET_CUR,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+ *value = uvc_mapping_get_s32(mapping, UVC_GET_CUR,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
return 0;
}
@@ -1275,12 +1345,12 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
* as supported.
*/
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
- return mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ return uvc_mapping_get_s32(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
- return mapping->get(mapping, UVC_GET_MAX,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+ return uvc_mapping_get_s32(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
return ~0;
}
@@ -1324,10 +1394,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
return ret;
}
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
- v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
- }
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF)
+ v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping,
+ UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
switch (mapping->v4l2_type) {
case V4L2_CTRL_TYPE_MENU:
@@ -1359,16 +1428,16 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
}
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
- v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
+ v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
- v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+ v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
- v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
return 0;
}
@@ -1581,7 +1650,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
ctrl->handle = NULL;
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
- s32 value = mapping->get(mapping, UVC_GET_CUR, data);
+ s32 value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data);
/*
* handle may be NULL here if the device sends auto-update
@@ -1925,8 +1994,8 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
if (ret < 0)
return ret;
}
- xctrl->value = mapping->get(mapping, UVC_GET_DEF,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
+ xctrl->value = uvc_mapping_get_s32(mapping, UVC_GET_DEF,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
return 0;
}
@@ -1963,12 +2032,12 @@ int uvc_ctrl_set(struct uvc_fh *handle,
return ret;
}
- min = mapping->get(mapping, UVC_GET_MIN,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- max = mapping->get(mapping, UVC_GET_MAX,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
- step = mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ min = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
+ max = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+ step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
if (step == 0)
step = 1;
@@ -2047,8 +2116,8 @@ int uvc_ctrl_set(struct uvc_fh *handle,
ctrl->info.size);
}
- mapping->set(mapping, value,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+ uvc_mapping_set_s32(mapping, value,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
ctrl->handle = handle;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 6ebaabd11443..3d32a56c5ff8 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -131,10 +131,10 @@ struct uvc_control_mapping {
const struct uvc_control_mapping *(*filter_mapping)
(struct uvc_video_chain *chain,
struct uvc_control *ctrl);
- s32 (*get)(struct uvc_control_mapping *mapping, u8 query,
- const u8 *data);
- void (*set)(struct uvc_control_mapping *mapping, s32 value,
- u8 *data);
+ int (*get)(struct uvc_control_mapping *mapping, u8 query,
+ const void *uvc_in, size_t v4l2_size, void *v4l2_out);
+ int (*set)(struct uvc_control_mapping *mapping, size_t v4l2_size,
+ const void *v4l2_in, void *uvc_out);
};
struct uvc_control {
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 10/19] media: uvcvideo: Factor out clamping from uvc_ctrl_set
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (8 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 09/19] media: uvcvideo: Support any size for mapping get/set Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
2024-12-09 12:57 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 11/19] media: uvcvideo: add support for compound controls Ricardo Ribalda
` (9 subsequent siblings)
19 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
Move the logic to a separated function. Do not expect any change.
This is a preparation for supporting compound controls.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 82 +++++++++++++++++++++-------------------
1 file changed, 44 insertions(+), 38 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 6d5167eb368d..893d12cd3f90 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2002,28 +2002,17 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
return -EINVAL;
}
-int uvc_ctrl_set(struct uvc_fh *handle,
- struct v4l2_ext_control *xctrl)
+static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ s32 *value_in_out)
{
- struct uvc_video_chain *chain = handle->chain;
- struct uvc_control *ctrl;
- struct uvc_control_mapping *mapping;
- s32 value;
+ s32 value = *value_in_out;
u32 step;
s32 min;
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;
- if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
- return -EACCES;
-
- /* Clamp out of range values. */
switch (mapping->v4l2_type) {
case V4L2_CTRL_TYPE_INTEGER:
if (!ctrl->cached) {
@@ -2041,14 +2030,13 @@ int uvc_ctrl_set(struct uvc_fh *handle,
if (step == 0)
step = 1;
- xctrl->value = min + DIV_ROUND_CLOSEST((u32)(xctrl->value - min),
- step) * step;
+ value = min + DIV_ROUND_CLOSEST((u32)(value - min), step) * step;
if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
- xctrl->value = clamp(xctrl->value, min, max);
+ value = clamp(value, min, max);
else
- xctrl->value = clamp_t(u32, xctrl->value, min, max);
- value = xctrl->value;
- break;
+ value = clamp_t(u32, value, min, max);
+ *value_in_out = value;
+ return 0;
case V4L2_CTRL_TYPE_BITMASK:
if (!ctrl->cached) {
@@ -2057,21 +2045,20 @@ int uvc_ctrl_set(struct uvc_fh *handle,
return ret;
}
- xctrl->value &= uvc_get_ctrl_bitmap(ctrl, mapping);
- value = xctrl->value;
- break;
+ value &= uvc_get_ctrl_bitmap(ctrl, mapping);
+ *value_in_out = value;
+ return 0;
case V4L2_CTRL_TYPE_BOOLEAN:
- xctrl->value = clamp(xctrl->value, 0, 1);
- value = xctrl->value;
- break;
+ *value_in_out = clamp(value, 0, 1);
+ return 0;
case V4L2_CTRL_TYPE_MENU:
- if (xctrl->value < (ffs(mapping->menu_mask) - 1) ||
- xctrl->value > (fls(mapping->menu_mask) - 1))
+ if (value < (ffs(mapping->menu_mask) - 1) ||
+ value > (fls(mapping->menu_mask) - 1))
return -ERANGE;
- if (!test_bit(xctrl->value, &mapping->menu_mask))
+ if (!test_bit(value, &mapping->menu_mask))
return -EINVAL;
/*
@@ -2079,8 +2066,7 @@ int uvc_ctrl_set(struct uvc_fh *handle,
* UVC controls that support it.
*/
if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) {
- int val = uvc_mapping_get_menu_value(mapping,
- xctrl->value);
+ int val = uvc_mapping_get_menu_value(mapping, value);
if (!ctrl->cached) {
ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
@@ -2090,14 +2076,34 @@ int uvc_ctrl_set(struct uvc_fh *handle,
if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & val))
return -EINVAL;
}
- value = xctrl->value;
- break;
+ return 0;
default:
- value = xctrl->value;
- break;
+ return 0;
}
+ return 0;
+}
+
+int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
+{
+ struct uvc_video_chain *chain = handle->chain;
+ struct uvc_control_mapping *mapping;
+ struct uvc_control *ctrl;
+ int ret;
+
+ if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
+ return -EACCES;
+
+ ctrl = uvc_find_control(chain, xctrl->id, &mapping);
+ if (!ctrl)
+ return -EINVAL;
+ if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
+ return -EACCES;
+
+ ret = uvc_ctrl_clamp(chain, ctrl, mapping, &xctrl->value);
+ if (ret)
+ return ret;
/*
* If the mapping doesn't span the whole UVC control, the current value
* needs to be loaded from the device to perform the read-modify-write
@@ -2116,7 +2122,7 @@ int uvc_ctrl_set(struct uvc_fh *handle,
ctrl->info.size);
}
- uvc_mapping_set_s32(mapping, value,
+ uvc_mapping_set_s32(mapping, xctrl->value,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 11/19] media: uvcvideo: add support for compound controls
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (9 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 10/19] media: uvcvideo: Factor out clamping from uvc_ctrl_set Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 13:35 ` Hans de Goede
2024-12-09 13:58 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 12/19] media: uvcvideo: Factor out query_boundaries from query_ctrl Ricardo Ribalda
` (8 subsequent siblings)
19 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, Yunke Cao
From: Yunke Cao <yunkec@google.com>
This patch adds support for compound controls. This is required to
support controls that cannot be represented with a s64 data, such as the
Region of Interest.
Signed-off-by: Yunke Cao <yunkec@google.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 224 ++++++++++++++++++++++++++++++++-------
drivers/media/usb/uvc/uvcvideo.h | 5 +
2 files changed, 192 insertions(+), 37 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 893d12cd3f90..e51cd0a2228a 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -367,6 +367,11 @@ static const u32 uvc_control_classes[] = {
static const int exposure_auto_mapping[] = { 2, 1, 4, 8 };
+static bool uvc_ctrl_mapping_is_compound(struct uvc_control_mapping *mapping)
+{
+ return mapping->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES;
+}
+
static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping,
u8 query, const void *data_in)
{
@@ -1048,7 +1053,7 @@ static int uvc_entity_match_guid(const struct uvc_entity *entity,
static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id,
struct uvc_control_mapping **mapping, struct uvc_control **control,
- int next)
+ int next, int next_compound)
{
struct uvc_control *ctrl;
struct uvc_control_mapping *map;
@@ -1063,14 +1068,16 @@ static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id,
continue;
list_for_each_entry(map, &ctrl->info.mappings, list) {
- if ((map->id == v4l2_id) && !next) {
+ if (map->id == v4l2_id && !next && !next_compound) {
*control = ctrl;
*mapping = map;
return;
}
if ((*mapping == NULL || (*mapping)->id > map->id) &&
- (map->id > v4l2_id) && next) {
+ (map->id > v4l2_id) &&
+ (uvc_ctrl_mapping_is_compound(map) ?
+ next_compound : next)) {
*control = ctrl;
*mapping = map;
}
@@ -1084,6 +1091,7 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
struct uvc_control *ctrl = NULL;
struct uvc_entity *entity;
int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;
+ int next_compound = v4l2_id & V4L2_CTRL_FLAG_NEXT_COMPOUND;
*mapping = NULL;
@@ -1092,12 +1100,13 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
/* Find the control. */
list_for_each_entry(entity, &chain->entities, chain) {
- __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
- if (ctrl && !next)
+ __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next,
+ next_compound);
+ if (ctrl && !next && !next_compound)
return ctrl;
}
- if (ctrl == NULL && !next)
+ if (!ctrl && !next && !next_compound)
uvc_dbg(chain->dev, CONTROL, "Control 0x%08x not found\n",
v4l2_id);
@@ -1220,7 +1229,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
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;
+ bool find_next = req_id &
+ (V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND);
unsigned int i;
req_id &= V4L2_CTRL_ID_MASK;
@@ -1310,10 +1320,12 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
}
__uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
- &master_ctrl, 0);
+ &master_ctrl, 0, 0);
if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
return 0;
+ if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
+ return -EIO;
ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
if (ret >= 0 && val != mapping->master_manual)
@@ -1377,10 +1389,15 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
if (mapping->master_id)
__uvc_find_control(ctrl->entity, mapping->master_id,
- &master_map, &master_ctrl, 0);
+ &master_map, &master_ctrl, 0, 0);
if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
s32 val;
- int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
+ int ret;
+
+ if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
+ return -EIO;
+
+ ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
if (ret < 0)
return ret;
@@ -1388,6 +1405,15 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
}
+ if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
+ v4l2_ctrl->default_value = 0;
+ v4l2_ctrl->minimum = 0;
+ v4l2_ctrl->maximum = 0;
+ v4l2_ctrl->step = 0;
+ return 0;
+ }
+
if (!ctrl->cached) {
int ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
@@ -1627,11 +1653,12 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
s32 val = 0;
- __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0);
+ __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0, 0);
if (ctrl == NULL)
return;
- if (__uvc_ctrl_get(chain, ctrl, mapping, &val) == 0)
+ if (uvc_ctrl_mapping_is_compound(mapping) ||
+ __uvc_ctrl_get(chain, ctrl, mapping, &val) == 0)
changes |= V4L2_EVENT_CTRL_CH_VALUE;
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
@@ -1650,7 +1677,12 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
ctrl->handle = NULL;
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
- s32 value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data);
+ s32 value;
+
+ if (uvc_ctrl_mapping_is_compound(mapping))
+ value = 0;
+ else
+ value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data);
/*
* handle may be NULL here if the device sends auto-update
@@ -1736,6 +1768,7 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
for (i = 0; i < xctrls_count; ++i) {
u32 changes = V4L2_EVENT_CTRL_CH_VALUE;
+ s32 value;
ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
@@ -1760,6 +1793,10 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
slave_id);
}
+ if (uvc_ctrl_mapping_is_compound(mapping))
+ value = 0;
+ else
+ value = xctrls[i].value;
/*
* If the master is being modified in the same transaction
* flags may change too.
@@ -1770,7 +1807,7 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
changes |= V4L2_EVENT_CTRL_CH_FLAGS;
uvc_ctrl_send_event(handle->chain, handle, ctrl, mapping,
- xctrls[i].value, changes);
+ value, changes);
}
}
@@ -1802,7 +1839,8 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
s32 val = 0;
- if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
+ if (uvc_ctrl_mapping_is_compound(mapping) ||
+ __uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
changes |= V4L2_EVENT_CTRL_CH_VALUE;
uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val,
@@ -1935,7 +1973,7 @@ static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
for (i = 0; i < ctrls->count; i++) {
__uvc_find_control(entity, ctrls->controls[i].id, &mapping,
- &ctrl_found, 0);
+ &ctrl_found, 0, 0);
if (uvc_control == ctrl_found)
return i;
}
@@ -1971,19 +2009,59 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
return ret;
}
-int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
- struct v4l2_ext_control *xctrl)
+static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ u32 which,
+ struct v4l2_ext_control *xctrl)
{
- struct uvc_control *ctrl;
- struct uvc_control_mapping *mapping;
-
- if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
- return -EACCES;
+ u8 *data __free(kfree) = NULL;
+ size_t size;
+ u8 query;
+ int ret;
+ int id;
- ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL)
+ switch (which) {
+ case V4L2_CTRL_WHICH_CUR_VAL:
+ ret = __uvc_ctrl_load_cur(chain, ctrl);
+ if (ret < 0)
+ return ret;
+ id = UVC_CTRL_DATA_CURRENT;
+ query = UVC_GET_CUR;
+ break;
+ case V4L2_CTRL_WHICH_DEF_VAL:
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ return ret;
+ id = UVC_CTRL_DATA_DEF;
+ query = UVC_GET_DEF;
+ break;
+ default:
return -EINVAL;
+ }
+
+ size = DIV_ROUND_UP(mapping->size, 8);
+ if (xctrl->size < size) {
+ xctrl->size = size;
+ return -ENOSPC;
+ }
+
+ data = kmalloc(size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = mapping->get(mapping, query, uvc_ctrl_data(ctrl, id), size, data);
+ if (ret < 0)
+ return ret;
+
+ return copy_to_user(xctrl->ptr, data, size) ? -EFAULT : 0;
+}
+static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ u32 which, struct v4l2_ext_control *xctrl)
+{
switch (which) {
case V4L2_CTRL_WHICH_CUR_VAL:
return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
@@ -2002,6 +2080,33 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
return -EINVAL;
}
+static int uvc_mapping_get_xctrl(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ u32 which, struct v4l2_ext_control *xctrl)
+{
+ if (uvc_ctrl_mapping_is_compound(mapping))
+ return uvc_mapping_get_xctrl_compound(chain, ctrl, mapping,
+ which, xctrl);
+ return uvc_mapping_get_xctrl_std(chain, ctrl, mapping, which, xctrl);
+}
+
+int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
+ struct v4l2_ext_control *xctrl)
+{
+ 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)
+ return -EINVAL;
+
+ return uvc_mapping_get_xctrl(chain, ctrl, mapping, which, xctrl);
+}
+
static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
struct uvc_control *ctrl,
struct uvc_control_mapping *mapping,
@@ -2085,6 +2190,37 @@ static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
return 0;
}
+static int uvc_mapping_set_xctrl_compound(struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ struct v4l2_ext_control *xctrl)
+{
+ u8 *data __free(kfree) = NULL;
+ size_t size;
+
+ size = DIV_ROUND_UP(mapping->size, 8);
+ if (xctrl->size != size)
+ return -EINVAL;
+
+ data = memdup_user(xctrl->ptr, size);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return mapping->set(mapping, size, data,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+}
+
+static int uvc_mapping_set_xctrl(struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ struct v4l2_ext_control *xctrl)
+{
+ if (uvc_ctrl_mapping_is_compound(mapping))
+ return uvc_mapping_set_xctrl_compound(ctrl, mapping, xctrl);
+
+ uvc_mapping_set_s32(mapping, xctrl->value,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+ return 0;
+}
+
int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
{
struct uvc_video_chain *chain = handle->chain;
@@ -2122,8 +2258,9 @@ int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
ctrl->info.size);
}
- uvc_mapping_set_s32(mapping, xctrl->value,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+ ret = uvc_mapping_set_xctrl(ctrl, mapping, xctrl);
+ if (ret)
+ return ret;
if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
ctrl->handle = handle;
@@ -2501,6 +2638,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
struct uvc_control_mapping *map;
unsigned int size;
unsigned int i;
+ int ret;
/*
* Most mappings come from static kernel data, and need to be duplicated.
@@ -2518,8 +2656,10 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
/* For UVCIOC_CTRL_MAP custom control */
if (mapping->name) {
map->name = kstrdup(mapping->name, GFP_KERNEL);
- if (!map->name)
- goto err_nomem;
+ if (!map->name) {
+ ret = -ENOMEM;
+ goto free_mem;
+ }
}
INIT_LIST_HEAD(&map->ev_subs);
@@ -2529,21 +2669,31 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
* fls(mapping->menu_mask);
map->menu_mapping = kmemdup(mapping->menu_mapping, size,
GFP_KERNEL);
- if (!map->menu_mapping)
- goto err_nomem;
+ if (!map->menu_mapping) {
+ ret = -ENOMEM;
+ goto free_mem;
+ }
}
if (mapping->menu_names && mapping->menu_mask) {
size = sizeof(mapping->menu_names[0])
* fls(mapping->menu_mask);
map->menu_names = kmemdup(mapping->menu_names, size,
GFP_KERNEL);
- if (!map->menu_names)
- goto err_nomem;
+ if (!map->menu_names) {
+ ret = -ENOMEM;
+ goto free_mem;
+ }
}
- if (map->get == NULL)
+ if (uvc_ctrl_mapping_is_compound(map))
+ if (WARN_ON(!map->set || !map->get)) {
+ ret = -EIO;
+ goto free_mem;
+ }
+
+ if (!map->get)
map->get = uvc_get_le_value;
- if (map->set == NULL)
+ if (!map->set)
map->set = uvc_set_le_value;
for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) {
@@ -2561,12 +2711,12 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
return 0;
-err_nomem:
+free_mem:
kfree(map->menu_names);
kfree(map->menu_mapping);
kfree(map->name);
kfree(map);
- return -ENOMEM;
+ return ret;
}
int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 3d32a56c5ff8..f429f325433b 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -115,7 +115,12 @@ struct uvc_control_mapping {
u8 entity[16];
u8 selector;
+ /*
+ * Size of the control data in the payload of the UVC control GET and
+ * SET requests, expressed in bits.
+ */
u8 size;
+
u8 offset;
enum v4l2_ctrl_type v4l2_type;
u32 data_type;
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 12/19] media: uvcvideo: Factor out query_boundaries from query_ctrl
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (10 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 11/19] media: uvcvideo: add support for compound controls Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
2024-12-09 13:38 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 13/19] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL Ricardo Ribalda
` (7 subsequent siblings)
19 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
Split the function in two parts. queryctrl_boundaries will be used in
future patches.
No functional change expected from this patch.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 106 ++++++++++++++++++++++-----------------
1 file changed, 60 insertions(+), 46 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index e51cd0a2228a..b591d7fddc37 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1367,53 +1367,11 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
return ~0;
}
-static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct uvc_control *ctrl,
- struct uvc_control_mapping *mapping,
- struct v4l2_queryctrl *v4l2_ctrl)
+static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ struct v4l2_queryctrl *v4l2_ctrl)
{
- struct uvc_control_mapping *master_map = NULL;
- struct uvc_control *master_ctrl = NULL;
-
- memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
- v4l2_ctrl->id = mapping->id;
- v4l2_ctrl->type = mapping->v4l2_type;
- strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping),
- sizeof(v4l2_ctrl->name));
- v4l2_ctrl->flags = 0;
-
- if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
- v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
- v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
- if (mapping->master_id)
- __uvc_find_control(ctrl->entity, mapping->master_id,
- &master_map, &master_ctrl, 0, 0);
- if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
- s32 val;
- int ret;
-
- if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
- return -EIO;
-
- ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
- if (ret < 0)
- return ret;
-
- if (val != mapping->master_manual)
- v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- }
-
- if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
- v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
- v4l2_ctrl->default_value = 0;
- v4l2_ctrl->minimum = 0;
- v4l2_ctrl->maximum = 0;
- v4l2_ctrl->step = 0;
- return 0;
- }
-
if (!ctrl->cached) {
int ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
@@ -1456,18 +1414,74 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
+ else
+ v4l2_ctrl->minimum = 0;
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+ else
+ v4l2_ctrl->maximum = 0;
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ else
+ v4l2_ctrl->step = 0;
return 0;
}
+static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ struct v4l2_queryctrl *v4l2_ctrl)
+{
+ struct uvc_control_mapping *master_map = NULL;
+ struct uvc_control *master_ctrl = NULL;
+
+ memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
+ v4l2_ctrl->id = mapping->id;
+ v4l2_ctrl->type = mapping->v4l2_type;
+ strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping),
+ sizeof(v4l2_ctrl->name));
+ v4l2_ctrl->flags = 0;
+
+ if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ if (mapping->master_id)
+ __uvc_find_control(ctrl->entity, mapping->master_id,
+ &master_map, &master_ctrl, 0, 0);
+ if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
+ s32 val;
+ int ret;
+
+ if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
+ return -EIO;
+
+ ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != mapping->master_manual)
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ }
+
+ if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
+ v4l2_ctrl->default_value = 0;
+ v4l2_ctrl->minimum = 0;
+ v4l2_ctrl->maximum = 0;
+ v4l2_ctrl->step = 0;
+ return 0;
+ }
+
+ return __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl);
+}
+
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl)
{
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 13/19] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (11 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 12/19] media: uvcvideo: Factor out query_boundaries from query_ctrl Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 13:47 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 14/19] media: uvcvideo: Use the camera to clamp compound controls Ricardo Ribalda
` (6 subsequent siblings)
19 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, Yunke Cao
From: Yunke Cao <yunkec@google.com>
Add support for V4L2_CTRL_WHICH_MIN/MAX_VAL in uvc driver.
It is needed for the V4L2_CID_UVC_REGION_OF_INTEREST_RECT control.
Signed-off-by: Yunke Cao <yunkec@google.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 96 ++++++++++++++++++++++++++++++++--------
drivers/media/usb/uvc/uvc_v4l2.c | 2 +
2 files changed, 79 insertions(+), 19 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index b591d7fddc37..0dae5e8c3ca0 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1270,6 +1270,37 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
return 0;
}
+static bool uvc_ctrl_is_readable(u32 which, struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping)
+{
+ if (which == V4L2_CTRL_WHICH_CUR_VAL)
+ return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR);
+
+ if (which == V4L2_CTRL_WHICH_DEF_VAL)
+ return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF);
+
+ /* Types with implicit boundaries. */
+ switch (mapping->v4l2_type) {
+ case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ case V4L2_CTRL_TYPE_BUTTON:
+ return true;
+ case V4L2_CTRL_TYPE_BITMASK:
+ return (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) ||
+ (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX);
+ default:
+ break;
+ }
+
+ if (which == V4L2_CTRL_WHICH_MIN_VAL)
+ return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN);
+
+ if (which == V4L2_CTRL_WHICH_MAX_VAL)
+ return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX);
+
+ return false;
+}
+
/*
* Check if control @v4l2_id can be accessed by the given control @ioctl
* (VIDIOC_G_EXT_CTRLS, VIDIOC_TRY_EXT_CTRLS or VIDIOC_S_EXT_CTRLS).
@@ -1288,7 +1319,6 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
struct uvc_control *master_ctrl = NULL;
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl;
- bool read = ioctl == VIDIOC_G_EXT_CTRLS;
s32 val;
int ret;
int i;
@@ -1300,10 +1330,10 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
if (!ctrl)
return -EINVAL;
- if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) && read)
- return -EACCES;
+ if (ioctl == VIDIOC_G_EXT_CTRLS)
+ return uvc_ctrl_is_readable(ctrls->which, ctrl, mapping);
- if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read)
+ if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
return -EACCES;
if (ioctl != VIDIOC_S_EXT_CTRLS || !mapping->master_id)
@@ -1451,6 +1481,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) &&
+ (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN))
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX;
if (mapping->master_id)
__uvc_find_control(ctrl->entity, mapping->master_id,
@@ -2037,16 +2070,18 @@ static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
switch (which) {
case V4L2_CTRL_WHICH_CUR_VAL:
- ret = __uvc_ctrl_load_cur(chain, ctrl);
- if (ret < 0)
- return ret;
id = UVC_CTRL_DATA_CURRENT;
query = UVC_GET_CUR;
break;
+ case V4L2_CTRL_WHICH_MIN_VAL:
+ id = UVC_CTRL_DATA_MIN;
+ query = UVC_GET_MIN;
+ break;
+ case V4L2_CTRL_WHICH_MAX_VAL:
+ id = UVC_CTRL_DATA_MAX;
+ query = UVC_GET_MAX;
+ break;
case V4L2_CTRL_WHICH_DEF_VAL:
- ret = uvc_ctrl_populate_cache(chain, ctrl);
- if (ret < 0)
- return ret;
id = UVC_CTRL_DATA_DEF;
query = UVC_GET_DEF;
break;
@@ -2064,6 +2099,14 @@ static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
if (!data)
return -ENOMEM;
+ if (which == V4L2_CTRL_WHICH_CUR_VAL)
+ ret = __uvc_ctrl_load_cur(chain, ctrl);
+ else
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+
+ if (ret < 0)
+ return ret;
+
ret = mapping->get(mapping, query, uvc_ctrl_data(ctrl, id), size, data);
if (ret < 0)
return ret;
@@ -2076,22 +2119,37 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
struct uvc_control_mapping *mapping,
u32 which, struct v4l2_ext_control *xctrl)
{
+ struct v4l2_queryctrl qc;
+ int ret;
+
switch (which) {
case V4L2_CTRL_WHICH_CUR_VAL:
return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
case V4L2_CTRL_WHICH_DEF_VAL:
- if (!ctrl->cached) {
- int ret = uvc_ctrl_populate_cache(chain, ctrl);
+ case V4L2_CTRL_WHICH_MIN_VAL:
+ case V4L2_CTRL_WHICH_MAX_VAL:
+ break;
+ default:
+ return -EINVAL;
+ }
- if (ret < 0)
- return ret;
- }
- xctrl->value = uvc_mapping_get_s32(mapping, UVC_GET_DEF,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
- return 0;
+ ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qc);
+ if (ret < 0)
+ return ret;
+
+ switch (which) {
+ case V4L2_CTRL_WHICH_DEF_VAL:
+ xctrl->value = qc.default_value;
+ break;
+ case V4L2_CTRL_WHICH_MIN_VAL:
+ xctrl->value = qc.minimum;
+ break;
+ case V4L2_CTRL_WHICH_MAX_VAL:
+ xctrl->value = qc.maximum;
+ break;
}
- return -EINVAL;
+ return 0;
}
static int uvc_mapping_get_xctrl(struct uvc_video_chain *chain,
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 65dbb53b1e75..7e284770149d 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1087,6 +1087,8 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
switch (ctrls->which) {
case V4L2_CTRL_WHICH_DEF_VAL:
case V4L2_CTRL_WHICH_CUR_VAL:
+ case V4L2_CTRL_WHICH_MAX_VAL:
+ case V4L2_CTRL_WHICH_MIN_VAL:
which = ctrls->which;
break;
default:
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 14/19] media: uvcvideo: Use the camera to clamp compound controls
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (12 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 13/19] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 14:05 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl Ricardo Ribalda
` (5 subsequent siblings)
19 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
Compound controls cannot e reliable clamped. There is plenty of space
for interpretation for the device manufacturer.
When we write a compound control, let the camera do the clamping and
return back to the user the value used by the device.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 0dae5e8c3ca0..72ed7dc9cfc1 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2339,6 +2339,18 @@ int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
ctrl->dirty = 1;
ctrl->modified = 1;
+
+ /*
+ * Compound controls cannot reliable clamp the value when they are
+ * written to the device. Let the device do the clamping and read back
+ * the value that the device is using. We do not need to return an
+ * error if this fails.
+ */
+ if (uvc_ctrl_mapping_is_compound(mapping) &&
+ uvc_ctrl_is_readable(V4L2_CTRL_WHICH_CUR_VAL, ctrl, mapping))
+ uvc_mapping_get_xctrl_compound(chain, ctrl, mapping,
+ V4L2_CTRL_WHICH_CUR_VAL, xctrl);
+
return 0;
}
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (13 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 14/19] media: uvcvideo: Use the camera to clamp compound controls Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
2024-12-09 14:08 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 16/19] media: uvcvideo: Introduce uvc_mapping_v4l2_size Ricardo Ribalda
` (4 subsequent siblings)
19 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
v4l2_query_ext_ctrl contains information that is missing in
v4l2_queryctrl, like elem_size and elems.
With this change we can handle all the element_size information inside
uvc_ctrl.c.
Now that we are at it, remove the memset of the reserved fields, the
v4l2 ioctl handler should do that for us.
There is no functional change expected from this change.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 24 ++++++++++++++----------
drivers/media/usb/uvc/uvc_v4l2.c | 35 +++++++++++++++--------------------
drivers/media/usb/uvc/uvcvideo.h | 2 +-
3 files changed, 30 insertions(+), 31 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 72ed7dc9cfc1..1bc019138995 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1252,7 +1252,8 @@ static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
}
static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
- u32 found_id, struct v4l2_queryctrl *v4l2_ctrl)
+ u32 found_id,
+ struct v4l2_query_ext_ctrl *v4l2_ctrl)
{
int idx;
@@ -1400,7 +1401,7 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
struct uvc_control *ctrl,
struct uvc_control_mapping *mapping,
- struct v4l2_queryctrl *v4l2_ctrl)
+ struct v4l2_query_ext_ctrl *v4l2_ctrl)
{
if (!ctrl->cached) {
int ret = uvc_ctrl_populate_cache(chain, ctrl);
@@ -1465,7 +1466,7 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct uvc_control *ctrl,
struct uvc_control_mapping *mapping,
- struct v4l2_queryctrl *v4l2_ctrl)
+ struct v4l2_query_ext_ctrl *v4l2_ctrl)
{
struct uvc_control_mapping *master_map = NULL;
struct uvc_control *master_ctrl = NULL;
@@ -1503,6 +1504,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
}
+ v4l2_ctrl->elem_size = sizeof(s32);
+ v4l2_ctrl->elems = 1;
+
if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
v4l2_ctrl->default_value = 0;
@@ -1516,7 +1520,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
}
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct v4l2_queryctrl *v4l2_ctrl)
+ struct v4l2_query_ext_ctrl *v4l2_ctrl)
{
struct uvc_control *ctrl;
struct uvc_control_mapping *mapping;
@@ -1642,7 +1646,7 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
struct uvc_control_mapping *mapping,
s32 value, u32 changes)
{
- struct v4l2_queryctrl v4l2_ctrl;
+ struct v4l2_query_ext_ctrl v4l2_ctrl;
__uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
@@ -2119,7 +2123,7 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
struct uvc_control_mapping *mapping,
u32 which, struct v4l2_ext_control *xctrl)
{
- struct v4l2_queryctrl qc;
+ struct v4l2_query_ext_ctrl qec;
int ret;
switch (which) {
@@ -2133,19 +2137,19 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
return -EINVAL;
}
- ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qc);
+ ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qec);
if (ret < 0)
return ret;
switch (which) {
case V4L2_CTRL_WHICH_DEF_VAL:
- xctrl->value = qc.default_value;
+ xctrl->value = qec.default_value;
break;
case V4L2_CTRL_WHICH_MIN_VAL:
- xctrl->value = qc.minimum;
+ xctrl->value = qec.minimum;
break;
case V4L2_CTRL_WHICH_MAX_VAL:
- xctrl->value = qc.maximum;
+ xctrl->value = qec.maximum;
break;
}
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 7e284770149d..5000c74271e0 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1014,40 +1014,35 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
return ret;
}
-static int uvc_ioctl_queryctrl(struct file *file, void *fh,
- struct v4l2_queryctrl *qc)
+static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
+ struct v4l2_query_ext_ctrl *qec)
{
struct uvc_fh *handle = fh;
struct uvc_video_chain *chain = handle->chain;
- return uvc_query_v4l2_ctrl(chain, qc);
+ return uvc_query_v4l2_ctrl(chain, qec);
}
-static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
- struct v4l2_query_ext_ctrl *qec)
+static int uvc_ioctl_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *qc)
{
struct uvc_fh *handle = fh;
struct uvc_video_chain *chain = handle->chain;
- struct v4l2_queryctrl qc = { qec->id };
+ struct v4l2_query_ext_ctrl qec = { qc->id };
int ret;
- ret = uvc_query_v4l2_ctrl(chain, &qc);
+ ret = uvc_query_v4l2_ctrl(chain, &qec);
if (ret)
return ret;
- qec->id = qc.id;
- qec->type = qc.type;
- strscpy(qec->name, qc.name, sizeof(qec->name));
- qec->minimum = qc.minimum;
- qec->maximum = qc.maximum;
- qec->step = qc.step;
- qec->default_value = qc.default_value;
- qec->flags = qc.flags;
- qec->elem_size = 4;
- qec->elems = 1;
- qec->nr_of_dims = 0;
- memset(qec->dims, 0, sizeof(qec->dims));
- memset(qec->reserved, 0, sizeof(qec->reserved));
+ qc->id = qec.id;
+ qc->type = qec.type;
+ strscpy(qc->name, qec.name, sizeof(qc->name));
+ qc->minimum = qec.minimum;
+ qc->maximum = qec.maximum;
+ qc->step = qec.step;
+ qc->default_value = qec.default_value;
+ qc->flags = qec.flags;
return 0;
}
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index f429f325433b..8aca1a2fe587 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -766,7 +766,7 @@ void uvc_status_put(struct uvc_device *dev);
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct v4l2_queryctrl *v4l2_ctrl);
+ struct v4l2_query_ext_ctrl *v4l2_ctrl);
int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
struct v4l2_querymenu *query_menu);
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 16/19] media: uvcvideo: Introduce uvc_mapping_v4l2_size
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (14 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 8:51 ` Yunke Cao
2024-12-09 14:09 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map Ricardo Ribalda
` (3 subsequent siblings)
19 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
Centralize the calculation for the v4l2_size of a mapping.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 1bc019138995..f262e05ad3a8 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1463,6 +1463,14 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
return 0;
}
+static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
+{
+ if (uvc_ctrl_mapping_is_compound(mapping))
+ return DIV_ROUND_UP(mapping->size, 8);
+
+ return sizeof(s32);
+}
+
static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct uvc_control *ctrl,
struct uvc_control_mapping *mapping,
@@ -1504,7 +1512,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
}
- v4l2_ctrl->elem_size = sizeof(s32);
+ v4l2_ctrl->elem_size = uvc_mapping_v4l2_size(mapping);
v4l2_ctrl->elems = 1;
if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
@@ -2093,7 +2101,7 @@ static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
return -EINVAL;
}
- size = DIV_ROUND_UP(mapping->size, 8);
+ size = uvc_mapping_v4l2_size(mapping);
if (xctrl->size < size) {
xctrl->size = size;
return -ENOSPC;
@@ -2271,9 +2279,8 @@ static int uvc_mapping_set_xctrl_compound(struct uvc_control *ctrl,
struct v4l2_ext_control *xctrl)
{
u8 *data __free(kfree) = NULL;
- size_t size;
+ size_t size = uvc_mapping_v4l2_size(mapping);
- size = DIV_ROUND_UP(mapping->size, 8);
if (xctrl->size != size)
return -EINVAL;
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (15 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 16/19] media: uvcvideo: Introduce uvc_mapping_v4l2_size Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-29 8:15 ` Ricardo Ribalda
2024-12-09 14:11 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI Ricardo Ribalda
` (2 subsequent siblings)
19 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda
Do not process unknown data types.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_v4l2.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 5000c74271e0..4c88dab15554 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -106,6 +106,12 @@ static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain,
struct uvc_control_mapping *map;
int ret;
+ if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) {
+ uvc_dbg(chain->dev, CONTROL,
+ "Unsupported UVC data type %u\n", xmap->data_type);
+ return -ENOTTY;
+ }
+
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (map == NULL)
return -ENOMEM;
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (16 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-11-14 19:53 ` Gergo Koteles
` (2 more replies)
2024-11-14 19:10 ` [PATCH v15 19/19] media: uvcvideo: document " Ricardo Ribalda
2024-12-09 8:53 ` [PATCH v15 00/19] media: uvcvideo: Implement " Yunke Cao
19 siblings, 3 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, Yunke Cao
From: Yunke Cao <yunkec@google.com>
Implement support for ROI as described in UVC 1.5:
4.2.2.1.20 Digital Region of Interest (ROI) Control
ROI control is implemented using V4L2 control API as
two UVC-specific controls:
V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Yunke Cao <yunkec@google.com>
---
drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++++++++++++++++++++
drivers/media/usb/uvc/uvcvideo.h | 7 ++++
include/uapi/linux/usb/video.h | 1 +
include/uapi/linux/uvcvideo.h | 13 ++++++
include/uapi/linux/v4l2-controls.h | 9 +++++
5 files changed, 111 insertions(+)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index f262e05ad3a8..5b619ef40dd3 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -358,6 +358,24 @@ static const struct uvc_control_info uvc_ctrls[] = {
.flags = UVC_CTRL_FLAG_GET_CUR
| UVC_CTRL_FLAG_AUTO_UPDATE,
},
+ /*
+ * UVC_CTRL_FLAG_AUTO_UPDATE is needed because the RoI may get updated
+ * by sensors.
+ * "This RoI should be the same as specified in most recent SET_CUR
+ * except in the case where the ‘Auto Detect and Track’ and/or
+ * ‘Image Stabilization’ bit have been set."
+ * 4.2.2.1.20 Digital Region of Interest (ROI) Control
+ */
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
+ .index = 21,
+ .size = 10,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
+ },
};
static const u32 uvc_control_classes[] = {
@@ -603,6 +621,44 @@ static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
return out_mapping;
}
+static int uvc_get_rect(struct uvc_control_mapping *mapping, u8 query,
+ const void *uvc_in, size_t v4l2_size, void *v4l2_out)
+{
+ const struct uvc_rect *uvc_rect = uvc_in;
+ struct v4l2_rect *v4l2_rect = v4l2_out;
+
+ if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
+ return -EINVAL;
+
+ if (uvc_rect->left > uvc_rect->right ||
+ uvc_rect->top > uvc_rect->bottom)
+ return -EIO;
+
+ v4l2_rect->top = uvc_rect->top;
+ v4l2_rect->left = uvc_rect->left;
+ v4l2_rect->height = uvc_rect->bottom - uvc_rect->top + 1;
+ v4l2_rect->width = uvc_rect->right - uvc_rect->left + 1;
+
+ return 0;
+}
+
+static int uvc_set_rect(struct uvc_control_mapping *mapping, size_t v4l2_size,
+ const void *v4l2_in, void *uvc_out)
+{
+ struct uvc_rect *uvc_rect = uvc_out;
+ const struct v4l2_rect *v4l2_rect = v4l2_in;
+
+ if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
+ return -EINVAL;
+
+ uvc_rect->top = max(0xffff, v4l2_rect->top);
+ uvc_rect->left = max(0xffff, v4l2_rect->left);
+ uvc_rect->bottom = max(0xffff, v4l2_rect->height + v4l2_rect->top - 1);
+ uvc_rect->right = max(0xffff, v4l2_rect->width + v4l2_rect->left - 1);
+
+ return 0;
+}
+
static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
{
.id = V4L2_CID_BRIGHTNESS,
@@ -897,6 +953,28 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
.filter_mapping = uvc_ctrl_filter_plf_mapping,
},
+ {
+ .id = V4L2_CID_UVC_REGION_OF_INTEREST_RECT,
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
+ .size = sizeof(struct uvc_rect) * 8,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_RECT,
+ .data_type = UVC_CTRL_DATA_TYPE_RECT,
+ .get = uvc_get_rect,
+ .set = uvc_set_rect,
+ .name = "Region Of Interest Rectangle",
+ },
+ {
+ .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
+ .size = 16,
+ .offset = 64,
+ .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
+ .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
+ .name = "Region Of Interest Auto Controls",
+ },
};
/* ------------------------------------------------------------------------
@@ -1465,6 +1543,9 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
{
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_RECT)
+ return sizeof(struct v4l2_rect);
+
if (uvc_ctrl_mapping_is_compound(mapping))
return DIV_ROUND_UP(mapping->size, 8);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 8aca1a2fe587..d910a5e5b514 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -294,6 +294,13 @@ struct uvc_streaming_header {
u8 bTriggerUsage;
};
+struct uvc_rect {
+ u16 top;
+ u16 left;
+ u16 bottom;
+ u16 right;
+} __packed;
+
enum uvc_buffer_state {
UVC_BUF_STATE_IDLE = 0,
UVC_BUF_STATE_QUEUED = 1,
diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
index 2ff0e8a3a683..2afb4420e6c4 100644
--- a/include/uapi/linux/usb/video.h
+++ b/include/uapi/linux/usb/video.h
@@ -104,6 +104,7 @@
#define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f
#define UVC_CT_ROLL_RELATIVE_CONTROL 0x10
#define UVC_CT_PRIVACY_CONTROL 0x11
+#define UVC_CT_REGION_OF_INTEREST_CONTROL 0x14
/* A.9.5. Processing Unit Control Selectors */
#define UVC_PU_CONTROL_UNDEFINED 0x00
diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
index f86185456dc5..cbe15bca9569 100644
--- a/include/uapi/linux/uvcvideo.h
+++ b/include/uapi/linux/uvcvideo.h
@@ -16,6 +16,7 @@
#define UVC_CTRL_DATA_TYPE_BOOLEAN 3
#define UVC_CTRL_DATA_TYPE_ENUM 4
#define UVC_CTRL_DATA_TYPE_BITMASK 5
+#define UVC_CTRL_DATA_TYPE_RECT 6
/* Control flags */
#define UVC_CTRL_FLAG_SET_CUR (1 << 0)
@@ -38,6 +39,18 @@
#define UVC_MENU_NAME_LEN 32
+/* V4L2 driver-specific controls */
+#define V4L2_CID_UVC_REGION_OF_INTEREST_RECT (V4L2_CID_USER_UVC_BASE + 1)
+#define V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (V4L2_CID_USER_UVC_BASE + 2)
+#define V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE (1 << 0)
+#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS (1 << 1)
+#define V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE (1 << 2)
+#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS (1 << 3)
+#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT (1 << 4)
+#define V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK (1 << 5)
+#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION (1 << 6)
+#define V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY (1 << 7)
+
struct uvc_menu_info {
__u32 value;
__u8 name[UVC_MENU_NAME_LEN];
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 974fd254e573..6c91d6fa4708 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -215,6 +215,13 @@ enum v4l2_colorfx {
*/
#define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0)
+/*
+ * The base for the uvc driver controls.
+ * See linux/uvcvideo.h for the list of controls.
+ * We reserve 64 controls for this driver.
+ */
+#define V4L2_CID_USER_UVC_BASE (V4L2_CID_USER_BASE + 0x11e0)
+
/* MPEG-class control IDs */
/* The MPEG controls are applicable to all codec controls
* and the 'MPEG' part of the define is historical */
@@ -1089,6 +1096,8 @@ enum v4l2_auto_focus_range {
#define V4L2_CID_HDR_SENSOR_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
+/* CAMERA-class private control IDs */
+
/* FM Modulator class control IDs */
#define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v15 19/19] media: uvcvideo: document UVC v1.5 ROI
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (17 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI Ricardo Ribalda
@ 2024-11-14 19:10 ` Ricardo Ribalda
2024-12-09 14:36 ` Hans de Goede
2024-12-09 8:53 ` [PATCH v15 00/19] media: uvcvideo: Implement " Yunke Cao
19 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 19:10 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Ricardo Ribalda, Yunke Cao,
Sergey Senozhatsky
From: Yunke Cao <yunkec@google.com>
Added documentation of V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
An example of a userspace implementing this feature can be found at:
https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/release-R121-15699.B/camera/hal/usb/
Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Signed-off-by: Yunke Cao <yunkec@google.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
.../userspace-api/media/drivers/uvcvideo.rst | 64 ++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/Documentation/userspace-api/media/drivers/uvcvideo.rst b/Documentation/userspace-api/media/drivers/uvcvideo.rst
index a290f9fadae9..1cdcd45907a3 100644
--- a/Documentation/userspace-api/media/drivers/uvcvideo.rst
+++ b/Documentation/userspace-api/media/drivers/uvcvideo.rst
@@ -181,6 +181,7 @@ Argument: struct uvc_xu_control_mapping
UVC_CTRL_DATA_TYPE_BOOLEAN Boolean
UVC_CTRL_DATA_TYPE_ENUM Enumeration
UVC_CTRL_DATA_TYPE_BITMASK Bitmask
+ UVC_CTRL_DATA_TYPE_RECT Rectangular area
UVCIOC_CTRL_QUERY - Query a UVC XU control
@@ -255,3 +256,66 @@ Argument: struct uvc_xu_control_query
__u8 query Request code to send to the device
__u16 size Control data size (in bytes)
__u8 *data Control value
+
+
+Driver-specific V4L2 controls
+-----------------------------
+
+The uvcvideo driver implements the following UVC-specific controls:
+
+``V4L2_CID_UVC_REGION_OF_INTEREST_RECT (struct)``
+ This control determines the region of interest (ROI). ROI is a
+ rectangular area represented by a struct :c:type:`v4l2_rect`. The
+ rectangle is in global sensor coordinates and pixel units. It is
+ independent of the field of view, not impacted by any cropping or
+ scaling.
+
+ Use ``V4L2_CTRL_WHICH_MIN_VAL`` and ``V4L2_CTRL_WHICH_MAX_VAL`` to query
+ the range of rectangle sizes.
+
+ Setting a ROI allows the camera to optimize the capture for the region.
+ The value of ``V4L2_CID_REGION_OF_INTEREST_AUTO`` control determines
+ the detailed behavior.
+
+ An example of use of this control, can be found in the:
+ `Chrome OS USB camera HAL.
+ <https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/release-R121-15699.B/camera/hal/usb/>`
+
+
+``V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (bitmask)``
+ This determines which, if any, on-board features should track to the
+ Region of Interest specified by the current value of
+ ``V4L2_CID_UVD__REGION_OF_INTEREST_RECT``.
+
+ Max value is a mask indicating all supported Auto Controls.
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE``
+ - Setting this bit causes automatic exposure to track the region of
+ interest instead of the whole image.
+ * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS``
+ - Setting this bit causes automatic iris to track the region of interest
+ instead of the whole image.
+ * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE``
+ - Setting this bit causes automatic white balance to track the region
+ of interest instead of the whole image.
+ * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS``
+ - Setting this bit causes automatic focus adjustment to track the region
+ of interest instead of the whole image.
+ * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT``
+ - Setting this bit causes automatic face detection to track the region of
+ interest instead of the whole image.
+ * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK``
+ - Setting this bit enables automatic face detection and tracking. The
+ current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by
+ the driver.
+ * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION``
+ - Setting this bit enables automatic image stabilization. The
+ current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by
+ the driver.
+ * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY``
+ - Setting this bit enables automatically capture the specified region
+ with higher quality if possible.
--
2.47.0.338.g60cca15819-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 19:10 ` [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI Ricardo Ribalda
@ 2024-11-14 19:53 ` Gergo Koteles
2024-11-14 20:03 ` Ricardo Ribalda
2024-12-02 8:02 ` Yunke Cao
2024-12-09 14:22 ` Hans de Goede
2 siblings, 1 reply; 62+ messages in thread
From: Gergo Koteles @ 2024-11-14 19:53 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Hans de Goede, Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Yunke Cao
Hi Ricardo,
On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
>
> + },
> + {
> + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> + .entity = UVC_GUID_UVC_CAMERA,
> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> + .size = 16,
> + .offset = 64,
> + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> + .name = "Region Of Interest Auto Controls",
> + },
> };
>
Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
Thanks,
Gergo
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 19:53 ` Gergo Koteles
@ 2024-11-14 20:03 ` Ricardo Ribalda
2024-11-14 20:16 ` Gergo Koteles
2024-11-18 15:59 ` Hans de Goede
0 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 20:03 UTC (permalink / raw)
To: Gergo Koteles
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel, Yunke Cao
Hi Gergo
Sorry, I forgot to reply to your comment in v14.
On Thu, 14 Nov 2024 at 20:53, Gergo Koteles <soyer@irl.hu> wrote:
>
> Hi Ricardo,
>
> On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
> >
> > + },
> > + {
> > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> > + .entity = UVC_GUID_UVC_CAMERA,
> > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > + .size = 16,
> > + .offset = 64,
> > + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> > + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > + .name = "Region Of Interest Auto Controls",
> > + },
> > };
> >
>
> Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
If I create 8 Booleans, they will always be shown in the device. And
the user will not have a way to know which values are available and
which are not.
We will also fail the v4l2-compliance test, because there will be up
to 7 boolean controls that will not be able to be set to 1, eventhough
they are writable.
Thanks for the prompt review.
>
> Thanks,
> Gergo
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 20:03 ` Ricardo Ribalda
@ 2024-11-14 20:16 ` Gergo Koteles
2024-11-14 20:28 ` Ricardo Ribalda
2024-11-18 15:59 ` Hans de Goede
1 sibling, 1 reply; 62+ messages in thread
From: Gergo Koteles @ 2024-11-14 20:16 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel, Yunke Cao
Hi Ricardo,
On Thu, 2024-11-14 at 21:03 +0100, Ricardo Ribalda wrote:
> Hi Gergo
>
> Sorry, I forgot to reply to your comment in v14.
>
> On Thu, 14 Nov 2024 at 20:53, Gergo Koteles <soyer@irl.hu> wrote:
> >
> > Hi Ricardo,
> >
> > On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
> > >
> > > + },
> > > + {
> > > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> > > + .entity = UVC_GUID_UVC_CAMERA,
> > > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > > + .size = 16,
> > > + .offset = 64,
> > > + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> > > + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > > + .name = "Region Of Interest Auto Controls",
> > > + },
> > > };
> > >
> >
> > Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
>
> If I create 8 Booleans, they will always be shown in the device. And
> the user will not have a way to know which values are available and
> which are not.
>
> We will also fail the v4l2-compliance test, because there will be up
> to 7 boolean controls that will not be able to be set to 1, eventhough
> they are writable.
>
And can't it be that only those returned by GET_MAX be added?
```
The bmAutoControls bitmask determines which, if any, on board features
should track to the region of interest. To detect if a device supports
a particular Auto Control, use GET_MAX which returns a mask indicating
all supported Auto Controls.
```
Sorry for the misunderstanding, I just don't quite understand.
Thanks,
Gergo
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 20:16 ` Gergo Koteles
@ 2024-11-14 20:28 ` Ricardo Ribalda
2024-11-15 0:04 ` Gergo Koteles
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-14 20:28 UTC (permalink / raw)
To: Gergo Koteles
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel, Yunke Cao
Hi
On Thu, 14 Nov 2024 at 21:16, Gergo Koteles <soyer@irl.hu> wrote:
>
> Hi Ricardo,
>
> On Thu, 2024-11-14 at 21:03 +0100, Ricardo Ribalda wrote:
> > Hi Gergo
> >
> > Sorry, I forgot to reply to your comment in v14.
> >
> > On Thu, 14 Nov 2024 at 20:53, Gergo Koteles <soyer@irl.hu> wrote:
> > >
> > > Hi Ricardo,
> > >
> > > On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
> > > >
> > > > + },
> > > > + {
> > > > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> > > > + .entity = UVC_GUID_UVC_CAMERA,
> > > > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > > > + .size = 16,
> > > > + .offset = 64,
> > > > + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> > > > + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > > > + .name = "Region Of Interest Auto Controls",
> > > > + },
> > > > };
> > > >
> > >
> > > Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
> >
> > If I create 8 Booleans, they will always be shown in the device. And
> > the user will not have a way to know which values are available and
> > which are not.
> >
> > We will also fail the v4l2-compliance test, because there will be up
> > to 7 boolean controls that will not be able to be set to 1, eventhough
> > they are writable.
> >
>
> And can't it be that only those returned by GET_MAX be added?
>
> ```
> The bmAutoControls bitmask determines which, if any, on board features
> should track to the region of interest. To detect if a device supports
> a particular Auto Control, use GET_MAX which returns a mask indicating
> all supported Auto Controls.
> ```
>
> Sorry for the misunderstanding, I just don't quite understand.
I guess we could, but we would have to make a big change in the way
the controls are probed today. uvc does not use the control framework.
What will be the benefit of using 8 controls?
- Applications still have to know what those controls do, they should
not rely on the control name.
- Changing from lets say AUTO_EXPOSURE to AUTO_FOCUS, will require to
send at least 2 controls via v4l2_s_ext_control... I think it is more
practical and less prone to errrors to send just one control
If the number of autos were unknown, then having multiple controls
could be a good idea, but they are part of the uvc standard and
unlikely to be changed.
Thanks!
>
> Thanks,
>
> Gergo
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 20:28 ` Ricardo Ribalda
@ 2024-11-15 0:04 ` Gergo Koteles
2024-11-15 8:22 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Gergo Koteles @ 2024-11-15 0:04 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel, Yunke Cao
Hi Ricardo,
On Thu, 2024-11-14 at 21:28 +0100, Ricardo Ribalda wrote:
> Hi
>
> On Thu, 14 Nov 2024 at 21:16, Gergo Koteles <soyer@irl.hu> wrote:
> >
> > Hi Ricardo,
> >
> > On Thu, 2024-11-14 at 21:03 +0100, Ricardo Ribalda wrote:
> > > Hi Gergo
> > >
> > > Sorry, I forgot to reply to your comment in v14.
> > >
> > > On Thu, 14 Nov 2024 at 20:53, Gergo Koteles <soyer@irl.hu> wrote:
> > > >
> > > > Hi Ricardo,
> > > >
> > > > On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
> > > > >
> > > > > + },
> > > > > + {
> > > > > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> > > > > + .entity = UVC_GUID_UVC_CAMERA,
> > > > > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > > > > + .size = 16,
> > > > > + .offset = 64,
> > > > > + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> > > > > + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > > > > + .name = "Region Of Interest Auto Controls",
> > > > > + },
> > > > > };
> > > > >
> > > >
> > > > Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
> > >
> > > If I create 8 Booleans, they will always be shown in the device. And
> > > the user will not have a way to know which values are available and
> > > which are not.
> > >
> > > We will also fail the v4l2-compliance test, because there will be up
> > > to 7 boolean controls that will not be able to be set to 1, eventhough
> > > they are writable.
> > >
> >
> > And can't it be that only those returned by GET_MAX be added?
> >
> > ```
> > The bmAutoControls bitmask determines which, if any, on board features
> > should track to the region of interest. To detect if a device supports
> > a particular Auto Control, use GET_MAX which returns a mask indicating
> > all supported Auto Controls.
> > ```
> >
> > Sorry for the misunderstanding, I just don't quite understand.
>
> I guess we could, but we would have to make a big change in the way
> the controls are probed today. uvc does not use the control framework.
>
> What will be the benefit of using 8 controls?
> - Applications still have to know what those controls do, they should
> not rely on the control name.
Applications like v4l2-ctl are not aware of every controls, work by
control type, and let the user decide what to do, based on the name.
To avoid having to know each bitmask type control, they need to be able
to query which bit means what and what to display to the user.
Could VIDIOC_QUERYMENU be supplemented with this?
> - Changing from lets say AUTO_EXPOSURE to AUTO_FOCUS, will require to
> send at least 2 controls via v4l2_s_ext_control... I think it is more
> practical and less prone to errrors to send just one control
>
Yes, that could be a good reason.
Thanks,
Gergo
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-15 0:04 ` Gergo Koteles
@ 2024-11-15 8:22 ` Ricardo Ribalda
0 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-15 8:22 UTC (permalink / raw)
To: Gergo Koteles
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel, Yunke Cao
On Fri, 15 Nov 2024 at 01:04, Gergo Koteles <soyer@irl.hu> wrote:
>
> Hi Ricardo,
>
> On Thu, 2024-11-14 at 21:28 +0100, Ricardo Ribalda wrote:
> > Hi
> >
> > On Thu, 14 Nov 2024 at 21:16, Gergo Koteles <soyer@irl.hu> wrote:
> > >
> > > Hi Ricardo,
> > >
> > > On Thu, 2024-11-14 at 21:03 +0100, Ricardo Ribalda wrote:
> > > > Hi Gergo
> > > >
> > > > Sorry, I forgot to reply to your comment in v14.
> > > >
> > > > On Thu, 14 Nov 2024 at 20:53, Gergo Koteles <soyer@irl.hu> wrote:
> > > > >
> > > > > Hi Ricardo,
> > > > >
> > > > > On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
> > > > > >
> > > > > > + },
> > > > > > + {
> > > > > > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> > > > > > + .entity = UVC_GUID_UVC_CAMERA,
> > > > > > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > > > > > + .size = 16,
> > > > > > + .offset = 64,
> > > > > > + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> > > > > > + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > > > > > + .name = "Region Of Interest Auto Controls",
> > > > > > + },
> > > > > > };
> > > > > >
> > > > >
> > > > > Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
> > > >
> > > > If I create 8 Booleans, they will always be shown in the device. And
> > > > the user will not have a way to know which values are available and
> > > > which are not.
> > > >
> > > > We will also fail the v4l2-compliance test, because there will be up
> > > > to 7 boolean controls that will not be able to be set to 1, eventhough
> > > > they are writable.
> > > >
> > >
> > > And can't it be that only those returned by GET_MAX be added?
> > >
> > > ```
> > > The bmAutoControls bitmask determines which, if any, on board features
> > > should track to the region of interest. To detect if a device supports
> > > a particular Auto Control, use GET_MAX which returns a mask indicating
> > > all supported Auto Controls.
> > > ```
> > >
> > > Sorry for the misunderstanding, I just don't quite understand.
> >
> > I guess we could, but we would have to make a big change in the way
> > the controls are probed today. uvc does not use the control framework.
> >
> > What will be the benefit of using 8 controls?
> > - Applications still have to know what those controls do, they should
> > not rely on the control name.
>
> Applications like v4l2-ctl are not aware of every controls, work by
> control type, and let the user decide what to do, based on the name.
>
> To avoid having to know each bitmask type control, they need to be able
> to query which bit means what and what to display to the user.
>
> Could VIDIOC_QUERYMENU be supplemented with this?
I believe that violates compliance. VIDIOC_QUERYMENU should only be
used on menus.
https://git.linuxtv.org/v4l-utils.git/tree/utils/v4l2-compliance/v4l2-test-controls.cpp?h=v4l-utils-1.28.1#n143
>
>
> > - Changing from lets say AUTO_EXPOSURE to AUTO_FOCUS, will require to
> > send at least 2 controls via v4l2_s_ext_control... I think it is more
> > practical and less prone to errrors to send just one control
> >
>
> Yes, that could be a good reason.
>
> Thanks,
> Gergo
>
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 20:03 ` Ricardo Ribalda
2024-11-14 20:16 ` Gergo Koteles
@ 2024-11-18 15:59 ` Hans de Goede
2024-11-18 16:16 ` Ricardo Ribalda Delgado
1 sibling, 1 reply; 62+ messages in thread
From: Hans de Goede @ 2024-11-18 15:59 UTC (permalink / raw)
To: Ricardo Ribalda, Gergo Koteles
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Ricardo Ribalda,
Sakari Ailus, Hans Verkuil, Yunke Cao, linux-media, linux-kernel,
Yunke Cao
Hi Ricardo,
On 14-Nov-24 9:03 PM, Ricardo Ribalda wrote:
> Hi Gergo
>
> Sorry, I forgot to reply to your comment in v14.
>
> On Thu, 14 Nov 2024 at 20:53, Gergo Koteles <soyer@irl.hu> wrote:
>>
>> Hi Ricardo,
>>
>> On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
>>>
>>> + },
>>> + {
>>> + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
>>> + .entity = UVC_GUID_UVC_CAMERA,
>>> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
>>> + .size = 16,
>>> + .offset = 64,
>>> + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
>>> + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
>>> + .name = "Region Of Interest Auto Controls",
>>> + },
>>> };
>>>
>>
>> Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
>
> If I create 8 Booleans, they will always be shown in the device. And
> the user will not have a way to know which values are available and
> which are not.
>
> We will also fail the v4l2-compliance test, because there will be up
> to 7 boolean controls that will not be able to be set to 1, eventhough
> they are writable.
So why can't these other controls be set to 1? Because only one
of the options in the bitmask can be selected at a time ?
If only 1 bit in the UVC_CTRL_DATA_TYPE_BITMASK for this can be one
at the time, then this should be mapped to a V4L2_CTRL_TYPE_MENU
just like how that is done for V4L2_CID_EXPOSURE_AUTO already.
Actually looking at existing comments about UVC_CTRL_DATA_TYPE_BITMASK
in the driver there is this comment on top of uvc_mapping_get_menu_value()
* For controls of type UVC_CTRL_DATA_TYPE_BITMASK, the UVC control value is
* expressed as a bitmask and is thus guaranteed to have a single bit set.
Assuming this "guaranteed to have a single bit set" comment is valid for
the V4L2_CID_UVC_REGION_OF_INTEREST_AUTO part of UVC_CT_REGION_OF_INTEREST_CONTROL
too then I think we should simply map this to a menu similar to how
this is done for V4L2_CID_EXPOSURE_AUTO.
Note V4L2_CID_EXPOSURE_AUTO is the only existing user of UVC_CTRL_DATA_TYPE_BITMASK
at the moment.
Mapping this to a menu should nicely address Gergo's concerns here.
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-18 15:59 ` Hans de Goede
@ 2024-11-18 16:16 ` Ricardo Ribalda Delgado
2024-11-25 14:27 ` Hans de Goede
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-11-18 16:16 UTC (permalink / raw)
To: Hans de Goede
Cc: Ricardo Ribalda, Gergo Koteles, Laurent Pinchart,
Mauro Carvalho Chehab, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel, Yunke Cao
Hi
On Mon, Nov 18, 2024 at 4:59 PM Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi Ricardo,
>
> On 14-Nov-24 9:03 PM, Ricardo Ribalda wrote:
> > Hi Gergo
> >
> > Sorry, I forgot to reply to your comment in v14.
> >
> > On Thu, 14 Nov 2024 at 20:53, Gergo Koteles <soyer@irl.hu> wrote:
> >>
> >> Hi Ricardo,
> >>
> >> On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
> >>>
> >>> + },
> >>> + {
> >>> + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> >>> + .entity = UVC_GUID_UVC_CAMERA,
> >>> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> >>> + .size = 16,
> >>> + .offset = 64,
> >>> + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> >>> + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> >>> + .name = "Region Of Interest Auto Controls",
> >>> + },
> >>> };
> >>>
> >>
> >> Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
> >
> > If I create 8 Booleans, they will always be shown in the device. And
> > the user will not have a way to know which values are available and
> > which are not.
> >
> > We will also fail the v4l2-compliance test, because there will be up
> > to 7 boolean controls that will not be able to be set to 1, eventhough
> > they are writable.
>
> So why can't these other controls be set to 1? Because only one
> of the options in the bitmask can be selected at a time ?
>
> If only 1 bit in the UVC_CTRL_DATA_TYPE_BITMASK for this can be one
> at the time, then this should be mapped to a V4L2_CTRL_TYPE_MENU
> just like how that is done for V4L2_CID_EXPOSURE_AUTO already.
>
> Actually looking at existing comments about UVC_CTRL_DATA_TYPE_BITMASK
> in the driver there is this comment on top of uvc_mapping_get_menu_value()
>
> * For controls of type UVC_CTRL_DATA_TYPE_BITMASK, the UVC control value is
> * expressed as a bitmask and is thus guaranteed to have a single bit set.
>
> Assuming this "guaranteed to have a single bit set" comment is valid for
> the V4L2_CID_UVC_REGION_OF_INTEREST_AUTO part of UVC_CT_REGION_OF_INTEREST_CONTROL
> too then I think we should simply map this to a menu similar to how
> this is done for V4L2_CID_EXPOSURE_AUTO.
>
> Note V4L2_CID_EXPOSURE_AUTO is the only existing user of UVC_CTRL_DATA_TYPE_BITMASK
> at the moment.
>
> Mapping this to a menu should nicely address Gergo's concerns here.
The UVC standard is not very clear re bmAutoControls. It says:
"""
The bmAutoControls bitmask determines which, if any, on board features
should track to the region of interest. To detect if a device supports
a particular Auto Control, use GET_MAX which returns a mask indicating
all supported Auto Controls.
GET_CUR returns the current Region of Interest (RoI) being employed by
the device. This RoI should be the same as specified in most recent
SET_CUR except in the case where the ‘Auto Detect and Track’ and/or
‘Image Stabilization’ bit have been set.
"""
Which makes me believe that you can set another Auto value + one of
these ones. So I do not think that we can assume "guaranteed to have a
single bit set".
The behaviour will vary module to module. So I'd rather take a
conservative approach here and let the hardware clamp the value and
not us.
>
> Regards,
>
> Hans
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-18 16:16 ` Ricardo Ribalda Delgado
@ 2024-11-25 14:27 ` Hans de Goede
0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-11-25 14:27 UTC (permalink / raw)
To: Ricardo Ribalda Delgado
Cc: Ricardo Ribalda, Gergo Koteles, Laurent Pinchart,
Mauro Carvalho Chehab, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel, Yunke Cao
Hi Ricardo,
On 18-Nov-24 5:16 PM, Ricardo Ribalda Delgado wrote:
> Hi
>
> On Mon, Nov 18, 2024 at 4:59 PM Hans de Goede <hdegoede@redhat.com> wrote:
>>
>> Hi Ricardo,
>>
>> On 14-Nov-24 9:03 PM, Ricardo Ribalda wrote:
>>> Hi Gergo
>>>
>>> Sorry, I forgot to reply to your comment in v14.
>>>
>>> On Thu, 14 Nov 2024 at 20:53, Gergo Koteles <soyer@irl.hu> wrote:
>>>>
>>>> Hi Ricardo,
>>>>
>>>> On Thu, 2024-11-14 at 19:10 +0000, Ricardo Ribalda wrote:
>>>>>
>>>>> + },
>>>>> + {
>>>>> + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
>>>>> + .entity = UVC_GUID_UVC_CAMERA,
>>>>> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
>>>>> + .size = 16,
>>>>> + .offset = 64,
>>>>> + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
>>>>> + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
>>>>> + .name = "Region Of Interest Auto Controls",
>>>>> + },
>>>>> };
>>>>>
>>>>
>>>> Wouldn't be better to use 8 V4L2_CTRL_TYPE_BOOLEAN controls for this?
>>>
>>> If I create 8 Booleans, they will always be shown in the device. And
>>> the user will not have a way to know which values are available and
>>> which are not.
>>>
>>> We will also fail the v4l2-compliance test, because there will be up
>>> to 7 boolean controls that will not be able to be set to 1, eventhough
>>> they are writable.
>>
>> So why can't these other controls be set to 1? Because only one
>> of the options in the bitmask can be selected at a time ?
>>
>> If only 1 bit in the UVC_CTRL_DATA_TYPE_BITMASK for this can be one
>> at the time, then this should be mapped to a V4L2_CTRL_TYPE_MENU
>> just like how that is done for V4L2_CID_EXPOSURE_AUTO already.
>>
>> Actually looking at existing comments about UVC_CTRL_DATA_TYPE_BITMASK
>> in the driver there is this comment on top of uvc_mapping_get_menu_value()
>>
>> * For controls of type UVC_CTRL_DATA_TYPE_BITMASK, the UVC control value is
>> * expressed as a bitmask and is thus guaranteed to have a single bit set.
>>
>> Assuming this "guaranteed to have a single bit set" comment is valid for
>> the V4L2_CID_UVC_REGION_OF_INTEREST_AUTO part of UVC_CT_REGION_OF_INTEREST_CONTROL
>> too then I think we should simply map this to a menu similar to how
>> this is done for V4L2_CID_EXPOSURE_AUTO.
>>
>> Note V4L2_CID_EXPOSURE_AUTO is the only existing user of UVC_CTRL_DATA_TYPE_BITMASK
>> at the moment.
>>
>> Mapping this to a menu should nicely address Gergo's concerns here.
>
> The UVC standard is not very clear re bmAutoControls. It says:
> """
> The bmAutoControls bitmask determines which, if any, on board features
> should track to the region of interest. To detect if a device supports
> a particular Auto Control, use GET_MAX which returns a mask indicating
> all supported Auto Controls.
> GET_CUR returns the current Region of Interest (RoI) being employed by
> the device. This RoI should be the same as specified in most recent
> SET_CUR except in the case where the ‘Auto Detect and Track’ and/or
> ‘Image Stabilization’ bit have been set.
> """
>
> Which makes me believe that you can set another Auto value + one of
> these ones. So I do not think that we can assume "guaranteed to have a
> single bit set".
I see I already was afraid it would be something like this but
it would have been nice if we could have turned this into a menu control.
> The behaviour will vary module to module. So I'd rather take a
> conservative approach here and let the hardware clamp the value and
> not us.
Agreed.
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 05/19] media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value
2024-11-14 19:10 ` [PATCH v15 05/19] media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value Ricardo Ribalda
@ 2024-11-25 15:50 ` Hans de Goede
0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-11-25 15:50 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> map->get() gets a value from an uvc_control in "UVC format" and converts
> it to a value that can be consumed by v4l2.
>
> Instead of using a special get function for V4L2_CTRL_TYPE_MENU, we
> were converting from uvc_get_le_value in two different places.
>
> Move the conversion to uvc_get_le_value().
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 77 +++++++++++++++++-----------------------
> 1 file changed, 32 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index bab9fdac98e6..77f7058ec966 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -862,6 +862,25 @@ static inline void uvc_clear_bit(u8 *data, int bit)
> data[bit >> 3] &= ~(1 << (bit & 7));
> }
>
> +static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val)
> +{
> + unsigned int i;
> +
> + for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
> + u32 menu_value;
> +
> + if (!test_bit(i, &mapping->menu_mask))
> + continue;
> +
> + menu_value = uvc_mapping_get_menu_value(mapping, i);
> +
> + if (menu_value == val)
> + return i;
> + }
> +
> + return val;
> +}
> +
> /*
> * Extract the bit string specified by mapping->offset and mapping->size
> * from the little-endian data stored at 'data' and return the result as
> @@ -896,6 +915,16 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
> if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
> value |= -(value & (1 << (mapping->size - 1)));
>
> + /* If it is a menu, convert from uvc to v4l2. */
> + if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
> + return value;
> +
> + switch (query) {
> + case UVC_GET_CUR:
> + case UVC_GET_DEF:
> + return uvc_menu_to_v4l2_menu(mapping, value);
> + }
> +
> return value;
> }
>
> @@ -1060,32 +1089,6 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
> return 0;
> }
>
> -static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping,
> - const u8 *data)
> -{
> - s32 value = mapping->get(mapping, UVC_GET_CUR, data);
> -
> - if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
> - unsigned int i;
> -
> - for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
> - u32 menu_value;
> -
> - if (!test_bit(i, &mapping->menu_mask))
> - continue;
> -
> - menu_value = uvc_mapping_get_menu_value(mapping, i);
> -
> - if (menu_value == value) {
> - value = i;
> - break;
> - }
> - }
> - }
> -
> - return value;
> -}
> -
> static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
> struct uvc_control *ctrl)
> {
> @@ -1136,8 +1139,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
> if (ret < 0)
> return ret;
>
> - *value = __uvc_ctrl_get_value(mapping,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> + *value = mapping->get(mapping, UVC_GET_CUR,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
>
> return 0;
> }
> @@ -1287,7 +1290,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> {
> struct uvc_control_mapping *master_map = NULL;
> struct uvc_control *master_ctrl = NULL;
> - unsigned int i;
>
> memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> v4l2_ctrl->id = mapping->id;
> @@ -1330,21 +1332,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1;
> v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1;
> v4l2_ctrl->step = 1;
> -
> - for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
> - u32 menu_value;
> -
> - if (!test_bit(i, &mapping->menu_mask))
> - continue;
> -
> - menu_value = uvc_mapping_get_menu_value(mapping, i);
> -
> - if (menu_value == v4l2_ctrl->default_value) {
> - v4l2_ctrl->default_value = i;
> - break;
> - }
> - }
> -
> return 0;
>
> case V4L2_CTRL_TYPE_BOOLEAN:
> @@ -1592,7 +1579,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
> ctrl->handle = NULL;
>
> list_for_each_entry(mapping, &ctrl->info.mappings, list) {
> - s32 value = __uvc_ctrl_get_value(mapping, data);
> + s32 value = mapping->get(mapping, UVC_GET_CUR, data);
>
> /*
> * handle may be NULL here if the device sends auto-update
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 06/19] media: uvcvideo: Handle uvc menu translation inside uvc_set_le_value
2024-11-14 19:10 ` [PATCH v15 06/19] media: uvcvideo: Handle uvc menu translation inside uvc_set_le_value Ricardo Ribalda
@ 2024-11-25 15:58 ` Hans de Goede
0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-11-25 15:58 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> Be consistent with uvc_get_le_value() and do the menu translation there.
>
> Note that in this case, the refactor does not provide much... but
> consistency is a nice feature.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 10 ++++++----
> 1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 77f7058ec966..c975e0ab479b 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -939,6 +939,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
> int offset = mapping->offset;
> u8 mask;
>
> + if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU)
> + value = uvc_mapping_get_menu_value(mapping, value);
> /*
> * According to the v4l2 spec, writing any value to a button control
> * should result in the action belonging to the button control being
There is a:
if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON)
below this comment block, maybe put the if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) below
that as "else if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON) ... "
Or maybe make this a switch-case on mapping->v4l2_type right away for future
special handling of other types ?
Otherwise this looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> @@ -1988,23 +1990,23 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> if (!test_bit(xctrl->value, &mapping->menu_mask))
> return -EINVAL;
>
> - value = uvc_mapping_get_menu_value(mapping, xctrl->value);
> -
> /*
> * Valid menu indices are reported by the GET_RES request for
> * UVC controls that support it.
> */
> if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) {
> + int val = uvc_mapping_get_menu_value(mapping,
> + xctrl->value);
> if (!ctrl->cached) {
> ret = uvc_ctrl_populate_cache(chain, ctrl);
> if (ret < 0)
> return ret;
> }
>
> - if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & value))
> + if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & val))
> return -EINVAL;
> }
> -
> + value = xctrl->value;
> break;
>
> default:
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 07/19] media: uvcvideo: refactor uvc_ioctl_g_ext_ctrls
2024-11-14 19:10 ` [PATCH v15 07/19] media: uvcvideo: refactor uvc_ioctl_g_ext_ctrls Ricardo Ribalda
@ 2024-11-25 16:01 ` Hans de Goede
0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-11-25 16:01 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> We want to support fetching the min and max values with g_ext_ctrls,
> this patch is a preparation for that.
>
> Instead of abusing uvc_query_v4l2_ctrl(), add an extra parameter to
> uvc_ctrl_get, so it can support fetching the default value.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 21 ++++++++++++++++++---
> drivers/media/usb/uvc/uvc_v4l2.c | 28 +++++++++++-----------------
> drivers/media/usb/uvc/uvcvideo.h | 3 ++-
> 3 files changed, 31 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index c975e0ab479b..d6afa131a5e1 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1902,8 +1902,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> return ret;
> }
>
> -int uvc_ctrl_get(struct uvc_video_chain *chain,
> - struct v4l2_ext_control *xctrl)
> +int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> + struct v4l2_ext_control *xctrl)
> {
> struct uvc_control *ctrl;
> struct uvc_control_mapping *mapping;
> @@ -1915,7 +1915,22 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
> if (ctrl == NULL)
> return -EINVAL;
>
> - return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
> + switch (which) {
> + case V4L2_CTRL_WHICH_CUR_VAL:
> + return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
> + case V4L2_CTRL_WHICH_DEF_VAL:
> + if (!ctrl->cached) {
> + int ret = uvc_ctrl_populate_cache(chain, ctrl);
> +
> + if (ret < 0)
> + return ret;
> + }
> + xctrl->value = mapping->get(mapping, UVC_GET_DEF,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> + return 0;
> + }
> +
> + return -EINVAL;
> }
>
> int uvc_ctrl_set(struct uvc_fh *handle,
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 97c5407f6603..02fd5cbc3474 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1078,34 +1078,28 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
> struct uvc_video_chain *chain = handle->chain;
> struct v4l2_ext_control *ctrl = ctrls->controls;
> unsigned int i;
> + u32 which;
> int ret;
>
> + switch (ctrls->which) {
> + case V4L2_CTRL_WHICH_DEF_VAL:
> + case V4L2_CTRL_WHICH_CUR_VAL:
> + which = ctrls->which;
> + break;
> + default:
> + which = V4L2_CTRL_WHICH_CUR_VAL;
> + }
> +
> ret = uvc_ctrl_check_access(chain, ctrls, VIDIOC_G_EXT_CTRLS);
> if (ret < 0)
> return ret;
>
> - if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
> - for (i = 0; i < ctrls->count; ++ctrl, ++i) {
> - struct v4l2_queryctrl qc = { .id = ctrl->id };
> -
> - ret = uvc_query_v4l2_ctrl(chain, &qc);
> - if (ret < 0) {
> - ctrls->error_idx = i;
> - return ret;
> - }
> -
> - ctrl->value = qc.default_value;
> - }
> -
> - return 0;
> - }
> -
> ret = uvc_ctrl_begin(chain);
> if (ret < 0)
> return ret;
>
> for (i = 0; i < ctrls->count; ++ctrl, ++i) {
> - ret = uvc_ctrl_get(chain, ctrl);
> + ret = uvc_ctrl_get(chain, which, ctrl);
> if (ret < 0) {
> uvc_ctrl_rollback(handle);
> ctrls->error_idx = i;
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 07f9921d83f2..6ebaabd11443 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -788,7 +788,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
> return __uvc_ctrl_commit(handle, 1, NULL);
> }
>
> -int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
> +int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> + struct v4l2_ext_control *xctrl);
> int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
> int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
> const struct v4l2_ext_controls *ctrls,
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 08/19] media: uvcvideo: uvc_ioctl_(g|s)_ext_ctrls: handle NoP case
2024-11-14 19:10 ` [PATCH v15 08/19] media: uvcvideo: uvc_ioctl_(g|s)_ext_ctrls: handle NoP case Ricardo Ribalda
@ 2024-11-25 16:01 ` Hans de Goede
0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-11-25 16:01 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> If nothing needs to be done. Exit early.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_v4l2.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 02fd5cbc3474..65dbb53b1e75 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1081,6 +1081,9 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
> u32 which;
> int ret;
>
> + if (!ctrls->count)
> + return 0;
> +
> switch (ctrls->which) {
> case V4L2_CTRL_WHICH_DEF_VAL:
> case V4L2_CTRL_WHICH_CUR_VAL:
> @@ -1121,6 +1124,9 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
> unsigned int i;
> int ret;
>
> + if (!ctrls->count)
> + return 0;
> +
> ret = uvc_ctrl_check_access(chain, ctrls, ioctl);
> if (ret < 0)
> return ret;
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map
2024-11-14 19:10 ` [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map Ricardo Ribalda
@ 2024-11-29 8:15 ` Ricardo Ribalda
2024-12-09 14:11 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-11-29 8:15 UTC (permalink / raw)
To: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
On Thu, 14 Nov 2024 at 20:11, Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> Do not process unknown data types.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_v4l2.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 5000c74271e0..4c88dab15554 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -106,6 +106,12 @@ static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain,
> struct uvc_control_mapping *map;
> int ret;
>
> + if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) {
> + uvc_dbg(chain->dev, CONTROL,
> + "Unsupported UVC data type %u\n", xmap->data_type);
> + return -ENOTTY;
This should probably be -EINVAL
I am fixing it on the next version
> + }
> +
> map = kzalloc(sizeof(*map), GFP_KERNEL);
> if (map == NULL)
> return -ENOMEM;
>
> --
> 2.47.0.338.g60cca15819-goog
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 19:10 ` [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI Ricardo Ribalda
2024-11-14 19:53 ` Gergo Koteles
@ 2024-12-02 8:02 ` Yunke Cao
2024-12-02 9:26 ` Ricardo Ribalda
2024-12-09 14:22 ` Hans de Goede
2 siblings, 1 reply; 62+ messages in thread
From: Yunke Cao @ 2024-12-02 8:02 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel
Hi Ricardo,
Thanks for the new version!!
On Fri, Nov 15, 2024 at 4:11 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> From: Yunke Cao <yunkec@google.com>
>
> Implement support for ROI as described in UVC 1.5:
> 4.2.2.1.20 Digital Region of Interest (ROI) Control
>
> ROI control is implemented using V4L2 control API as
> two UVC-specific controls:
> V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
> V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
>
> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> Signed-off-by: Yunke Cao <yunkec@google.com>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++++++++++++++++++++
> drivers/media/usb/uvc/uvcvideo.h | 7 ++++
> include/uapi/linux/usb/video.h | 1 +
> include/uapi/linux/uvcvideo.h | 13 ++++++
> include/uapi/linux/v4l2-controls.h | 9 +++++
> 5 files changed, 111 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index f262e05ad3a8..5b619ef40dd3 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -358,6 +358,24 @@ static const struct uvc_control_info uvc_ctrls[] = {
> .flags = UVC_CTRL_FLAG_GET_CUR
> | UVC_CTRL_FLAG_AUTO_UPDATE,
> },
> + /*
> + * UVC_CTRL_FLAG_AUTO_UPDATE is needed because the RoI may get updated
> + * by sensors.
> + * "This RoI should be the same as specified in most recent SET_CUR
> + * except in the case where the ‘Auto Detect and Track’ and/or
> + * ‘Image Stabilization’ bit have been set."
> + * 4.2.2.1.20 Digital Region of Interest (ROI) Control
> + */
> + {
> + .entity = UVC_GUID_UVC_CAMERA,
> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> + .index = 21,
> + .size = 10,
> + .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
> + | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> + | UVC_CTRL_FLAG_GET_DEF
> + | UVC_CTRL_FLAG_AUTO_UPDATE,
> + },
> };
>
> static const u32 uvc_control_classes[] = {
> @@ -603,6 +621,44 @@ static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
> return out_mapping;
> }
>
> +static int uvc_get_rect(struct uvc_control_mapping *mapping, u8 query,
> + const void *uvc_in, size_t v4l2_size, void *v4l2_out)
> +{
> + const struct uvc_rect *uvc_rect = uvc_in;
> + struct v4l2_rect *v4l2_rect = v4l2_out;
> +
> + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> + return -EINVAL;
> +
> + if (uvc_rect->left > uvc_rect->right ||
> + uvc_rect->top > uvc_rect->bottom)
> + return -EIO;
> +
> + v4l2_rect->top = uvc_rect->top;
> + v4l2_rect->left = uvc_rect->left;
> + v4l2_rect->height = uvc_rect->bottom - uvc_rect->top + 1;
> + v4l2_rect->width = uvc_rect->right - uvc_rect->left + 1;
> +
> + return 0;
> +}
> +
> +static int uvc_set_rect(struct uvc_control_mapping *mapping, size_t v4l2_size,
> + const void *v4l2_in, void *uvc_out)
> +{
> + struct uvc_rect *uvc_rect = uvc_out;
> + const struct v4l2_rect *v4l2_rect = v4l2_in;
> +
> + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> + return -EINVAL;
> +
> + uvc_rect->top = max(0xffff, v4l2_rect->top);
> + uvc_rect->left = max(0xffff, v4l2_rect->left);
> + uvc_rect->bottom = max(0xffff, v4l2_rect->height + v4l2_rect->top - 1);
> + uvc_rect->right = max(0xffff, v4l2_rect->width + v4l2_rect->left - 1);
Should these be min()?
>
> +
> + return 0;
> +}
> +
> static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> {
> .id = V4L2_CID_BRIGHTNESS,
> @@ -897,6 +953,28 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
> .filter_mapping = uvc_ctrl_filter_plf_mapping,
> },
> + {
> + .id = V4L2_CID_UVC_REGION_OF_INTEREST_RECT,
> + .entity = UVC_GUID_UVC_CAMERA,
> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> + .size = sizeof(struct uvc_rect) * 8,
> + .offset = 0,
> + .v4l2_type = V4L2_CTRL_TYPE_RECT,
> + .data_type = UVC_CTRL_DATA_TYPE_RECT,
> + .get = uvc_get_rect,
> + .set = uvc_set_rect,
> + .name = "Region Of Interest Rectangle",
> + },
> + {
> + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> + .entity = UVC_GUID_UVC_CAMERA,
> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> + .size = 16,
> + .offset = 64,
> + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> + .name = "Region Of Interest Auto Controls",
> + },
> };
>
> /* ------------------------------------------------------------------------
> @@ -1465,6 +1543,9 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
>
> static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
> {
> + if (mapping->v4l2_type == V4L2_CTRL_TYPE_RECT)
> + return sizeof(struct v4l2_rect);
> +
> if (uvc_ctrl_mapping_is_compound(mapping))
> return DIV_ROUND_UP(mapping->size, 8);
>
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 8aca1a2fe587..d910a5e5b514 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -294,6 +294,13 @@ struct uvc_streaming_header {
> u8 bTriggerUsage;
> };
>
> +struct uvc_rect {
> + u16 top;
> + u16 left;
> + u16 bottom;
> + u16 right;
> +} __packed;
> +
> enum uvc_buffer_state {
> UVC_BUF_STATE_IDLE = 0,
> UVC_BUF_STATE_QUEUED = 1,
> diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
> index 2ff0e8a3a683..2afb4420e6c4 100644
> --- a/include/uapi/linux/usb/video.h
> +++ b/include/uapi/linux/usb/video.h
> @@ -104,6 +104,7 @@
> #define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f
> #define UVC_CT_ROLL_RELATIVE_CONTROL 0x10
> #define UVC_CT_PRIVACY_CONTROL 0x11
> +#define UVC_CT_REGION_OF_INTEREST_CONTROL 0x14
>
> /* A.9.5. Processing Unit Control Selectors */
> #define UVC_PU_CONTROL_UNDEFINED 0x00
> diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> index f86185456dc5..cbe15bca9569 100644
> --- a/include/uapi/linux/uvcvideo.h
> +++ b/include/uapi/linux/uvcvideo.h
> @@ -16,6 +16,7 @@
> #define UVC_CTRL_DATA_TYPE_BOOLEAN 3
> #define UVC_CTRL_DATA_TYPE_ENUM 4
> #define UVC_CTRL_DATA_TYPE_BITMASK 5
> +#define UVC_CTRL_DATA_TYPE_RECT 6
>
> /* Control flags */
> #define UVC_CTRL_FLAG_SET_CUR (1 << 0)
> @@ -38,6 +39,18 @@
>
> #define UVC_MENU_NAME_LEN 32
>
> +/* V4L2 driver-specific controls */
> +#define V4L2_CID_UVC_REGION_OF_INTEREST_RECT (V4L2_CID_USER_UVC_BASE + 1)
> +#define V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (V4L2_CID_USER_UVC_BASE + 2)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE (1 << 0)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS (1 << 1)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE (1 << 2)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS (1 << 3)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT (1 << 4)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK (1 << 5)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION (1 << 6)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY (1 << 7)
> +
> struct uvc_menu_info {
> __u32 value;
> __u8 name[UVC_MENU_NAME_LEN];
> diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
> index 974fd254e573..6c91d6fa4708 100644
> --- a/include/uapi/linux/v4l2-controls.h
> +++ b/include/uapi/linux/v4l2-controls.h
> @@ -215,6 +215,13 @@ enum v4l2_colorfx {
> */
> #define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0)
>
> +/*
> + * The base for the uvc driver controls.
> + * See linux/uvcvideo.h for the list of controls.
> + * We reserve 64 controls for this driver.
> + */
> +#define V4L2_CID_USER_UVC_BASE (V4L2_CID_USER_BASE + 0x11e0)
> +
> /* MPEG-class control IDs */
> /* The MPEG controls are applicable to all codec controls
> * and the 'MPEG' part of the define is historical */
> @@ -1089,6 +1096,8 @@ enum v4l2_auto_focus_range {
>
> #define V4L2_CID_HDR_SENSOR_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
>
> +/* CAMERA-class private control IDs */
> +
Do we still need this comment?
Best,
Yunke
> /* FM Modulator class control IDs */
>
> #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
>
> --
> 2.47.0.338.g60cca15819-goog
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-12-02 8:02 ` Yunke Cao
@ 2024-12-02 9:26 ` Ricardo Ribalda
2024-12-06 7:50 ` Yunke Cao
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-12-02 9:26 UTC (permalink / raw)
To: Yunke Cao
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, Yunke Cao,
linux-media, linux-kernel
On Mon, 2 Dec 2024 at 09:02, Yunke Cao <yunkec@google.com> wrote:
>
> Hi Ricardo,
>
> Thanks for the new version!!
>
> On Fri, Nov 15, 2024 at 4:11 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
> >
> > From: Yunke Cao <yunkec@google.com>
> >
> > Implement support for ROI as described in UVC 1.5:
> > 4.2.2.1.20 Digital Region of Interest (ROI) Control
> >
> > ROI control is implemented using V4L2 control API as
> > two UVC-specific controls:
> > V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
> > V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
> >
> > Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> > Signed-off-by: Yunke Cao <yunkec@google.com>
> > ---
> > drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++++++++++++++++++++
> > drivers/media/usb/uvc/uvcvideo.h | 7 ++++
> > include/uapi/linux/usb/video.h | 1 +
> > include/uapi/linux/uvcvideo.h | 13 ++++++
> > include/uapi/linux/v4l2-controls.h | 9 +++++
> > 5 files changed, 111 insertions(+)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index f262e05ad3a8..5b619ef40dd3 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -358,6 +358,24 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > .flags = UVC_CTRL_FLAG_GET_CUR
> > | UVC_CTRL_FLAG_AUTO_UPDATE,
> > },
> > + /*
> > + * UVC_CTRL_FLAG_AUTO_UPDATE is needed because the RoI may get updated
> > + * by sensors.
> > + * "This RoI should be the same as specified in most recent SET_CUR
> > + * except in the case where the ‘Auto Detect and Track’ and/or
> > + * ‘Image Stabilization’ bit have been set."
> > + * 4.2.2.1.20 Digital Region of Interest (ROI) Control
> > + */
> > + {
> > + .entity = UVC_GUID_UVC_CAMERA,
> > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > + .index = 21,
> > + .size = 10,
> > + .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
> > + | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> > + | UVC_CTRL_FLAG_GET_DEF
> > + | UVC_CTRL_FLAG_AUTO_UPDATE,
> > + },
> > };
> >
> > static const u32 uvc_control_classes[] = {
> > @@ -603,6 +621,44 @@ static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
> > return out_mapping;
> > }
> >
> > +static int uvc_get_rect(struct uvc_control_mapping *mapping, u8 query,
> > + const void *uvc_in, size_t v4l2_size, void *v4l2_out)
> > +{
> > + const struct uvc_rect *uvc_rect = uvc_in;
> > + struct v4l2_rect *v4l2_rect = v4l2_out;
> > +
> > + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> > + return -EINVAL;
> > +
> > + if (uvc_rect->left > uvc_rect->right ||
> > + uvc_rect->top > uvc_rect->bottom)
> > + return -EIO;
> > +
> > + v4l2_rect->top = uvc_rect->top;
> > + v4l2_rect->left = uvc_rect->left;
> > + v4l2_rect->height = uvc_rect->bottom - uvc_rect->top + 1;
> > + v4l2_rect->width = uvc_rect->right - uvc_rect->left + 1;
> > +
> > + return 0;
> > +}
> > +
> > +static int uvc_set_rect(struct uvc_control_mapping *mapping, size_t v4l2_size,
> > + const void *v4l2_in, void *uvc_out)
> > +{
> > + struct uvc_rect *uvc_rect = uvc_out;
> > + const struct v4l2_rect *v4l2_rect = v4l2_in;
> > +
> > + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> > + return -EINVAL;
> > +
> > + uvc_rect->top = max(0xffff, v4l2_rect->top);
> > + uvc_rect->left = max(0xffff, v4l2_rect->left);
> > + uvc_rect->bottom = max(0xffff, v4l2_rect->height + v4l2_rect->top - 1);
> > + uvc_rect->right = max(0xffff, v4l2_rect->width + v4l2_rect->left - 1);
>
> Should these be min()?
Ups :).
Fixed in the next version.
Thanks!
>
> >
> > +
> > + return 0;
> > +}
> > +
> > static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > {
> > .id = V4L2_CID_BRIGHTNESS,
> > @@ -897,6 +953,28 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
> > .filter_mapping = uvc_ctrl_filter_plf_mapping,
> > },
> > + {
> > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_RECT,
> > + .entity = UVC_GUID_UVC_CAMERA,
> > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > + .size = sizeof(struct uvc_rect) * 8,
> > + .offset = 0,
> > + .v4l2_type = V4L2_CTRL_TYPE_RECT,
> > + .data_type = UVC_CTRL_DATA_TYPE_RECT,
> > + .get = uvc_get_rect,
> > + .set = uvc_set_rect,
> > + .name = "Region Of Interest Rectangle",
> > + },
> > + {
> > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> > + .entity = UVC_GUID_UVC_CAMERA,
> > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > + .size = 16,
> > + .offset = 64,
> > + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> > + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > + .name = "Region Of Interest Auto Controls",
> > + },
> > };
> >
> > /* ------------------------------------------------------------------------
> > @@ -1465,6 +1543,9 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> >
> > static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
> > {
> > + if (mapping->v4l2_type == V4L2_CTRL_TYPE_RECT)
> > + return sizeof(struct v4l2_rect);
> > +
> > if (uvc_ctrl_mapping_is_compound(mapping))
> > return DIV_ROUND_UP(mapping->size, 8);
> >
> > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > index 8aca1a2fe587..d910a5e5b514 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -294,6 +294,13 @@ struct uvc_streaming_header {
> > u8 bTriggerUsage;
> > };
> >
> > +struct uvc_rect {
> > + u16 top;
> > + u16 left;
> > + u16 bottom;
> > + u16 right;
> > +} __packed;
> > +
> > enum uvc_buffer_state {
> > UVC_BUF_STATE_IDLE = 0,
> > UVC_BUF_STATE_QUEUED = 1,
> > diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
> > index 2ff0e8a3a683..2afb4420e6c4 100644
> > --- a/include/uapi/linux/usb/video.h
> > +++ b/include/uapi/linux/usb/video.h
> > @@ -104,6 +104,7 @@
> > #define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f
> > #define UVC_CT_ROLL_RELATIVE_CONTROL 0x10
> > #define UVC_CT_PRIVACY_CONTROL 0x11
> > +#define UVC_CT_REGION_OF_INTEREST_CONTROL 0x14
> >
> > /* A.9.5. Processing Unit Control Selectors */
> > #define UVC_PU_CONTROL_UNDEFINED 0x00
> > diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> > index f86185456dc5..cbe15bca9569 100644
> > --- a/include/uapi/linux/uvcvideo.h
> > +++ b/include/uapi/linux/uvcvideo.h
> > @@ -16,6 +16,7 @@
> > #define UVC_CTRL_DATA_TYPE_BOOLEAN 3
> > #define UVC_CTRL_DATA_TYPE_ENUM 4
> > #define UVC_CTRL_DATA_TYPE_BITMASK 5
> > +#define UVC_CTRL_DATA_TYPE_RECT 6
> >
> > /* Control flags */
> > #define UVC_CTRL_FLAG_SET_CUR (1 << 0)
> > @@ -38,6 +39,18 @@
> >
> > #define UVC_MENU_NAME_LEN 32
> >
> > +/* V4L2 driver-specific controls */
> > +#define V4L2_CID_UVC_REGION_OF_INTEREST_RECT (V4L2_CID_USER_UVC_BASE + 1)
> > +#define V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (V4L2_CID_USER_UVC_BASE + 2)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE (1 << 0)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS (1 << 1)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE (1 << 2)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS (1 << 3)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT (1 << 4)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK (1 << 5)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION (1 << 6)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY (1 << 7)
> > +
> > struct uvc_menu_info {
> > __u32 value;
> > __u8 name[UVC_MENU_NAME_LEN];
> > diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
> > index 974fd254e573..6c91d6fa4708 100644
> > --- a/include/uapi/linux/v4l2-controls.h
> > +++ b/include/uapi/linux/v4l2-controls.h
> > @@ -215,6 +215,13 @@ enum v4l2_colorfx {
> > */
> > #define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0)
> >
> > +/*
> > + * The base for the uvc driver controls.
> > + * See linux/uvcvideo.h for the list of controls.
> > + * We reserve 64 controls for this driver.
> > + */
> > +#define V4L2_CID_USER_UVC_BASE (V4L2_CID_USER_BASE + 0x11e0)
> > +
> > /* MPEG-class control IDs */
> > /* The MPEG controls are applicable to all codec controls
> > * and the 'MPEG' part of the define is historical */
> > @@ -1089,6 +1096,8 @@ enum v4l2_auto_focus_range {
> >
> > #define V4L2_CID_HDR_SENSOR_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
> >
> > +/* CAMERA-class private control IDs */
> > +
>
> Do we still need this comment?
>
> Best,
> Yunke
>
> > /* FM Modulator class control IDs */
> >
> > #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
> >
> > --
> > 2.47.0.338.g60cca15819-goog
> >
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-12-02 9:26 ` Ricardo Ribalda
@ 2024-12-06 7:50 ` Yunke Cao
0 siblings, 0 replies; 62+ messages in thread
From: Yunke Cao @ 2024-12-06 7:50 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Yunke Cao, Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, linux-media,
linux-kernel
On Mon, Dec 2, 2024 at 6:26 PM Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> On Mon, 2 Dec 2024 at 09:02, Yunke Cao <yunkec@google.com> wrote:
> >
> > Hi Ricardo,
> >
> > Thanks for the new version!!
> >
> > On Fri, Nov 15, 2024 at 4:11 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
> > >
> > > From: Yunke Cao <yunkec@google.com>
> > >
> > > Implement support for ROI as described in UVC 1.5:
> > > 4.2.2.1.20 Digital Region of Interest (ROI) Control
> > >
> > > ROI control is implemented using V4L2 control API as
> > > two UVC-specific controls:
> > > V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
> > > V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
> > >
> > > Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> > > Signed-off-by: Yunke Cao <yunkec@google.com>
> > > ---
> > > drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++++++++++++++++++++
> > > drivers/media/usb/uvc/uvcvideo.h | 7 ++++
> > > include/uapi/linux/usb/video.h | 1 +
> > > include/uapi/linux/uvcvideo.h | 13 ++++++
> > > include/uapi/linux/v4l2-controls.h | 9 +++++
> > > 5 files changed, 111 insertions(+)
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > index f262e05ad3a8..5b619ef40dd3 100644
> > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > @@ -358,6 +358,24 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > > .flags = UVC_CTRL_FLAG_GET_CUR
> > > | UVC_CTRL_FLAG_AUTO_UPDATE,
> > > },
> > > + /*
> > > + * UVC_CTRL_FLAG_AUTO_UPDATE is needed because the RoI may get updated
> > > + * by sensors.
> > > + * "This RoI should be the same as specified in most recent SET_CUR
> > > + * except in the case where the ‘Auto Detect and Track’ and/or
> > > + * ‘Image Stabilization’ bit have been set."
> > > + * 4.2.2.1.20 Digital Region of Interest (ROI) Control
> > > + */
> > > + {
> > > + .entity = UVC_GUID_UVC_CAMERA,
> > > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > > + .index = 21,
> > > + .size = 10,
> > > + .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
> > > + | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> > > + | UVC_CTRL_FLAG_GET_DEF
> > > + | UVC_CTRL_FLAG_AUTO_UPDATE,
> > > + },
> > > };
> > >
> > > static const u32 uvc_control_classes[] = {
> > > @@ -603,6 +621,44 @@ static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
> > > return out_mapping;
> > > }
> > >
> > > +static int uvc_get_rect(struct uvc_control_mapping *mapping, u8 query,
> > > + const void *uvc_in, size_t v4l2_size, void *v4l2_out)
> > > +{
> > > + const struct uvc_rect *uvc_rect = uvc_in;
> > > + struct v4l2_rect *v4l2_rect = v4l2_out;
> > > +
> > > + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> > > + return -EINVAL;
> > > +
> > > + if (uvc_rect->left > uvc_rect->right ||
> > > + uvc_rect->top > uvc_rect->bottom)
> > > + return -EIO;
> > > +
> > > + v4l2_rect->top = uvc_rect->top;
> > > + v4l2_rect->left = uvc_rect->left;
> > > + v4l2_rect->height = uvc_rect->bottom - uvc_rect->top + 1;
> > > + v4l2_rect->width = uvc_rect->right - uvc_rect->left + 1;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int uvc_set_rect(struct uvc_control_mapping *mapping, size_t v4l2_size,
> > > + const void *v4l2_in, void *uvc_out)
> > > +{
> > > + struct uvc_rect *uvc_rect = uvc_out;
> > > + const struct v4l2_rect *v4l2_rect = v4l2_in;
> > > +
> > > + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> > > + return -EINVAL;
> > > +
> > > + uvc_rect->top = max(0xffff, v4l2_rect->top);
> > > + uvc_rect->left = max(0xffff, v4l2_rect->left);
> > > + uvc_rect->bottom = max(0xffff, v4l2_rect->height + v4l2_rect->top - 1);
> > > + uvc_rect->right = max(0xffff, v4l2_rect->width + v4l2_rect->left - 1);
> >
> > Should these be min()?
>
> Ups :).
>
> Fixed in the next version.
>
> Thanks!
I've tested the patchset with this fix on Chrome OS and verified ROI
works as expected.
Reviewed-by: Yunke Cao <yunkec@google.com>
Tested-by: Yunke Cao <yunkec@google.com>
>
> >
> > >
> > > +
> > > + return 0;
> > > +}
> > > +
> > > static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > > {
> > > .id = V4L2_CID_BRIGHTNESS,
> > > @@ -897,6 +953,28 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > > .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
> > > .filter_mapping = uvc_ctrl_filter_plf_mapping,
> > > },
> > > + {
> > > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_RECT,
> > > + .entity = UVC_GUID_UVC_CAMERA,
> > > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > > + .size = sizeof(struct uvc_rect) * 8,
> > > + .offset = 0,
> > > + .v4l2_type = V4L2_CTRL_TYPE_RECT,
> > > + .data_type = UVC_CTRL_DATA_TYPE_RECT,
> > > + .get = uvc_get_rect,
> > > + .set = uvc_set_rect,
> > > + .name = "Region Of Interest Rectangle",
> > > + },
> > > + {
> > > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> > > + .entity = UVC_GUID_UVC_CAMERA,
> > > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > > + .size = 16,
> > > + .offset = 64,
> > > + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> > > + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > > + .name = "Region Of Interest Auto Controls",
> > > + },
> > > };
> > >
> > > /* ------------------------------------------------------------------------
> > > @@ -1465,6 +1543,9 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> > >
> > > static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
> > > {
> > > + if (mapping->v4l2_type == V4L2_CTRL_TYPE_RECT)
> > > + return sizeof(struct v4l2_rect);
> > > +
> > > if (uvc_ctrl_mapping_is_compound(mapping))
> > > return DIV_ROUND_UP(mapping->size, 8);
> > >
> > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > index 8aca1a2fe587..d910a5e5b514 100644
> > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > @@ -294,6 +294,13 @@ struct uvc_streaming_header {
> > > u8 bTriggerUsage;
> > > };
> > >
> > > +struct uvc_rect {
> > > + u16 top;
> > > + u16 left;
> > > + u16 bottom;
> > > + u16 right;
> > > +} __packed;
> > > +
> > > enum uvc_buffer_state {
> > > UVC_BUF_STATE_IDLE = 0,
> > > UVC_BUF_STATE_QUEUED = 1,
> > > diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
> > > index 2ff0e8a3a683..2afb4420e6c4 100644
> > > --- a/include/uapi/linux/usb/video.h
> > > +++ b/include/uapi/linux/usb/video.h
> > > @@ -104,6 +104,7 @@
> > > #define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f
> > > #define UVC_CT_ROLL_RELATIVE_CONTROL 0x10
> > > #define UVC_CT_PRIVACY_CONTROL 0x11
> > > +#define UVC_CT_REGION_OF_INTEREST_CONTROL 0x14
> > >
> > > /* A.9.5. Processing Unit Control Selectors */
> > > #define UVC_PU_CONTROL_UNDEFINED 0x00
> > > diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> > > index f86185456dc5..cbe15bca9569 100644
> > > --- a/include/uapi/linux/uvcvideo.h
> > > +++ b/include/uapi/linux/uvcvideo.h
> > > @@ -16,6 +16,7 @@
> > > #define UVC_CTRL_DATA_TYPE_BOOLEAN 3
> > > #define UVC_CTRL_DATA_TYPE_ENUM 4
> > > #define UVC_CTRL_DATA_TYPE_BITMASK 5
> > > +#define UVC_CTRL_DATA_TYPE_RECT 6
> > >
> > > /* Control flags */
> > > #define UVC_CTRL_FLAG_SET_CUR (1 << 0)
> > > @@ -38,6 +39,18 @@
> > >
> > > #define UVC_MENU_NAME_LEN 32
> > >
> > > +/* V4L2 driver-specific controls */
> > > +#define V4L2_CID_UVC_REGION_OF_INTEREST_RECT (V4L2_CID_USER_UVC_BASE + 1)
> > > +#define V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (V4L2_CID_USER_UVC_BASE + 2)
> > > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE (1 << 0)
> > > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS (1 << 1)
> > > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE (1 << 2)
> > > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS (1 << 3)
> > > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT (1 << 4)
> > > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK (1 << 5)
> > > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION (1 << 6)
> > > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY (1 << 7)
> > > +
> > > struct uvc_menu_info {
> > > __u32 value;
> > > __u8 name[UVC_MENU_NAME_LEN];
> > > diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
> > > index 974fd254e573..6c91d6fa4708 100644
> > > --- a/include/uapi/linux/v4l2-controls.h
> > > +++ b/include/uapi/linux/v4l2-controls.h
> > > @@ -215,6 +215,13 @@ enum v4l2_colorfx {
> > > */
> > > #define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0)
> > >
> > > +/*
> > > + * The base for the uvc driver controls.
> > > + * See linux/uvcvideo.h for the list of controls.
> > > + * We reserve 64 controls for this driver.
> > > + */
> > > +#define V4L2_CID_USER_UVC_BASE (V4L2_CID_USER_BASE + 0x11e0)
> > > +
> > > /* MPEG-class control IDs */
> > > /* The MPEG controls are applicable to all codec controls
> > > * and the 'MPEG' part of the define is historical */
> > > @@ -1089,6 +1096,8 @@ enum v4l2_auto_focus_range {
> > >
> > > #define V4L2_CID_HDR_SENSOR_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
> > >
> > > +/* CAMERA-class private control IDs */
> > > +
> >
> > Do we still need this comment?
> >
> > Best,
> > Yunke
> >
> > > /* FM Modulator class control IDs */
> > >
> > > #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
> > >
> > > --
> > > 2.47.0.338.g60cca15819-goog
> > >
>
>
>
> --
> Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 10/19] media: uvcvideo: Factor out clamping from uvc_ctrl_set
2024-11-14 19:10 ` [PATCH v15 10/19] media: uvcvideo: Factor out clamping from uvc_ctrl_set Ricardo Ribalda
@ 2024-12-09 8:50 ` Yunke Cao
2024-12-09 12:57 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Yunke Cao @ 2024-12-09 8:50 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, linux-media,
linux-kernel
Hi Ricardo,
This patch looks good to me.
Reviewed-by: Yunke Cao <yunkec@google.com>
Thanks,
Yunke
On Fri, Nov 15, 2024 at 4:10 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> Move the logic to a separated function. Do not expect any change.
> This is a preparation for supporting compound controls.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 82 +++++++++++++++++++++-------------------
> 1 file changed, 44 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 6d5167eb368d..893d12cd3f90 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -2002,28 +2002,17 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> return -EINVAL;
> }
>
> -int uvc_ctrl_set(struct uvc_fh *handle,
> - struct v4l2_ext_control *xctrl)
> +static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + s32 *value_in_out)
> {
> - struct uvc_video_chain *chain = handle->chain;
> - struct uvc_control *ctrl;
> - struct uvc_control_mapping *mapping;
> - s32 value;
> + s32 value = *value_in_out;
> u32 step;
> s32 min;
> 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;
> - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> - return -EACCES;
> -
> - /* Clamp out of range values. */
> switch (mapping->v4l2_type) {
> case V4L2_CTRL_TYPE_INTEGER:
> if (!ctrl->cached) {
> @@ -2041,14 +2030,13 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> if (step == 0)
> step = 1;
>
> - xctrl->value = min + DIV_ROUND_CLOSEST((u32)(xctrl->value - min),
> - step) * step;
> + value = min + DIV_ROUND_CLOSEST((u32)(value - min), step) * step;
> if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
> - xctrl->value = clamp(xctrl->value, min, max);
> + value = clamp(value, min, max);
> else
> - xctrl->value = clamp_t(u32, xctrl->value, min, max);
> - value = xctrl->value;
> - break;
> + value = clamp_t(u32, value, min, max);
> + *value_in_out = value;
> + return 0;
>
> case V4L2_CTRL_TYPE_BITMASK:
> if (!ctrl->cached) {
> @@ -2057,21 +2045,20 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> return ret;
> }
>
> - xctrl->value &= uvc_get_ctrl_bitmap(ctrl, mapping);
> - value = xctrl->value;
> - break;
> + value &= uvc_get_ctrl_bitmap(ctrl, mapping);
> + *value_in_out = value;
> + return 0;
>
> case V4L2_CTRL_TYPE_BOOLEAN:
> - xctrl->value = clamp(xctrl->value, 0, 1);
> - value = xctrl->value;
> - break;
> + *value_in_out = clamp(value, 0, 1);
> + return 0;
>
> case V4L2_CTRL_TYPE_MENU:
> - if (xctrl->value < (ffs(mapping->menu_mask) - 1) ||
> - xctrl->value > (fls(mapping->menu_mask) - 1))
> + if (value < (ffs(mapping->menu_mask) - 1) ||
> + value > (fls(mapping->menu_mask) - 1))
> return -ERANGE;
>
> - if (!test_bit(xctrl->value, &mapping->menu_mask))
> + if (!test_bit(value, &mapping->menu_mask))
> return -EINVAL;
>
> /*
> @@ -2079,8 +2066,7 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> * UVC controls that support it.
> */
> if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) {
> - int val = uvc_mapping_get_menu_value(mapping,
> - xctrl->value);
> + int val = uvc_mapping_get_menu_value(mapping, value);
> if (!ctrl->cached) {
> ret = uvc_ctrl_populate_cache(chain, ctrl);
> if (ret < 0)
> @@ -2090,14 +2076,34 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & val))
> return -EINVAL;
> }
> - value = xctrl->value;
> - break;
> + return 0;
>
> default:
> - value = xctrl->value;
> - break;
> + return 0;
> }
>
> + return 0;
> +}
> +
> +int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
> +{
> + struct uvc_video_chain *chain = handle->chain;
> + struct uvc_control_mapping *mapping;
> + struct uvc_control *ctrl;
> + int ret;
> +
> + if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
> + return -EACCES;
> +
> + ctrl = uvc_find_control(chain, xctrl->id, &mapping);
> + if (!ctrl)
> + return -EINVAL;
> + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> + return -EACCES;
> +
> + ret = uvc_ctrl_clamp(chain, ctrl, mapping, &xctrl->value);
> + if (ret)
> + return ret;
> /*
> * If the mapping doesn't span the whole UVC control, the current value
> * needs to be loaded from the device to perform the read-modify-write
> @@ -2116,7 +2122,7 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> ctrl->info.size);
> }
>
> - uvc_mapping_set_s32(mapping, value,
> + uvc_mapping_set_s32(mapping, xctrl->value,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
>
> --
> 2.47.0.338.g60cca15819-goog
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 12/19] media: uvcvideo: Factor out query_boundaries from query_ctrl
2024-11-14 19:10 ` [PATCH v15 12/19] media: uvcvideo: Factor out query_boundaries from query_ctrl Ricardo Ribalda
@ 2024-12-09 8:50 ` Yunke Cao
2024-12-09 13:38 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Yunke Cao @ 2024-12-09 8:50 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, linux-media,
linux-kernel
Hi Ricardo,
This patch looks good to me.
Reviewed-by: Yunke Cao <yunkec@google.com>
Thanks,
Yunke
On Fri, Nov 15, 2024 at 4:10 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> Split the function in two parts. queryctrl_boundaries will be used in
> future patches.
>
> No functional change expected from this patch.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 106 ++++++++++++++++++++++-----------------
> 1 file changed, 60 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index e51cd0a2228a..b591d7fddc37 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1367,53 +1367,11 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
> return ~0;
> }
>
> -static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> - struct uvc_control *ctrl,
> - struct uvc_control_mapping *mapping,
> - struct v4l2_queryctrl *v4l2_ctrl)
> +static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + struct v4l2_queryctrl *v4l2_ctrl)
> {
> - struct uvc_control_mapping *master_map = NULL;
> - struct uvc_control *master_ctrl = NULL;
> -
> - memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> - v4l2_ctrl->id = mapping->id;
> - v4l2_ctrl->type = mapping->v4l2_type;
> - strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping),
> - sizeof(v4l2_ctrl->name));
> - v4l2_ctrl->flags = 0;
> -
> - if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
> - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> -
> - if (mapping->master_id)
> - __uvc_find_control(ctrl->entity, mapping->master_id,
> - &master_map, &master_ctrl, 0, 0);
> - if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> - s32 val;
> - int ret;
> -
> - if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
> - return -EIO;
> -
> - ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> - if (ret < 0)
> - return ret;
> -
> - if (val != mapping->master_manual)
> - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> - }
> -
> - if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
> - v4l2_ctrl->default_value = 0;
> - v4l2_ctrl->minimum = 0;
> - v4l2_ctrl->maximum = 0;
> - v4l2_ctrl->step = 0;
> - return 0;
> - }
> -
> if (!ctrl->cached) {
> int ret = uvc_ctrl_populate_cache(chain, ctrl);
> if (ret < 0)
> @@ -1456,18 +1414,74 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
> v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> + else
> + v4l2_ctrl->minimum = 0;
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
> v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> + else
> + v4l2_ctrl->maximum = 0;
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
> v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> + else
> + v4l2_ctrl->step = 0;
>
> return 0;
> }
>
> +static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + struct v4l2_queryctrl *v4l2_ctrl)
> +{
> + struct uvc_control_mapping *master_map = NULL;
> + struct uvc_control *master_ctrl = NULL;
> +
> + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> + v4l2_ctrl->id = mapping->id;
> + v4l2_ctrl->type = mapping->v4l2_type;
> + strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping),
> + sizeof(v4l2_ctrl->name));
> + v4l2_ctrl->flags = 0;
> +
> + if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
> + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +
> + if (mapping->master_id)
> + __uvc_find_control(ctrl->entity, mapping->master_id,
> + &master_map, &master_ctrl, 0, 0);
> + if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> + s32 val;
> + int ret;
> +
> + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
> + return -EIO;
> +
> + ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> + if (ret < 0)
> + return ret;
> +
> + if (val != mapping->master_manual)
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> + }
> +
> + if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
> + v4l2_ctrl->default_value = 0;
> + v4l2_ctrl->minimum = 0;
> + v4l2_ctrl->maximum = 0;
> + v4l2_ctrl->step = 0;
> + return 0;
> + }
> +
> + return __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl);
> +}
> +
> int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> struct v4l2_queryctrl *v4l2_ctrl)
> {
>
> --
> 2.47.0.338.g60cca15819-goog
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl
2024-11-14 19:10 ` [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl Ricardo Ribalda
@ 2024-12-09 8:50 ` Yunke Cao
2024-12-09 14:08 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Yunke Cao @ 2024-12-09 8:50 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, linux-media,
linux-kernel
Hi Ricardo,
This patch looks good to me.
Reviewed-by: Yunke Cao <yunkec@google.com>
Thanks,
Yunke
On Fri, Nov 15, 2024 at 4:11 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> v4l2_query_ext_ctrl contains information that is missing in
> v4l2_queryctrl, like elem_size and elems.
>
> With this change we can handle all the element_size information inside
> uvc_ctrl.c.
>
> Now that we are at it, remove the memset of the reserved fields, the
> v4l2 ioctl handler should do that for us.
>
> There is no functional change expected from this change.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 24 ++++++++++++++----------
> drivers/media/usb/uvc/uvc_v4l2.c | 35 +++++++++++++++--------------------
> drivers/media/usb/uvc/uvcvideo.h | 2 +-
> 3 files changed, 30 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 72ed7dc9cfc1..1bc019138995 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1252,7 +1252,8 @@ static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
> }
>
> static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
> - u32 found_id, struct v4l2_queryctrl *v4l2_ctrl)
> + u32 found_id,
> + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> {
> int idx;
>
> @@ -1400,7 +1401,7 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
> static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> struct uvc_control *ctrl,
> struct uvc_control_mapping *mapping,
> - struct v4l2_queryctrl *v4l2_ctrl)
> + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> {
> if (!ctrl->cached) {
> int ret = uvc_ctrl_populate_cache(chain, ctrl);
> @@ -1465,7 +1466,7 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> struct uvc_control *ctrl,
> struct uvc_control_mapping *mapping,
> - struct v4l2_queryctrl *v4l2_ctrl)
> + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> {
> struct uvc_control_mapping *master_map = NULL;
> struct uvc_control *master_ctrl = NULL;
> @@ -1503,6 +1504,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> }
>
> + v4l2_ctrl->elem_size = sizeof(s32);
> + v4l2_ctrl->elems = 1;
> +
> if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
> v4l2_ctrl->default_value = 0;
> @@ -1516,7 +1520,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> }
>
> int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> - struct v4l2_queryctrl *v4l2_ctrl)
> + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> {
> struct uvc_control *ctrl;
> struct uvc_control_mapping *mapping;
> @@ -1642,7 +1646,7 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
> struct uvc_control_mapping *mapping,
> s32 value, u32 changes)
> {
> - struct v4l2_queryctrl v4l2_ctrl;
> + struct v4l2_query_ext_ctrl v4l2_ctrl;
>
> __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
>
> @@ -2119,7 +2123,7 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
> struct uvc_control_mapping *mapping,
> u32 which, struct v4l2_ext_control *xctrl)
> {
> - struct v4l2_queryctrl qc;
> + struct v4l2_query_ext_ctrl qec;
> int ret;
>
> switch (which) {
> @@ -2133,19 +2137,19 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
> return -EINVAL;
> }
>
> - ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qc);
> + ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qec);
> if (ret < 0)
> return ret;
>
> switch (which) {
> case V4L2_CTRL_WHICH_DEF_VAL:
> - xctrl->value = qc.default_value;
> + xctrl->value = qec.default_value;
> break;
> case V4L2_CTRL_WHICH_MIN_VAL:
> - xctrl->value = qc.minimum;
> + xctrl->value = qec.minimum;
> break;
> case V4L2_CTRL_WHICH_MAX_VAL:
> - xctrl->value = qc.maximum;
> + xctrl->value = qec.maximum;
> break;
> }
>
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 7e284770149d..5000c74271e0 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1014,40 +1014,35 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
> return ret;
> }
>
> -static int uvc_ioctl_queryctrl(struct file *file, void *fh,
> - struct v4l2_queryctrl *qc)
> +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
> + struct v4l2_query_ext_ctrl *qec)
> {
> struct uvc_fh *handle = fh;
> struct uvc_video_chain *chain = handle->chain;
>
> - return uvc_query_v4l2_ctrl(chain, qc);
> + return uvc_query_v4l2_ctrl(chain, qec);
> }
>
> -static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
> - struct v4l2_query_ext_ctrl *qec)
> +static int uvc_ioctl_queryctrl(struct file *file, void *fh,
> + struct v4l2_queryctrl *qc)
> {
> struct uvc_fh *handle = fh;
> struct uvc_video_chain *chain = handle->chain;
> - struct v4l2_queryctrl qc = { qec->id };
> + struct v4l2_query_ext_ctrl qec = { qc->id };
> int ret;
>
> - ret = uvc_query_v4l2_ctrl(chain, &qc);
> + ret = uvc_query_v4l2_ctrl(chain, &qec);
> if (ret)
> return ret;
>
> - qec->id = qc.id;
> - qec->type = qc.type;
> - strscpy(qec->name, qc.name, sizeof(qec->name));
> - qec->minimum = qc.minimum;
> - qec->maximum = qc.maximum;
> - qec->step = qc.step;
> - qec->default_value = qc.default_value;
> - qec->flags = qc.flags;
> - qec->elem_size = 4;
> - qec->elems = 1;
> - qec->nr_of_dims = 0;
> - memset(qec->dims, 0, sizeof(qec->dims));
> - memset(qec->reserved, 0, sizeof(qec->reserved));
> + qc->id = qec.id;
> + qc->type = qec.type;
> + strscpy(qc->name, qec.name, sizeof(qc->name));
> + qc->minimum = qec.minimum;
> + qc->maximum = qec.maximum;
> + qc->step = qec.step;
> + qc->default_value = qec.default_value;
> + qc->flags = qec.flags;
>
> return 0;
> }
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index f429f325433b..8aca1a2fe587 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -766,7 +766,7 @@ void uvc_status_put(struct uvc_device *dev);
> extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
>
> int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> - struct v4l2_queryctrl *v4l2_ctrl);
> + struct v4l2_query_ext_ctrl *v4l2_ctrl);
> int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
> struct v4l2_querymenu *query_menu);
>
>
> --
> 2.47.0.338.g60cca15819-goog
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 16/19] media: uvcvideo: Introduce uvc_mapping_v4l2_size
2024-11-14 19:10 ` [PATCH v15 16/19] media: uvcvideo: Introduce uvc_mapping_v4l2_size Ricardo Ribalda
@ 2024-12-09 8:51 ` Yunke Cao
2024-12-09 14:09 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Yunke Cao @ 2024-12-09 8:51 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, linux-media,
linux-kernel
Hi Ricardo,
This patch looks good to me.
Reviewed-by: Yunke Cao <yunkec@google.com>
Thanks,
Yunke
On Fri, Nov 15, 2024 at 4:11 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> Centralize the calculation for the v4l2_size of a mapping.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 15 +++++++++++----
> 1 file changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 1bc019138995..f262e05ad3a8 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1463,6 +1463,14 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> return 0;
> }
>
> +static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
> +{
> + if (uvc_ctrl_mapping_is_compound(mapping))
> + return DIV_ROUND_UP(mapping->size, 8);
> +
> + return sizeof(s32);
> +}
> +
> static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> struct uvc_control *ctrl,
> struct uvc_control_mapping *mapping,
> @@ -1504,7 +1512,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> }
>
> - v4l2_ctrl->elem_size = sizeof(s32);
> + v4l2_ctrl->elem_size = uvc_mapping_v4l2_size(mapping);
> v4l2_ctrl->elems = 1;
>
> if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> @@ -2093,7 +2101,7 @@ static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
> return -EINVAL;
> }
>
> - size = DIV_ROUND_UP(mapping->size, 8);
> + size = uvc_mapping_v4l2_size(mapping);
> if (xctrl->size < size) {
> xctrl->size = size;
> return -ENOSPC;
> @@ -2271,9 +2279,8 @@ static int uvc_mapping_set_xctrl_compound(struct uvc_control *ctrl,
> struct v4l2_ext_control *xctrl)
> {
> u8 *data __free(kfree) = NULL;
> - size_t size;
> + size_t size = uvc_mapping_v4l2_size(mapping);
>
> - size = DIV_ROUND_UP(mapping->size, 8);
> if (xctrl->size != size)
> return -EINVAL;
>
>
> --
> 2.47.0.338.g60cca15819-goog
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
` (18 preceding siblings ...)
2024-11-14 19:10 ` [PATCH v15 19/19] media: uvcvideo: document " Ricardo Ribalda
@ 2024-12-09 8:53 ` Yunke Cao
19 siblings, 0 replies; 62+ messages in thread
From: Yunke Cao @ 2024-12-09 8:53 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, linux-media,
linux-kernel, stable, Yunke Cao, Sergey Senozhatsky,
Daniel Scally
Hi Ricardo,
I've tested the patchset with the fix I commented on in patch 18/19 on
Chrome OS and verified that the region of interest works as expected.
Tested-by: Yunke Cao <yunkec@google.com>
Best,
Yunke
On Fri, Nov 15, 2024 at 4:10 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> This patchset implements UVC v1.5 region of interest using V4L2
> control API.
>
> ROI control is consisted two uvc specific controls.
> 1. A rectangle control with a newly added type V4L2_CTRL_TYPE_RECT.
> 2. An auto control with type bitmask.
>
> V4L2_CTRL_WHICH_MIN/MAX_VAL is added to support the rectangle control.
>
> The corresponding v4l-utils series can be found at
> https://patchwork.linuxtv.org/project/linux-media/list/?series=11069 .
>
> Tested with v4l2-compliance, v4l2-ctl, calling ioctls on usb cameras and
> VIVID with a newly added V4L2_CTRL_TYPE_RECT control.
>
> This set includes also the patch:
> media: uvcvideo: Fix event flags in uvc_ctrl_send_events
> It is not technically part of this change, but we conflict with it.
>
> I am continuing the work that Yunke did.
>
> Changes in v15:
> - Modify mapping set/get to support any size
> - Remove v4l2_size field. It is not needed, we can use the v4l2_type to
> infer it.
> - Improve documentation.
> - Lots of refactoring, now adding compound and roi are very small
> patches.
> - Remove rectangle clamping, not supported by some firmware.
> - Remove init, we can add it later.
> - Move uvc_cid to USER_BASE
>
> - Link to v14: https://lore.kernel.org/linux-media/20231201071907.3080126-1-yunkec@google.com/
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> Hans Verkuil (1):
> media: v4l2-ctrls: add support for V4L2_CTRL_WHICH_MIN/MAX_VAL
>
> Ricardo Ribalda (12):
> media: uvcvideo: Fix event flags in uvc_ctrl_send_events
> media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value
> media: uvcvideo: Handle uvc menu translation inside uvc_set_le_value
> media: uvcvideo: refactor uvc_ioctl_g_ext_ctrls
> media: uvcvideo: uvc_ioctl_(g|s)_ext_ctrls: handle NoP case
> media: uvcvideo: Support any size for mapping get/set
> media: uvcvideo: Factor out clamping from uvc_ctrl_set
> media: uvcvideo: Factor out query_boundaries from query_ctrl
> media: uvcvideo: Use the camera to clamp compound controls
> media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl
> media: uvcvideo: Introduce uvc_mapping_v4l2_size
> media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map
>
> Yunke Cao (6):
> media: v4l2_ctrl: Add V4L2_CTRL_TYPE_RECT
> media: vivid: Add a rectangle control
> media: uvcvideo: add support for compound controls
> media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL
> media: uvcvideo: implement UVC v1.5 ROI
> media: uvcvideo: document UVC v1.5 ROI
>
> .../userspace-api/media/drivers/uvcvideo.rst | 64 ++
> .../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 26 +-
> .../userspace-api/media/v4l/vidioc-queryctrl.rst | 14 +
> .../userspace-api/media/videodev2.h.rst.exceptions | 4 +
> drivers/media/i2c/imx214.c | 4 +-
> drivers/media/platform/qcom/venus/venc_ctrls.c | 9 +-
> drivers/media/test-drivers/vivid/vivid-ctrls.c | 34 +
> drivers/media/usb/uvc/uvc_ctrl.c | 805 ++++++++++++++++-----
> drivers/media/usb/uvc/uvc_v4l2.c | 77 +-
> drivers/media/usb/uvc/uvcvideo.h | 25 +-
> drivers/media/v4l2-core/v4l2-ctrls-api.c | 54 +-
> drivers/media/v4l2-core/v4l2-ctrls-core.c | 167 ++++-
> drivers/media/v4l2-core/v4l2-ioctl.c | 4 +-
> include/media/v4l2-ctrls.h | 38 +-
> include/uapi/linux/usb/video.h | 1 +
> include/uapi/linux/uvcvideo.h | 13 +
> include/uapi/linux/v4l2-controls.h | 9 +
> include/uapi/linux/videodev2.h | 5 +
> 18 files changed, 1062 insertions(+), 291 deletions(-)
> ---
> base-commit: 5516200c466f92954551406ea641376963c43a92
> change-id: 20241113-uvc-roi-66bd6cfa1e64
>
> Best regards,
> --
> Ricardo Ribalda <ribalda@chromium.org>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 09/19] media: uvcvideo: Support any size for mapping get/set
2024-11-14 19:10 ` [PATCH v15 09/19] media: uvcvideo: Support any size for mapping get/set Ricardo Ribalda
@ 2024-12-09 8:56 ` Yunke Cao
2024-12-09 12:49 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Yunke Cao @ 2024-12-09 8:56 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans de Goede,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil, linux-media,
linux-kernel
Hi Ricardo,
This patch looks good to me.
Reviewed-by: Yunke Cao <yunkec@google.com>
Thanks,
Yunke
On Fri, Nov 15, 2024 at 4:10 AM Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> Right now, we only support mappings for v4l2 controls with a max size of
> s32. This patch modifies the prototype of get/set so it can support any
> size.
>
> This is done to prepare for compound controls.
>
> Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 183 +++++++++++++++++++++++++++------------
> drivers/media/usb/uvc/uvcvideo.h | 8 +-
> 2 files changed, 130 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index d6afa131a5e1..6d5167eb368d 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -367,6 +367,22 @@ static const u32 uvc_control_classes[] = {
>
> static const int exposure_auto_mapping[] = { 2, 1, 4, 8 };
>
> +static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping,
> + u8 query, const void *data_in)
> +{
> + s32 data_out;
> +
> + mapping->get(mapping, query, data_in, sizeof(data_out), &data_out);
> +
> + return data_out;
> +}
> +
> +static void uvc_mapping_set_s32(struct uvc_control_mapping *mapping,
> + s32 data_in, void *data_out)
> +{
> + mapping->set(mapping, sizeof(data_in), &data_in, data_out);
> +}
> +
> /*
> * This function translates the V4L2 menu index @idx, as exposed to userspace as
> * the V4L2 control value, to the corresponding UVC control value used by the
> @@ -405,58 +421,93 @@ uvc_mapping_get_menu_name(const struct uvc_control_mapping *mapping, u32 idx)
> return v4l2_ctrl_get_menu(mapping->id)[idx];
> }
>
> -static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
> - u8 query, const u8 *data)
> +static int uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query,
> + const void *uvc_in, size_t v4l2_size,
> + void *v4l2_out)
> {
> - s8 zoom = (s8)data[0];
> + u8 value = ((u8 *)uvc_in)[2];
> + s8 sign = ((s8 *)uvc_in)[0];
> + s32 *out = v4l2_out;
> +
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
>
> switch (query) {
> case UVC_GET_CUR:
> - return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
> + *out = (sign == 0) ? 0 : (sign > 0 ? value : -value);
> + return 0;
>
> case UVC_GET_MIN:
> case UVC_GET_MAX:
> case UVC_GET_RES:
> case UVC_GET_DEF:
> default:
> - return data[2];
> + *out = value;
> + return 0;
> }
> }
>
> -static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
> - s32 value, u8 *data)
> +static int uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
> + size_t v4l2_size, const void *v4l2_in,
> + void *uvc_out)
> {
> - data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
> - data[2] = min((int)abs(value), 0xff);
> + u8 *out = uvc_out;
> + s32 value;
> +
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
> +
> + value = *(u32 *)v4l2_in;
> + out[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
> + out[2] = min_t(int, abs(value), 0xff);
> +
> + return 0;
> }
>
> -static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
> - u8 query, const u8 *data)
> +static int uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
> + u8 query, const void *uvc_in,
> + size_t v4l2_size, void *v4l2_out)
> {
> unsigned int first = mapping->offset / 8;
> - s8 rel = (s8)data[first];
> + u8 value = ((u8 *)uvc_in)[first + 1];
> + s8 sign = ((s8 *)uvc_in)[first];
> + s32 *out = v4l2_out;
> +
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
>
> switch (query) {
> case UVC_GET_CUR:
> - return (rel == 0) ? 0 : (rel > 0 ? data[first+1]
> - : -data[first+1]);
> + *out = (sign == 0) ? 0 : (sign > 0 ? value : -value);
> + return 0;
> case UVC_GET_MIN:
> - return -data[first+1];
> + *out = -value;
> + return 0;
> case UVC_GET_MAX:
> case UVC_GET_RES:
> case UVC_GET_DEF:
> default:
> - return data[first+1];
> + *out = value;
> + return 0;
> }
> }
>
> -static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
> - s32 value, u8 *data)
> +static int uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
> + size_t v4l2_size, const void *v4l2_in,
> + void *uvc_out)
> {
> unsigned int first = mapping->offset / 8;
> + u8 *out = uvc_out;
> + s32 value;
> +
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
>
> - data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
> - data[first+1] = min_t(int, abs(value), 0xff);
> + value = *(u32 *)v4l2_in;
> + out[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
> + out[first + 1] = min_t(int, abs(value), 0xff);
> +
> + return 0;
> }
>
> static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
> @@ -887,14 +938,20 @@ static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val)
> * a signed 32bit integer. Sign extension will be performed if the mapping
> * references a signed data type.
> */
> -static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
> - u8 query, const u8 *data)
> +static int uvc_get_le_value(struct uvc_control_mapping *mapping,
> + u8 query, const void *uvc_in, size_t v4l2_size,
> + void *v4l2_out)
> {
> - int bits = mapping->size;
> int offset = mapping->offset;
> + int bits = mapping->size;
> + const u8 *data = uvc_in;
> + s32 *out = v4l2_out;
> s32 value = 0;
> u8 mask;
>
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
> +
> data += offset / 8;
> offset &= 7;
> mask = ((1LL << bits) - 1) << offset;
> @@ -916,29 +973,40 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
> value |= -(value & (1 << (mapping->size - 1)));
>
> /* If it is a menu, convert from uvc to v4l2. */
> - if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
> - return value;
> + if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
> + *out = value;
> + return 0;
> + }
>
> switch (query) {
> case UVC_GET_CUR:
> case UVC_GET_DEF:
> - return uvc_menu_to_v4l2_menu(mapping, value);
> + *out = uvc_menu_to_v4l2_menu(mapping, value);
> + return 0;
> }
>
> - return value;
> + *out = value;
> + return 0;
> }
>
> /*
> * Set the bit string specified by mapping->offset and mapping->size
> * in the little-endian data stored at 'data' to the value 'value'.
> */
> -static void uvc_set_le_value(struct uvc_control_mapping *mapping,
> - s32 value, u8 *data)
> +static int uvc_set_le_value(struct uvc_control_mapping *mapping,
> + size_t v4l2_size, const void *v4l2_in,
> + void *uvc_out)
> {
> - int bits = mapping->size;
> int offset = mapping->offset;
> + int bits = mapping->size;
> + u8 *data = uvc_out;
> + s32 value;
> u8 mask;
>
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
> +
> + value = *(s32 *)v4l2_in;
> if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU)
> value = uvc_mapping_get_menu_value(mapping, value);
> /*
> @@ -960,6 +1028,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
> bits -= 8 - offset;
> offset = 0;
> }
> +
> + return 0;
> }
>
> /* ------------------------------------------------------------------------
> @@ -1141,8 +1211,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
> if (ret < 0)
> return ret;
>
> - *value = mapping->get(mapping, UVC_GET_CUR,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> + *value = uvc_mapping_get_s32(mapping, UVC_GET_CUR,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
>
> return 0;
> }
> @@ -1275,12 +1345,12 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
> * as supported.
> */
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
> - return mapping->get(mapping, UVC_GET_RES,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> + return uvc_mapping_get_s32(mapping, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
> - return mapping->get(mapping, UVC_GET_MAX,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> + return uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
>
> return ~0;
> }
> @@ -1324,10 +1394,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> return ret;
> }
>
> - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
> - v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> - }
> + if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF)
> + v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping,
> + UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
>
> switch (mapping->v4l2_type) {
> case V4L2_CTRL_TYPE_MENU:
> @@ -1359,16 +1428,16 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> }
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
> - v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> + v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
> - v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> + v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
> - v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> + v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
>
> return 0;
> }
> @@ -1581,7 +1650,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
> ctrl->handle = NULL;
>
> list_for_each_entry(mapping, &ctrl->info.mappings, list) {
> - s32 value = mapping->get(mapping, UVC_GET_CUR, data);
> + s32 value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data);
>
> /*
> * handle may be NULL here if the device sends auto-update
> @@ -1925,8 +1994,8 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> if (ret < 0)
> return ret;
> }
> - xctrl->value = mapping->get(mapping, UVC_GET_DEF,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> + xctrl->value = uvc_mapping_get_s32(mapping, UVC_GET_DEF,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> return 0;
> }
>
> @@ -1963,12 +2032,12 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> return ret;
> }
>
> - min = mapping->get(mapping, UVC_GET_MIN,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> - max = mapping->get(mapping, UVC_GET_MAX,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> - step = mapping->get(mapping, UVC_GET_RES,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> + min = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> + max = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> + step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> if (step == 0)
> step = 1;
>
> @@ -2047,8 +2116,8 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> ctrl->info.size);
> }
>
> - mapping->set(mapping, value,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> + uvc_mapping_set_s32(mapping, value,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
> ctrl->handle = handle;
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 6ebaabd11443..3d32a56c5ff8 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -131,10 +131,10 @@ struct uvc_control_mapping {
> const struct uvc_control_mapping *(*filter_mapping)
> (struct uvc_video_chain *chain,
> struct uvc_control *ctrl);
> - s32 (*get)(struct uvc_control_mapping *mapping, u8 query,
> - const u8 *data);
> - void (*set)(struct uvc_control_mapping *mapping, s32 value,
> - u8 *data);
> + int (*get)(struct uvc_control_mapping *mapping, u8 query,
> + const void *uvc_in, size_t v4l2_size, void *v4l2_out);
> + int (*set)(struct uvc_control_mapping *mapping, size_t v4l2_size,
> + const void *v4l2_in, void *uvc_out);
> };
>
> struct uvc_control {
>
> --
> 2.47.0.338.g60cca15819-goog
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 09/19] media: uvcvideo: Support any size for mapping get/set
2024-11-14 19:10 ` [PATCH v15 09/19] media: uvcvideo: Support any size for mapping get/set Ricardo Ribalda
2024-12-09 8:56 ` Yunke Cao
@ 2024-12-09 12:49 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 12:49 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> Right now, we only support mappings for v4l2 controls with a max size of
> s32. This patch modifies the prototype of get/set so it can support any
> size.
>
> This is done to prepare for compound controls.
>
> Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 183 +++++++++++++++++++++++++++------------
> drivers/media/usb/uvc/uvcvideo.h | 8 +-
> 2 files changed, 130 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index d6afa131a5e1..6d5167eb368d 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -367,6 +367,22 @@ static const u32 uvc_control_classes[] = {
>
> static const int exposure_auto_mapping[] = { 2, 1, 4, 8 };
>
> +static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping,
> + u8 query, const void *data_in)
> +{
> + s32 data_out;
> +
> + mapping->get(mapping, query, data_in, sizeof(data_out), &data_out);
If mapping->get() fails, e.g. hits the -EINVAL path in uvc_ctrl_get_zoom()
then this will return the uninitialized data_out.
I realize that this is supposed to never happen and adding error-handling
here would not be helpful since there is no way to return an error-code
without changing the function prototype.
But I think you should at least initialize data_out to 0 to avoid leaking
stack-memory contents to userspace if we somehow do manage to hit this.
> +
> + return data_out;
> +}
> +
> +static void uvc_mapping_set_s32(struct uvc_control_mapping *mapping,
> + s32 data_in, void *data_out)
> +{
> + mapping->set(mapping, sizeof(data_in), &data_in, data_out);
> +}
> +
> /*
> * This function translates the V4L2 menu index @idx, as exposed to userspace as
> * the V4L2 control value, to the corresponding UVC control value used by the
> @@ -405,58 +421,93 @@ uvc_mapping_get_menu_name(const struct uvc_control_mapping *mapping, u32 idx)
> return v4l2_ctrl_get_menu(mapping->id)[idx];
> }
>
> -static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
> - u8 query, const u8 *data)
> +static int uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query,
> + const void *uvc_in, size_t v4l2_size,
> + void *v4l2_out)
> {
> - s8 zoom = (s8)data[0];
> + u8 value = ((u8 *)uvc_in)[2];
> + s8 sign = ((s8 *)uvc_in)[0];
> + s32 *out = v4l2_out;
> +
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
>
> switch (query) {
> case UVC_GET_CUR:
> - return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
> + *out = (sign == 0) ? 0 : (sign > 0 ? value : -value);
> + return 0;
>
> case UVC_GET_MIN:
> case UVC_GET_MAX:
> case UVC_GET_RES:
> case UVC_GET_DEF:
> default:
> - return data[2];
> + *out = value;
> + return 0;
> }
> }
>
> -static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
> - s32 value, u8 *data)
> +static int uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
> + size_t v4l2_size, const void *v4l2_in,
> + void *uvc_out)
> {
> - data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
> - data[2] = min((int)abs(value), 0xff);
> + u8 *out = uvc_out;
> + s32 value;
> +
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
> +
> + value = *(u32 *)v4l2_in;
> + out[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
> + out[2] = min_t(int, abs(value), 0xff);
> +
> + return 0;
> }
>
> -static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
> - u8 query, const u8 *data)
> +static int uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
> + u8 query, const void *uvc_in,
> + size_t v4l2_size, void *v4l2_out)
> {
> unsigned int first = mapping->offset / 8;
> - s8 rel = (s8)data[first];
> + u8 value = ((u8 *)uvc_in)[first + 1];
> + s8 sign = ((s8 *)uvc_in)[first];
> + s32 *out = v4l2_out;
> +
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
>
> switch (query) {
> case UVC_GET_CUR:
> - return (rel == 0) ? 0 : (rel > 0 ? data[first+1]
> - : -data[first+1]);
> + *out = (sign == 0) ? 0 : (sign > 0 ? value : -value);
> + return 0;
> case UVC_GET_MIN:
> - return -data[first+1];
> + *out = -value;
> + return 0;
> case UVC_GET_MAX:
> case UVC_GET_RES:
> case UVC_GET_DEF:
> default:
> - return data[first+1];
> + *out = value;
> + return 0;
> }
> }
>
> -static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
> - s32 value, u8 *data)
> +static int uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
> + size_t v4l2_size, const void *v4l2_in,
> + void *uvc_out)
> {
> unsigned int first = mapping->offset / 8;
> + u8 *out = uvc_out;
> + s32 value;
> +
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
>
> - data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
> - data[first+1] = min_t(int, abs(value), 0xff);
> + value = *(u32 *)v4l2_in;
> + out[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
> + out[first + 1] = min_t(int, abs(value), 0xff);
> +
> + return 0;
> }
>
> static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
> @@ -887,14 +938,20 @@ static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val)
> * a signed 32bit integer. Sign extension will be performed if the mapping
> * references a signed data type.
> */
> -static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
> - u8 query, const u8 *data)
> +static int uvc_get_le_value(struct uvc_control_mapping *mapping,
> + u8 query, const void *uvc_in, size_t v4l2_size,
> + void *v4l2_out)
> {
> - int bits = mapping->size;
> int offset = mapping->offset;
> + int bits = mapping->size;
> + const u8 *data = uvc_in;
> + s32 *out = v4l2_out;
> s32 value = 0;
> u8 mask;
>
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
> +
> data += offset / 8;
> offset &= 7;
> mask = ((1LL << bits) - 1) << offset;
> @@ -916,29 +973,40 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
> value |= -(value & (1 << (mapping->size - 1)));
>
> /* If it is a menu, convert from uvc to v4l2. */
> - if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
> - return value;
> + if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
> + *out = value;
> + return 0;
> + }
>
> switch (query) {
> case UVC_GET_CUR:
> case UVC_GET_DEF:
> - return uvc_menu_to_v4l2_menu(mapping, value);
> + *out = uvc_menu_to_v4l2_menu(mapping, value);
> + return 0;
> }
>
> - return value;
> + *out = value;
> + return 0;
> }
>
> /*
> * Set the bit string specified by mapping->offset and mapping->size
> * in the little-endian data stored at 'data' to the value 'value'.
> */
> -static void uvc_set_le_value(struct uvc_control_mapping *mapping,
> - s32 value, u8 *data)
> +static int uvc_set_le_value(struct uvc_control_mapping *mapping,
> + size_t v4l2_size, const void *v4l2_in,
> + void *uvc_out)
> {
> - int bits = mapping->size;
> int offset = mapping->offset;
> + int bits = mapping->size;
> + u8 *data = uvc_out;
> + s32 value;
> u8 mask;
>
> + if (WARN_ON(v4l2_size != sizeof(s32)))
> + return -EINVAL;
> +
> + value = *(s32 *)v4l2_in;
> if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU)
> value = uvc_mapping_get_menu_value(mapping, value);
> /*
> @@ -960,6 +1028,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
> bits -= 8 - offset;
> offset = 0;
> }
> +
> + return 0;
> }
>
> /* ------------------------------------------------------------------------
> @@ -1141,8 +1211,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
> if (ret < 0)
> return ret;
>
> - *value = mapping->get(mapping, UVC_GET_CUR,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> + *value = uvc_mapping_get_s32(mapping, UVC_GET_CUR,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
>
> return 0;
> }
> @@ -1275,12 +1345,12 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
> * as supported.
> */
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
> - return mapping->get(mapping, UVC_GET_RES,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> + return uvc_mapping_get_s32(mapping, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
> - return mapping->get(mapping, UVC_GET_MAX,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> + return uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
>
> return ~0;
> }
> @@ -1324,10 +1394,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> return ret;
> }
>
> - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
> - v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> - }
> + if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF)
> + v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping,
> + UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
>
> switch (mapping->v4l2_type) {
> case V4L2_CTRL_TYPE_MENU:
The dropping of the { } here seems to be an unrelated code style change, please
drop this.
> @@ -1359,16 +1428,16 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> }
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
> - v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> + v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
> - v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> + v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
> - v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> + v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
>
> return 0;
> }
> @@ -1581,7 +1650,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
> ctrl->handle = NULL;
>
> list_for_each_entry(mapping, &ctrl->info.mappings, list) {
> - s32 value = mapping->get(mapping, UVC_GET_CUR, data);
> + s32 value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data);
>
> /*
> * handle may be NULL here if the device sends auto-update
> @@ -1925,8 +1994,8 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> if (ret < 0)
> return ret;
> }
> - xctrl->value = mapping->get(mapping, UVC_GET_DEF,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> + xctrl->value = uvc_mapping_get_s32(mapping, UVC_GET_DEF,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> return 0;
> }
>
> @@ -1963,12 +2032,12 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> return ret;
> }
>
> - min = mapping->get(mapping, UVC_GET_MIN,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> - max = mapping->get(mapping, UVC_GET_MAX,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> - step = mapping->get(mapping, UVC_GET_RES,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> + min = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> + max = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> + step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> if (step == 0)
> step = 1;
>
> @@ -2047,8 +2116,8 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> ctrl->info.size);
> }
>
> - mapping->set(mapping, value,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> + uvc_mapping_set_s32(mapping, value,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
> ctrl->handle = handle;
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 6ebaabd11443..3d32a56c5ff8 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -131,10 +131,10 @@ struct uvc_control_mapping {
> const struct uvc_control_mapping *(*filter_mapping)
> (struct uvc_video_chain *chain,
> struct uvc_control *ctrl);
> - s32 (*get)(struct uvc_control_mapping *mapping, u8 query,
> - const u8 *data);
> - void (*set)(struct uvc_control_mapping *mapping, s32 value,
> - u8 *data);
> + int (*get)(struct uvc_control_mapping *mapping, u8 query,
> + const void *uvc_in, size_t v4l2_size, void *v4l2_out);
> + int (*set)(struct uvc_control_mapping *mapping, size_t v4l2_size,
> + const void *v4l2_in, void *uvc_out);
> };
>
> struct uvc_control {
>
Exceot for my 2 small remarks this patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 10/19] media: uvcvideo: Factor out clamping from uvc_ctrl_set
2024-11-14 19:10 ` [PATCH v15 10/19] media: uvcvideo: Factor out clamping from uvc_ctrl_set Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
@ 2024-12-09 12:57 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 12:57 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> Move the logic to a separated function. Do not expect any change.
> This is a preparation for supporting compound controls.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 82 +++++++++++++++++++++-------------------
> 1 file changed, 44 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 6d5167eb368d..893d12cd3f90 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -2002,28 +2002,17 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> return -EINVAL;
> }
>
> -int uvc_ctrl_set(struct uvc_fh *handle,
> - struct v4l2_ext_control *xctrl)
> +static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + s32 *value_in_out)
> {
> - struct uvc_video_chain *chain = handle->chain;
> - struct uvc_control *ctrl;
> - struct uvc_control_mapping *mapping;
> - s32 value;
> + s32 value = *value_in_out;
> u32 step;
> s32 min;
> 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;
> - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> - return -EACCES;
> -
> - /* Clamp out of range values. */
> switch (mapping->v4l2_type) {
> case V4L2_CTRL_TYPE_INTEGER:
> if (!ctrl->cached) {
> @@ -2041,14 +2030,13 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> if (step == 0)
> step = 1;
>
> - xctrl->value = min + DIV_ROUND_CLOSEST((u32)(xctrl->value - min),
> - step) * step;
> + value = min + DIV_ROUND_CLOSEST((u32)(value - min), step) * step;
> if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
> - xctrl->value = clamp(xctrl->value, min, max);
> + value = clamp(value, min, max);
> else
> - xctrl->value = clamp_t(u32, xctrl->value, min, max);
> - value = xctrl->value;
> - break;
> + value = clamp_t(u32, value, min, max);
> + *value_in_out = value;
> + return 0;
>
> case V4L2_CTRL_TYPE_BITMASK:
> if (!ctrl->cached) {
> @@ -2057,21 +2045,20 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> return ret;
> }
>
> - xctrl->value &= uvc_get_ctrl_bitmap(ctrl, mapping);
> - value = xctrl->value;
> - break;
> + value &= uvc_get_ctrl_bitmap(ctrl, mapping);
> + *value_in_out = value;
> + return 0;
>
> case V4L2_CTRL_TYPE_BOOLEAN:
> - xctrl->value = clamp(xctrl->value, 0, 1);
> - value = xctrl->value;
> - break;
> + *value_in_out = clamp(value, 0, 1);
> + return 0;
>
> case V4L2_CTRL_TYPE_MENU:
> - if (xctrl->value < (ffs(mapping->menu_mask) - 1) ||
> - xctrl->value > (fls(mapping->menu_mask) - 1))
> + if (value < (ffs(mapping->menu_mask) - 1) ||
> + value > (fls(mapping->menu_mask) - 1))
> return -ERANGE;
>
> - if (!test_bit(xctrl->value, &mapping->menu_mask))
> + if (!test_bit(value, &mapping->menu_mask))
> return -EINVAL;
>
> /*
> @@ -2079,8 +2066,7 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> * UVC controls that support it.
> */
> if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) {
> - int val = uvc_mapping_get_menu_value(mapping,
> - xctrl->value);
> + int val = uvc_mapping_get_menu_value(mapping, value);
> if (!ctrl->cached) {
> ret = uvc_ctrl_populate_cache(chain, ctrl);
> if (ret < 0)
> @@ -2090,14 +2076,34 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & val))
> return -EINVAL;
> }
> - value = xctrl->value;
> - break;
> + return 0;
>
> default:
> - value = xctrl->value;
> - break;
> + return 0;
> }
>
> + return 0;
> +}
> +
> +int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
> +{
> + struct uvc_video_chain *chain = handle->chain;
> + struct uvc_control_mapping *mapping;
> + struct uvc_control *ctrl;
> + int ret;
> +
> + if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
> + return -EACCES;
> +
> + ctrl = uvc_find_control(chain, xctrl->id, &mapping);
> + if (!ctrl)
> + return -EINVAL;
> + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> + return -EACCES;
> +
> + ret = uvc_ctrl_clamp(chain, ctrl, mapping, &xctrl->value);
> + if (ret)
> + return ret;
> /*
> * If the mapping doesn't span the whole UVC control, the current value
> * needs to be loaded from the device to perform the read-modify-write
> @@ -2116,7 +2122,7 @@ int uvc_ctrl_set(struct uvc_fh *handle,
> ctrl->info.size);
> }
>
> - uvc_mapping_set_s32(mapping, value,
> + uvc_mapping_set_s32(mapping, xctrl->value,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 11/19] media: uvcvideo: add support for compound controls
2024-11-14 19:10 ` [PATCH v15 11/19] media: uvcvideo: add support for compound controls Ricardo Ribalda
@ 2024-12-09 13:35 ` Hans de Goede
2024-12-09 13:58 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 13:35 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Yunke Cao
Hi Ricardo,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> From: Yunke Cao <yunkec@google.com>
>
> This patch adds support for compound controls. This is required to
> support controls that cannot be represented with a s64 data, such as the
> Region of Interest.
>
> Signed-off-by: Yunke Cao <yunkec@google.com>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 224 ++++++++++++++++++++++++++++++++-------
> drivers/media/usb/uvc/uvcvideo.h | 5 +
> 2 files changed, 192 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 893d12cd3f90..e51cd0a2228a 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -367,6 +367,11 @@ static const u32 uvc_control_classes[] = {
>
> static const int exposure_auto_mapping[] = { 2, 1, 4, 8 };
>
> +static bool uvc_ctrl_mapping_is_compound(struct uvc_control_mapping *mapping)
> +{
> + return mapping->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES;
> +}
> +
> static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping,
> u8 query, const void *data_in)
> {
> @@ -1048,7 +1053,7 @@ static int uvc_entity_match_guid(const struct uvc_entity *entity,
>
> static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id,
> struct uvc_control_mapping **mapping, struct uvc_control **control,
> - int next)
> + int next, int next_compound)
> {
> struct uvc_control *ctrl;
> struct uvc_control_mapping *map;
> @@ -1063,14 +1068,16 @@ static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id,
> continue;
>
> list_for_each_entry(map, &ctrl->info.mappings, list) {
> - if ((map->id == v4l2_id) && !next) {
> + if (map->id == v4l2_id && !next && !next_compound) {
> *control = ctrl;
> *mapping = map;
> return;
> }
>
> if ((*mapping == NULL || (*mapping)->id > map->id) &&
> - (map->id > v4l2_id) && next) {
> + (map->id > v4l2_id) &&
> + (uvc_ctrl_mapping_is_compound(map) ?
> + next_compound : next)) {
> *control = ctrl;
> *mapping = map;
> }
> @@ -1084,6 +1091,7 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
> struct uvc_control *ctrl = NULL;
> struct uvc_entity *entity;
> int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;
> + int next_compound = v4l2_id & V4L2_CTRL_FLAG_NEXT_COMPOUND;
>
> *mapping = NULL;
>
> @@ -1092,12 +1100,13 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
>
> /* Find the control. */
> list_for_each_entry(entity, &chain->entities, chain) {
> - __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
> - if (ctrl && !next)
> + __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next,
> + next_compound);
> + if (ctrl && !next && !next_compound)
> return ctrl;
> }
>
> - if (ctrl == NULL && !next)
> + if (!ctrl && !next && !next_compound)
> uvc_dbg(chain->dev, CONTROL, "Control 0x%08x not found\n",
> v4l2_id);
>
> @@ -1220,7 +1229,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
> 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;
> + bool find_next = req_id &
> + (V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND);
> unsigned int i;
>
> req_id &= V4L2_CTRL_ID_MASK;
> @@ -1310,10 +1320,12 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
> }
>
> __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
> - &master_ctrl, 0);
> + &master_ctrl, 0, 0);
>
> if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> return 0;
> + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
> + return -EIO;
>
> ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> if (ret >= 0 && val != mapping->master_manual)
> @@ -1377,10 +1389,15 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>
> if (mapping->master_id)
> __uvc_find_control(ctrl->entity, mapping->master_id,
> - &master_map, &master_ctrl, 0);
> + &master_map, &master_ctrl, 0, 0);
> if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> s32 val;
> - int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> + int ret;
> +
> + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
> + return -EIO;
> +
> + ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> if (ret < 0)
> return ret;
>
> @@ -1388,6 +1405,15 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> }
>
> + if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
> + v4l2_ctrl->default_value = 0;
> + v4l2_ctrl->minimum = 0;
> + v4l2_ctrl->maximum = 0;
> + v4l2_ctrl->step = 0;
> + return 0;
> + }
> +
> if (!ctrl->cached) {
> int ret = uvc_ctrl_populate_cache(chain, ctrl);
> if (ret < 0)
> @@ -1627,11 +1653,12 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
> u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
> s32 val = 0;
>
> - __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0);
> + __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0, 0);
> if (ctrl == NULL)
> return;
>
> - if (__uvc_ctrl_get(chain, ctrl, mapping, &val) == 0)
> + if (uvc_ctrl_mapping_is_compound(mapping) ||
> + __uvc_ctrl_get(chain, ctrl, mapping, &val) == 0)
> changes |= V4L2_EVENT_CTRL_CH_VALUE;
>
> uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
> @@ -1650,7 +1677,12 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
> ctrl->handle = NULL;
>
> list_for_each_entry(mapping, &ctrl->info.mappings, list) {
> - s32 value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data);
> + s32 value;
> +
> + if (uvc_ctrl_mapping_is_compound(mapping))
> + value = 0;
> + else
> + value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data);
>
> /*
> * handle may be NULL here if the device sends auto-update
> @@ -1736,6 +1768,7 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
>
> for (i = 0; i < xctrls_count; ++i) {
> u32 changes = V4L2_EVENT_CTRL_CH_VALUE;
> + s32 value;
>
> ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
> if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
> @@ -1760,6 +1793,10 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
> slave_id);
> }
>
> + if (uvc_ctrl_mapping_is_compound(mapping))
> + value = 0;
> + else
> + value = xctrls[i].value;
> /*
> * If the master is being modified in the same transaction
> * flags may change too.
> @@ -1770,7 +1807,7 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
> changes |= V4L2_EVENT_CTRL_CH_FLAGS;
>
> uvc_ctrl_send_event(handle->chain, handle, ctrl, mapping,
> - xctrls[i].value, changes);
> + value, changes);
> }
> }
>
> @@ -1802,7 +1839,8 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
> u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
> s32 val = 0;
>
> - if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
> + if (uvc_ctrl_mapping_is_compound(mapping) ||
> + __uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
> changes |= V4L2_EVENT_CTRL_CH_VALUE;
>
> uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val,
> @@ -1935,7 +1973,7 @@ static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
>
> for (i = 0; i < ctrls->count; i++) {
> __uvc_find_control(entity, ctrls->controls[i].id, &mapping,
> - &ctrl_found, 0);
> + &ctrl_found, 0, 0);
> if (uvc_control == ctrl_found)
> return i;
> }
> @@ -1971,19 +2009,59 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> return ret;
> }
>
> -int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> - struct v4l2_ext_control *xctrl)
> +static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + u32 which,
> + struct v4l2_ext_control *xctrl)
> {
> - struct uvc_control *ctrl;
> - struct uvc_control_mapping *mapping;
> -
> - if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
> - return -EACCES;
> + u8 *data __free(kfree) = NULL;
> + size_t size;
> + u8 query;
> + int ret;
> + int id;
>
> - ctrl = uvc_find_control(chain, xctrl->id, &mapping);
> - if (ctrl == NULL)
> + switch (which) {
> + case V4L2_CTRL_WHICH_CUR_VAL:
> + ret = __uvc_ctrl_load_cur(chain, ctrl);
> + if (ret < 0)
> + return ret;
> + id = UVC_CTRL_DATA_CURRENT;
> + query = UVC_GET_CUR;
> + break;
> + case V4L2_CTRL_WHICH_DEF_VAL:
> + ret = uvc_ctrl_populate_cache(chain, ctrl);
> + if (ret < 0)
> + return ret;
> + id = UVC_CTRL_DATA_DEF;
> + query = UVC_GET_DEF;
> + break;
> + default:
> return -EINVAL;
> + }
> +
> + size = DIV_ROUND_UP(mapping->size, 8);
> + if (xctrl->size < size) {
> + xctrl->size = size;
> + return -ENOSPC;
> + }
> +
> + data = kmalloc(size, GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + ret = mapping->get(mapping, query, uvc_ctrl_data(ctrl, id), size, data);
> + if (ret < 0)
> + return ret;
> +
> + return copy_to_user(xctrl->ptr, data, size) ? -EFAULT : 0;
> +}
>
> +static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + u32 which, struct v4l2_ext_control *xctrl)
> +{
> switch (which) {
> case V4L2_CTRL_WHICH_CUR_VAL:
> return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
> @@ -2002,6 +2080,33 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> return -EINVAL;
> }
>
> +static int uvc_mapping_get_xctrl(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + u32 which, struct v4l2_ext_control *xctrl)
> +{
> + if (uvc_ctrl_mapping_is_compound(mapping))
> + return uvc_mapping_get_xctrl_compound(chain, ctrl, mapping,
> + which, xctrl);
> + return uvc_mapping_get_xctrl_std(chain, ctrl, mapping, which, xctrl);
> +}
> +> +int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> + struct v4l2_ext_control *xctrl)
> +{
> + 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)
> + return -EINVAL;
> +
> + return uvc_mapping_get_xctrl(chain, ctrl, mapping, which, xctrl);
> +}
> +
> static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
> struct uvc_control *ctrl,
> struct uvc_control_mapping *mapping,
> @@ -2085,6 +2190,37 @@ static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
> return 0;
> }
>
> +static int uvc_mapping_set_xctrl_compound(struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + struct v4l2_ext_control *xctrl)
> +{
> + u8 *data __free(kfree) = NULL;
> + size_t size;
> +
> + size = DIV_ROUND_UP(mapping->size, 8);
> + if (xctrl->size != size)
> + return -EINVAL;
> +
> + data = memdup_user(xctrl->ptr, size);
> + if (IS_ERR(data))
> + return PTR_ERR(data);
> +
> + return mapping->set(mapping, size, data,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> +}
> +
> +static int uvc_mapping_set_xctrl(struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + struct v4l2_ext_control *xctrl)
> +{
> + if (uvc_ctrl_mapping_is_compound(mapping))
> + return uvc_mapping_set_xctrl_compound(ctrl, mapping, xctrl);
> +
> + uvc_mapping_set_s32(mapping, xctrl->value,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> + return 0;
> +}
> +
> int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
> {
> struct uvc_video_chain *chain = handle->chain;
> @@ -2122,8 +2258,9 @@ int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
> ctrl->info.size);
> }
>
> - uvc_mapping_set_s32(mapping, xctrl->value,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> + ret = uvc_mapping_set_xctrl(ctrl, mapping, xctrl);
> + if (ret)
> + return ret;
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
> ctrl->handle = handle;
> @@ -2501,6 +2638,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
> struct uvc_control_mapping *map;
> unsigned int size;
> unsigned int i;
> + int ret;
> > /*
> * Most mappings come from static kernel data, and need to be duplicated.
> @@ -2518,8 +2656,10 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
> /* For UVCIOC_CTRL_MAP custom control */
> if (mapping->name) {
> map->name = kstrdup(mapping->name, GFP_KERNEL);
> - if (!map->name)
> - goto err_nomem;
> + if (!map->name) {
> + ret = -ENOMEM;
> + goto free_mem;
> + }
> }
>
> INIT_LIST_HEAD(&map->ev_subs);
> @@ -2529,21 +2669,31 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
> * fls(mapping->menu_mask);
> map->menu_mapping = kmemdup(mapping->menu_mapping, size,
> GFP_KERNEL);
> - if (!map->menu_mapping)
> - goto err_nomem;
> + if (!map->menu_mapping) {
> + ret = -ENOMEM;
> + goto free_mem;
> + }
> }
> if (mapping->menu_names && mapping->menu_mask) {
> size = sizeof(mapping->menu_names[0])
> * fls(mapping->menu_mask);
> map->menu_names = kmemdup(mapping->menu_names, size,
> GFP_KERNEL);
> - if (!map->menu_names)
> - goto err_nomem;
> + if (!map->menu_names) {
> + ret = -ENOMEM;
> + goto free_mem;
> + }
> }
All the -ENOMEM related changes above introduce a lot of churn / make things harder
to review.
How about keeping everything above as is (except for introducing "int ret;"
and then ... see remark below at err_nomem label.
>
> - if (map->get == NULL)
> + if (uvc_ctrl_mapping_is_compound(map))
> + if (WARN_ON(!map->set || !map->get)) {
> + ret = -EIO;
> + goto free_mem;
> + }
> +
> + if (!map->get)
> map->get = uvc_get_le_value;
> - if (map->set == NULL)
> + if (!map->set)
> map->set = uvc_set_le_value;
>
> for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) {
These 2 changes replacing "if (map->Xet == NULL) with "if (!map->Xet)"
are unrelated style changes, please drop these.
> @@ -2561,12 +2711,12 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
>
> return 0;
>
And here (continued from above) then keep err_nomem and replace
free_mem with err_free_mem and set ret = -ENOMEM on err_nomem label:
err_nomem:
ret = -ENOMEM;
err_free_mem:
kfree(map->menu_names);
kfree(map->menu_mapping);
kfree(map->name);
kfree(map);
return ret;
}
I'm not 100% sold on this idea myself, but it does reduce the churn by quite a bit,
your choice if you want to follow my suggestion or not.
>
> int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 3d32a56c5ff8..f429f325433b 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -115,7 +115,12 @@ struct uvc_control_mapping {
> u8 entity[16];
> u8 selector;
>
> + /*
> + * Size of the control data in the payload of the UVC control GET and
> + * SET requests, expressed in bits.
> + */
> u8 size;
> +
> u8 offset;
> enum v4l2_ctrl_type v4l2_type;
> u32 data_type;
>
Otherwise this looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 12/19] media: uvcvideo: Factor out query_boundaries from query_ctrl
2024-11-14 19:10 ` [PATCH v15 12/19] media: uvcvideo: Factor out query_boundaries from query_ctrl Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
@ 2024-12-09 13:38 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 13:38 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> Split the function in two parts. queryctrl_boundaries will be used in
> future patches.
>
> No functional change expected from this patch.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 106 ++++++++++++++++++++++-----------------
> 1 file changed, 60 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index e51cd0a2228a..b591d7fddc37 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1367,53 +1367,11 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
> return ~0;
> }
>
> -static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> - struct uvc_control *ctrl,
> - struct uvc_control_mapping *mapping,
> - struct v4l2_queryctrl *v4l2_ctrl)
> +static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + struct v4l2_queryctrl *v4l2_ctrl)
> {
> - struct uvc_control_mapping *master_map = NULL;
> - struct uvc_control *master_ctrl = NULL;
> -
> - memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> - v4l2_ctrl->id = mapping->id;
> - v4l2_ctrl->type = mapping->v4l2_type;
> - strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping),
> - sizeof(v4l2_ctrl->name));
> - v4l2_ctrl->flags = 0;
> -
> - if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
> - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> -
> - if (mapping->master_id)
> - __uvc_find_control(ctrl->entity, mapping->master_id,
> - &master_map, &master_ctrl, 0, 0);
> - if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> - s32 val;
> - int ret;
> -
> - if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
> - return -EIO;
> -
> - ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> - if (ret < 0)
> - return ret;
> -
> - if (val != mapping->master_manual)
> - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> - }
> -
> - if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
> - v4l2_ctrl->default_value = 0;
> - v4l2_ctrl->minimum = 0;
> - v4l2_ctrl->maximum = 0;
> - v4l2_ctrl->step = 0;
> - return 0;
> - }
> -
> if (!ctrl->cached) {
> int ret = uvc_ctrl_populate_cache(chain, ctrl);
> if (ret < 0)
> @@ -1456,18 +1414,74 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
> v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> + else
> + v4l2_ctrl->minimum = 0;
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
> v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> + else
> + v4l2_ctrl->maximum = 0;
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
> v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> + else
> + v4l2_ctrl->step = 0;
>
> return 0;
> }
>
> +static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + struct v4l2_queryctrl *v4l2_ctrl)
> +{
> + struct uvc_control_mapping *master_map = NULL;
> + struct uvc_control *master_ctrl = NULL;
> +
> + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> + v4l2_ctrl->id = mapping->id;
> + v4l2_ctrl->type = mapping->v4l2_type;
> + strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping),
> + sizeof(v4l2_ctrl->name));
> + v4l2_ctrl->flags = 0;
> +
> + if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
> + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +
> + if (mapping->master_id)
> + __uvc_find_control(ctrl->entity, mapping->master_id,
> + &master_map, &master_ctrl, 0, 0);
> + if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
> + s32 val;
> + int ret;
> +
> + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
> + return -EIO;
> +
> + ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
> + if (ret < 0)
> + return ret;
> +
> + if (val != mapping->master_manual)
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> + }
> +
> + if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
> + v4l2_ctrl->default_value = 0;
> + v4l2_ctrl->minimum = 0;
> + v4l2_ctrl->maximum = 0;
> + v4l2_ctrl->step = 0;
> + return 0;
> + }
> +
> + return __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl);
> +}
> +
> int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> struct v4l2_queryctrl *v4l2_ctrl)
> {
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 13/19] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL
2024-11-14 19:10 ` [PATCH v15 13/19] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL Ricardo Ribalda
@ 2024-12-09 13:47 ` Hans de Goede
0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 13:47 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Yunke Cao
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> From: Yunke Cao <yunkec@google.com>
>
> Add support for V4L2_CTRL_WHICH_MIN/MAX_VAL in uvc driver.
> It is needed for the V4L2_CID_UVC_REGION_OF_INTEREST_RECT control.
>
> Signed-off-by: Yunke Cao <yunkec@google.com>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 96 ++++++++++++++++++++++++++++++++--------
> drivers/media/usb/uvc/uvc_v4l2.c | 2 +
> 2 files changed, 79 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index b591d7fddc37..0dae5e8c3ca0 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1270,6 +1270,37 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
> return 0;
> }
>
> +static bool uvc_ctrl_is_readable(u32 which, struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping)
> +{
> + if (which == V4L2_CTRL_WHICH_CUR_VAL)
> + return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR);
> +
> + if (which == V4L2_CTRL_WHICH_DEF_VAL)
> + return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF);
> +
> + /* Types with implicit boundaries. */
> + switch (mapping->v4l2_type) {
> + case V4L2_CTRL_TYPE_MENU:
> + case V4L2_CTRL_TYPE_BOOLEAN:
> + case V4L2_CTRL_TYPE_BUTTON:
> + return true;
> + case V4L2_CTRL_TYPE_BITMASK:
> + return (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) ||
> + (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX);
> + default:
> + break;
> + }
> +
> + if (which == V4L2_CTRL_WHICH_MIN_VAL)
> + return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN);
> +
> + if (which == V4L2_CTRL_WHICH_MAX_VAL)
> + return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX);
> +
> + return false;
> +}
> +
> /*
> * Check if control @v4l2_id can be accessed by the given control @ioctl
> * (VIDIOC_G_EXT_CTRLS, VIDIOC_TRY_EXT_CTRLS or VIDIOC_S_EXT_CTRLS).
> @@ -1288,7 +1319,6 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
> struct uvc_control *master_ctrl = NULL;
> struct uvc_control_mapping *mapping;
> struct uvc_control *ctrl;
> - bool read = ioctl == VIDIOC_G_EXT_CTRLS;
> s32 val;
> int ret;
> int i;
> @@ -1300,10 +1330,10 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
> if (!ctrl)
> return -EINVAL;
>
> - if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) && read)
> - return -EACCES;
> + if (ioctl == VIDIOC_G_EXT_CTRLS)
> + return uvc_ctrl_is_readable(ctrls->which, ctrl, mapping);
>
> - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read)
> + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> return -EACCES;
>
> if (ioctl != VIDIOC_S_EXT_CTRLS || !mapping->master_id)
> @@ -1451,6 +1481,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
> if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> + if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) &&
> + (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN))
> + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX;
>
> if (mapping->master_id)
> __uvc_find_control(ctrl->entity, mapping->master_id,
> @@ -2037,16 +2070,18 @@ static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
>
> switch (which) {
> case V4L2_CTRL_WHICH_CUR_VAL:
> - ret = __uvc_ctrl_load_cur(chain, ctrl);
> - if (ret < 0)
> - return ret;
> id = UVC_CTRL_DATA_CURRENT;
> query = UVC_GET_CUR;
> break;
> + case V4L2_CTRL_WHICH_MIN_VAL:
> + id = UVC_CTRL_DATA_MIN;
> + query = UVC_GET_MIN;
> + break;
> + case V4L2_CTRL_WHICH_MAX_VAL:
> + id = UVC_CTRL_DATA_MAX;
> + query = UVC_GET_MAX;
> + break;
> case V4L2_CTRL_WHICH_DEF_VAL:
> - ret = uvc_ctrl_populate_cache(chain, ctrl);
> - if (ret < 0)
> - return ret;
> id = UVC_CTRL_DATA_DEF;
> query = UVC_GET_DEF;
> break;
> @@ -2064,6 +2099,14 @@ static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
> if (!data)
> return -ENOMEM;
>
> + if (which == V4L2_CTRL_WHICH_CUR_VAL)
> + ret = __uvc_ctrl_load_cur(chain, ctrl);
> + else
> + ret = uvc_ctrl_populate_cache(chain, ctrl);
> +
> + if (ret < 0)
> + return ret;
> +
> ret = mapping->get(mapping, query, uvc_ctrl_data(ctrl, id), size, data);
> if (ret < 0)
> return ret;
> @@ -2076,22 +2119,37 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
> struct uvc_control_mapping *mapping,
> u32 which, struct v4l2_ext_control *xctrl)
> {
> + struct v4l2_queryctrl qc;
> + int ret;
> +
> switch (which) {
> case V4L2_CTRL_WHICH_CUR_VAL:
> return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
> case V4L2_CTRL_WHICH_DEF_VAL:
> - if (!ctrl->cached) {
> - int ret = uvc_ctrl_populate_cache(chain, ctrl);
> + case V4L2_CTRL_WHICH_MIN_VAL:
> + case V4L2_CTRL_WHICH_MAX_VAL:
> + break;
> + default:
> + return -EINVAL;
> + }
>
> - if (ret < 0)
> - return ret;
> - }
> - xctrl->value = uvc_mapping_get_s32(mapping, UVC_GET_DEF,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> - return 0;
> + ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qc);
> + if (ret < 0)
> + return ret;
> +
> + switch (which) {
> + case V4L2_CTRL_WHICH_DEF_VAL:
> + xctrl->value = qc.default_value;
> + break;
> + case V4L2_CTRL_WHICH_MIN_VAL:
> + xctrl->value = qc.minimum;
> + break;
> + case V4L2_CTRL_WHICH_MAX_VAL:
> + xctrl->value = qc.maximum;
> + break;
> }
>
> - return -EINVAL;
> + return 0;
> }
>
> static int uvc_mapping_get_xctrl(struct uvc_video_chain *chain,
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 65dbb53b1e75..7e284770149d 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1087,6 +1087,8 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
> switch (ctrls->which) {
> case V4L2_CTRL_WHICH_DEF_VAL:
> case V4L2_CTRL_WHICH_CUR_VAL:
> + case V4L2_CTRL_WHICH_MAX_VAL:
> + case V4L2_CTRL_WHICH_MIN_VAL:
> which = ctrls->which;
> break;
> default:
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 11/19] media: uvcvideo: add support for compound controls
2024-11-14 19:10 ` [PATCH v15 11/19] media: uvcvideo: add support for compound controls Ricardo Ribalda
2024-12-09 13:35 ` Hans de Goede
@ 2024-12-09 13:58 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 13:58 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Yunke Cao
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> From: Yunke Cao <yunkec@google.com>
>
> This patch adds support for compound controls. This is required to
> support controls that cannot be represented with a s64 data, such as the
> Region of Interest.
>
> Signed-off-by: Yunke Cao <yunkec@google.com>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 224 ++++++++++++++++++++++++++++++++-------
> drivers/media/usb/uvc/uvcvideo.h | 5 +
> 2 files changed, 192 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 893d12cd3f90..e51cd0a2228a 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
<snip>
> @@ -1971,19 +2009,59 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
> return ret;
> }
>
> -int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
> - struct v4l2_ext_control *xctrl)
> +static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl,
> + struct uvc_control_mapping *mapping,
> + u32 which,
> + struct v4l2_ext_control *xctrl)
> {
> - struct uvc_control *ctrl;
> - struct uvc_control_mapping *mapping;
> -
> - if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
> - return -EACCES;
> + u8 *data __free(kfree) = NULL;
> + size_t size;
> + u8 query;
> + int ret;
> + int id;
>
> - ctrl = uvc_find_control(chain, xctrl->id, &mapping);
> - if (ctrl == NULL)
> + switch (which) {
> + case V4L2_CTRL_WHICH_CUR_VAL:
> + ret = __uvc_ctrl_load_cur(chain, ctrl);
> + if (ret < 0)
> + return ret;
> + id = UVC_CTRL_DATA_CURRENT;
> + query = UVC_GET_CUR;
> + break;
> + case V4L2_CTRL_WHICH_DEF_VAL:
> + ret = uvc_ctrl_populate_cache(chain, ctrl);
> + if (ret < 0)
> + return ret;
> + id = UVC_CTRL_DATA_DEF;
> + query = UVC_GET_DEF;
> + break;
> + default:
> return -EINVAL;
> + }
> +
> + size = DIV_ROUND_UP(mapping->size, 8);
> + if (xctrl->size < size) {
> + xctrl->size = size;
> + return -ENOSPC;
> + }
> +
> + data = kmalloc(size, GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + ret = mapping->get(mapping, query, uvc_ctrl_data(ctrl, id), size, data);
> + if (ret < 0)
> + return ret;
> +
> + return copy_to_user(xctrl->ptr, data, size) ? -EFAULT : 0;
> +}
While reviewing "[PATCH v15 14/19] media: uvcvideo: Use the camera to clamp compound controls"
I realized that this copy_to_user() is somewhat unexpected. Normally we let the v4l2 core
ioctl wrapper take care of this.
Since there is no room in struct v4l2_ext_control to store the data I guess this is ok,
but IMHO this does at least need a comment explaining how this is a special case.
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 14/19] media: uvcvideo: Use the camera to clamp compound controls
2024-11-14 19:10 ` [PATCH v15 14/19] media: uvcvideo: Use the camera to clamp compound controls Ricardo Ribalda
@ 2024-12-09 14:05 ` Hans de Goede
2024-12-09 14:46 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 14:05 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> Compound controls cannot e reliable clamped. There is plenty of space
> for interpretation for the device manufacturer.
>
> When we write a compound control, let the camera do the clamping and
> return back to the user the value used by the device.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 0dae5e8c3ca0..72ed7dc9cfc1 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -2339,6 +2339,18 @@ int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
>
> ctrl->dirty = 1;
> ctrl->modified = 1;
> +
> + /*
> + * Compound controls cannot reliable clamp the value when they are
> + * written to the device. Let the device do the clamping and read back
> + * the value that the device is using. We do not need to return an
> + * error if this fails.
> + */
> + if (uvc_ctrl_mapping_is_compound(mapping) &&
> + uvc_ctrl_is_readable(V4L2_CTRL_WHICH_CUR_VAL, ctrl, mapping))
> + uvc_mapping_get_xctrl_compound(chain, ctrl, mapping,
> + V4L2_CTRL_WHICH_CUR_VAL, xctrl);
> +
I do not believe that this actually works / does what you want it to do.
At this point we have only updated in memory structures for the control
and not send anything to camera.
Querying the control to return the actual achieved values to userspace
only makes sense after uvc_ctrl_commit() has succeeded, unless I am
missing something ?
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl
2024-11-14 19:10 ` [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
@ 2024-12-09 14:08 ` Hans de Goede
2024-12-09 14:12 ` Ricardo Ribalda
1 sibling, 1 reply; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 14:08 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> v4l2_query_ext_ctrl contains information that is missing in
> v4l2_queryctrl, like elem_size and elems.
>
> With this change we can handle all the element_size information inside
> uvc_ctrl.c.
>
> Now that we are at it, remove the memset of the reserved fields, the
> v4l2 ioctl handler should do that for us.
>
> There is no functional change expected from this change.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Doesn't the v4l2-core ioctl wrapping offers queryctrl emulation
using query_ext_ctrl ? If not maybe that should be added there?
(this can be done later)
Othwerise looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 24 ++++++++++++++----------
> drivers/media/usb/uvc/uvc_v4l2.c | 35 +++++++++++++++--------------------
> drivers/media/usb/uvc/uvcvideo.h | 2 +-
> 3 files changed, 30 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 72ed7dc9cfc1..1bc019138995 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1252,7 +1252,8 @@ static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
> }
>
> static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
> - u32 found_id, struct v4l2_queryctrl *v4l2_ctrl)
> + u32 found_id,
> + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> {
> int idx;
>
> @@ -1400,7 +1401,7 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
> static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> struct uvc_control *ctrl,
> struct uvc_control_mapping *mapping,
> - struct v4l2_queryctrl *v4l2_ctrl)
> + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> {
> if (!ctrl->cached) {
> int ret = uvc_ctrl_populate_cache(chain, ctrl);
> @@ -1465,7 +1466,7 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> struct uvc_control *ctrl,
> struct uvc_control_mapping *mapping,
> - struct v4l2_queryctrl *v4l2_ctrl)
> + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> {
> struct uvc_control_mapping *master_map = NULL;
> struct uvc_control *master_ctrl = NULL;
> @@ -1503,6 +1504,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> }
>
> + v4l2_ctrl->elem_size = sizeof(s32);
> + v4l2_ctrl->elems = 1;
> +
> if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
> v4l2_ctrl->default_value = 0;
> @@ -1516,7 +1520,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> }
>
> int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> - struct v4l2_queryctrl *v4l2_ctrl)
> + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> {
> struct uvc_control *ctrl;
> struct uvc_control_mapping *mapping;
> @@ -1642,7 +1646,7 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
> struct uvc_control_mapping *mapping,
> s32 value, u32 changes)
> {
> - struct v4l2_queryctrl v4l2_ctrl;
> + struct v4l2_query_ext_ctrl v4l2_ctrl;
>
> __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
>
> @@ -2119,7 +2123,7 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
> struct uvc_control_mapping *mapping,
> u32 which, struct v4l2_ext_control *xctrl)
> {
> - struct v4l2_queryctrl qc;
> + struct v4l2_query_ext_ctrl qec;
> int ret;
>
> switch (which) {
> @@ -2133,19 +2137,19 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
> return -EINVAL;
> }
>
> - ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qc);
> + ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qec);
> if (ret < 0)
> return ret;
>
> switch (which) {
> case V4L2_CTRL_WHICH_DEF_VAL:
> - xctrl->value = qc.default_value;
> + xctrl->value = qec.default_value;
> break;
> case V4L2_CTRL_WHICH_MIN_VAL:
> - xctrl->value = qc.minimum;
> + xctrl->value = qec.minimum;
> break;
> case V4L2_CTRL_WHICH_MAX_VAL:
> - xctrl->value = qc.maximum;
> + xctrl->value = qec.maximum;
> break;
> }
>
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 7e284770149d..5000c74271e0 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1014,40 +1014,35 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
> return ret;
> }
>
> -static int uvc_ioctl_queryctrl(struct file *file, void *fh,
> - struct v4l2_queryctrl *qc)
> +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
> + struct v4l2_query_ext_ctrl *qec)
> {
> struct uvc_fh *handle = fh;
> struct uvc_video_chain *chain = handle->chain;
>
> - return uvc_query_v4l2_ctrl(chain, qc);
> + return uvc_query_v4l2_ctrl(chain, qec);
> }
>
> -static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
> - struct v4l2_query_ext_ctrl *qec)
> +static int uvc_ioctl_queryctrl(struct file *file, void *fh,
> + struct v4l2_queryctrl *qc)
> {
> struct uvc_fh *handle = fh;
> struct uvc_video_chain *chain = handle->chain;
> - struct v4l2_queryctrl qc = { qec->id };
> + struct v4l2_query_ext_ctrl qec = { qc->id };
> int ret;
>
> - ret = uvc_query_v4l2_ctrl(chain, &qc);
> + ret = uvc_query_v4l2_ctrl(chain, &qec);
> if (ret)
> return ret;
>
> - qec->id = qc.id;
> - qec->type = qc.type;
> - strscpy(qec->name, qc.name, sizeof(qec->name));
> - qec->minimum = qc.minimum;
> - qec->maximum = qc.maximum;
> - qec->step = qc.step;
> - qec->default_value = qc.default_value;
> - qec->flags = qc.flags;
> - qec->elem_size = 4;
> - qec->elems = 1;
> - qec->nr_of_dims = 0;
> - memset(qec->dims, 0, sizeof(qec->dims));
> - memset(qec->reserved, 0, sizeof(qec->reserved));
> + qc->id = qec.id;
> + qc->type = qec.type;
> + strscpy(qc->name, qec.name, sizeof(qc->name));
> + qc->minimum = qec.minimum;
> + qc->maximum = qec.maximum;
> + qc->step = qec.step;
> + qc->default_value = qec.default_value;
> + qc->flags = qec.flags;
>
> return 0;
> }
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index f429f325433b..8aca1a2fe587 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -766,7 +766,7 @@ void uvc_status_put(struct uvc_device *dev);
> extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
>
> int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> - struct v4l2_queryctrl *v4l2_ctrl);
> + struct v4l2_query_ext_ctrl *v4l2_ctrl);
> int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
> struct v4l2_querymenu *query_menu);
>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 16/19] media: uvcvideo: Introduce uvc_mapping_v4l2_size
2024-11-14 19:10 ` [PATCH v15 16/19] media: uvcvideo: Introduce uvc_mapping_v4l2_size Ricardo Ribalda
2024-12-09 8:51 ` Yunke Cao
@ 2024-12-09 14:09 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 14:09 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> Centralize the calculation for the v4l2_size of a mapping.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 15 +++++++++++----
> 1 file changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 1bc019138995..f262e05ad3a8 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1463,6 +1463,14 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> return 0;
> }
>
> +static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
> +{
> + if (uvc_ctrl_mapping_is_compound(mapping))
> + return DIV_ROUND_UP(mapping->size, 8);
> +
> + return sizeof(s32);
> +}
> +
> static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> struct uvc_control *ctrl,
> struct uvc_control_mapping *mapping,
> @@ -1504,7 +1512,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> }
>
> - v4l2_ctrl->elem_size = sizeof(s32);
> + v4l2_ctrl->elem_size = uvc_mapping_v4l2_size(mapping);
> v4l2_ctrl->elems = 1;
>
> if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> @@ -2093,7 +2101,7 @@ static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
> return -EINVAL;
> }
>
> - size = DIV_ROUND_UP(mapping->size, 8);
> + size = uvc_mapping_v4l2_size(mapping);
> if (xctrl->size < size) {
> xctrl->size = size;
> return -ENOSPC;
> @@ -2271,9 +2279,8 @@ static int uvc_mapping_set_xctrl_compound(struct uvc_control *ctrl,
> struct v4l2_ext_control *xctrl)
> {
> u8 *data __free(kfree) = NULL;
> - size_t size;
> + size_t size = uvc_mapping_v4l2_size(mapping);
>
> - size = DIV_ROUND_UP(mapping->size, 8);
> if (xctrl->size != size)
> return -EINVAL;
>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map
2024-11-14 19:10 ` [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map Ricardo Ribalda
2024-11-29 8:15 ` Ricardo Ribalda
@ 2024-12-09 14:11 ` Hans de Goede
2024-12-09 14:15 ` Ricardo Ribalda
1 sibling, 1 reply; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 14:11 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> Do not process unknown data types.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_v4l2.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 5000c74271e0..4c88dab15554 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -106,6 +106,12 @@ static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain,
> struct uvc_control_mapping *map;
> int ret;
>
> + if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) {
> + uvc_dbg(chain->dev, CONTROL,
> + "Unsupported UVC data type %u\n", xmap->data_type);
> + return -ENOTTY;
This seems like a textbook case for -EINVAL ?
Otherwise patch looks good to me:
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Regards,
Hans
> + }
> +
> map = kzalloc(sizeof(*map), GFP_KERNEL);
> if (map == NULL)
> return -ENOMEM;
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl
2024-12-09 14:08 ` Hans de Goede
@ 2024-12-09 14:12 ` Ricardo Ribalda
0 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-12-09 14:12 UTC (permalink / raw)
To: Hans de Goede
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Ricardo Ribalda,
Sakari Ailus, Hans Verkuil, Yunke Cao, linux-media, linux-kernel
On Mon, 9 Dec 2024 at 15:09, Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> > v4l2_query_ext_ctrl contains information that is missing in
> > v4l2_queryctrl, like elem_size and elems.
> >
> > With this change we can handle all the element_size information inside
> > uvc_ctrl.c.
> >
> > Now that we are at it, remove the memset of the reserved fields, the
> > v4l2 ioctl handler should do that for us.
> >
> > There is no functional change expected from this change.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
>
> Doesn't the v4l2-core ioctl wrapping offers queryctrl emulation
> using query_ext_ctrl ? If not maybe that should be added there?
> (this can be done later)
It does not look like. I also thought about that, but then I realised
that most of the drivers use the ctrl framework and then this is not
needed.
But anyway, as you said, it can be done later. I will add it to my todo :).
Regards!
>
> Othwerise looks good to me:
>
> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
>
> Regards,
>
> Hans
>
>
>
>
> > ---
> > drivers/media/usb/uvc/uvc_ctrl.c | 24 ++++++++++++++----------
> > drivers/media/usb/uvc/uvc_v4l2.c | 35 +++++++++++++++--------------------
> > drivers/media/usb/uvc/uvcvideo.h | 2 +-
> > 3 files changed, 30 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index 72ed7dc9cfc1..1bc019138995 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -1252,7 +1252,8 @@ static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
> > }
> >
> > static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
> > - u32 found_id, struct v4l2_queryctrl *v4l2_ctrl)
> > + u32 found_id,
> > + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> > {
> > int idx;
> >
> > @@ -1400,7 +1401,7 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
> > static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> > struct uvc_control *ctrl,
> > struct uvc_control_mapping *mapping,
> > - struct v4l2_queryctrl *v4l2_ctrl)
> > + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> > {
> > if (!ctrl->cached) {
> > int ret = uvc_ctrl_populate_cache(chain, ctrl);
> > @@ -1465,7 +1466,7 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> > static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> > struct uvc_control *ctrl,
> > struct uvc_control_mapping *mapping,
> > - struct v4l2_queryctrl *v4l2_ctrl)
> > + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> > {
> > struct uvc_control_mapping *master_map = NULL;
> > struct uvc_control *master_ctrl = NULL;
> > @@ -1503,6 +1504,9 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> > v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
> > }
> >
> > + v4l2_ctrl->elem_size = sizeof(s32);
> > + v4l2_ctrl->elems = 1;
> > +
> > if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) {
> > v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
> > v4l2_ctrl->default_value = 0;
> > @@ -1516,7 +1520,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> > }
> >
> > int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> > - struct v4l2_queryctrl *v4l2_ctrl)
> > + struct v4l2_query_ext_ctrl *v4l2_ctrl)
> > {
> > struct uvc_control *ctrl;
> > struct uvc_control_mapping *mapping;
> > @@ -1642,7 +1646,7 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
> > struct uvc_control_mapping *mapping,
> > s32 value, u32 changes)
> > {
> > - struct v4l2_queryctrl v4l2_ctrl;
> > + struct v4l2_query_ext_ctrl v4l2_ctrl;
> >
> > __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
> >
> > @@ -2119,7 +2123,7 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
> > struct uvc_control_mapping *mapping,
> > u32 which, struct v4l2_ext_control *xctrl)
> > {
> > - struct v4l2_queryctrl qc;
> > + struct v4l2_query_ext_ctrl qec;
> > int ret;
> >
> > switch (which) {
> > @@ -2133,19 +2137,19 @@ static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain,
> > return -EINVAL;
> > }
> >
> > - ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qc);
> > + ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qec);
> > if (ret < 0)
> > return ret;
> >
> > switch (which) {
> > case V4L2_CTRL_WHICH_DEF_VAL:
> > - xctrl->value = qc.default_value;
> > + xctrl->value = qec.default_value;
> > break;
> > case V4L2_CTRL_WHICH_MIN_VAL:
> > - xctrl->value = qc.minimum;
> > + xctrl->value = qec.minimum;
> > break;
> > case V4L2_CTRL_WHICH_MAX_VAL:
> > - xctrl->value = qc.maximum;
> > + xctrl->value = qec.maximum;
> > break;
> > }
> >
> > diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> > index 7e284770149d..5000c74271e0 100644
> > --- a/drivers/media/usb/uvc/uvc_v4l2.c
> > +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> > @@ -1014,40 +1014,35 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
> > return ret;
> > }
> >
> > -static int uvc_ioctl_queryctrl(struct file *file, void *fh,
> > - struct v4l2_queryctrl *qc)
> > +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
> > + struct v4l2_query_ext_ctrl *qec)
> > {
> > struct uvc_fh *handle = fh;
> > struct uvc_video_chain *chain = handle->chain;
> >
> > - return uvc_query_v4l2_ctrl(chain, qc);
> > + return uvc_query_v4l2_ctrl(chain, qec);
> > }
> >
> > -static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
> > - struct v4l2_query_ext_ctrl *qec)
> > +static int uvc_ioctl_queryctrl(struct file *file, void *fh,
> > + struct v4l2_queryctrl *qc)
> > {
> > struct uvc_fh *handle = fh;
> > struct uvc_video_chain *chain = handle->chain;
> > - struct v4l2_queryctrl qc = { qec->id };
> > + struct v4l2_query_ext_ctrl qec = { qc->id };
> > int ret;
> >
> > - ret = uvc_query_v4l2_ctrl(chain, &qc);
> > + ret = uvc_query_v4l2_ctrl(chain, &qec);
> > if (ret)
> > return ret;
> >
> > - qec->id = qc.id;
> > - qec->type = qc.type;
> > - strscpy(qec->name, qc.name, sizeof(qec->name));
> > - qec->minimum = qc.minimum;
> > - qec->maximum = qc.maximum;
> > - qec->step = qc.step;
> > - qec->default_value = qc.default_value;
> > - qec->flags = qc.flags;
> > - qec->elem_size = 4;
> > - qec->elems = 1;
> > - qec->nr_of_dims = 0;
> > - memset(qec->dims, 0, sizeof(qec->dims));
> > - memset(qec->reserved, 0, sizeof(qec->reserved));
> > + qc->id = qec.id;
> > + qc->type = qec.type;
> > + strscpy(qc->name, qec.name, sizeof(qc->name));
> > + qc->minimum = qec.minimum;
> > + qc->maximum = qec.maximum;
> > + qc->step = qec.step;
> > + qc->default_value = qec.default_value;
> > + qc->flags = qec.flags;
> >
> > return 0;
> > }
> > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > index f429f325433b..8aca1a2fe587 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -766,7 +766,7 @@ void uvc_status_put(struct uvc_device *dev);
> > extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
> >
> > int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> > - struct v4l2_queryctrl *v4l2_ctrl);
> > + struct v4l2_query_ext_ctrl *v4l2_ctrl);
> > int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
> > struct v4l2_querymenu *query_menu);
> >
> >
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map
2024-12-09 14:11 ` Hans de Goede
@ 2024-12-09 14:15 ` Ricardo Ribalda
0 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-12-09 14:15 UTC (permalink / raw)
To: Hans de Goede
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Ricardo Ribalda,
Sakari Ailus, Hans Verkuil, Yunke Cao, linux-media, linux-kernel
On Mon, 9 Dec 2024 at 15:12, Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> > Do not process unknown data types.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/usb/uvc/uvc_v4l2.c | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> > index 5000c74271e0..4c88dab15554 100644
> > --- a/drivers/media/usb/uvc/uvc_v4l2.c
> > +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> > @@ -106,6 +106,12 @@ static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain,
> > struct uvc_control_mapping *map;
> > int ret;
> >
> > + if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) {
> > + uvc_dbg(chain->dev, CONTROL,
> > + "Unsupported UVC data type %u\n", xmap->data_type);
> > + return -ENOTTY;
>
> This seems like a textbook case for -EINVAL ?
Indeed, :) https://lore.kernel.org/linux-media/8258ce59-cd06-46ba-b275-97eb9ae4d64c@redhat.com/T/#m2d38a4cf184ad3e4ea335e92ea74258d1da267c1
Thanks!
>
> Otherwise patch looks good to me:
>
> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
>
> Regards,
>
> Hans
>
>
>
> > + }
> > +
> > map = kzalloc(sizeof(*map), GFP_KERNEL);
> > if (map == NULL)
> > return -ENOMEM;
> >
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-11-14 19:10 ` [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI Ricardo Ribalda
2024-11-14 19:53 ` Gergo Koteles
2024-12-02 8:02 ` Yunke Cao
@ 2024-12-09 14:22 ` Hans de Goede
2024-12-09 15:23 ` Ricardo Ribalda
2 siblings, 1 reply; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 14:22 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Yunke Cao
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> From: Yunke Cao <yunkec@google.com>
>
> Implement support for ROI as described in UVC 1.5:
> 4.2.2.1.20 Digital Region of Interest (ROI) Control
>
> ROI control is implemented using V4L2 control API as
> two UVC-specific controls:
> V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
> V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
>
> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> Signed-off-by: Yunke Cao <yunkec@google.com>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++++++++++++++++++++
> drivers/media/usb/uvc/uvcvideo.h | 7 ++++
> include/uapi/linux/usb/video.h | 1 +
> include/uapi/linux/uvcvideo.h | 13 ++++++
> include/uapi/linux/v4l2-controls.h | 9 +++++
> 5 files changed, 111 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index f262e05ad3a8..5b619ef40dd3 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -358,6 +358,24 @@ static const struct uvc_control_info uvc_ctrls[] = {
> .flags = UVC_CTRL_FLAG_GET_CUR
> | UVC_CTRL_FLAG_AUTO_UPDATE,
> },
> + /*
> + * UVC_CTRL_FLAG_AUTO_UPDATE is needed because the RoI may get updated
> + * by sensors.
> + * "This RoI should be the same as specified in most recent SET_CUR
> + * except in the case where the ‘Auto Detect and Track’ and/or
> + * ‘Image Stabilization’ bit have been set."
> + * 4.2.2.1.20 Digital Region of Interest (ROI) Control
> + */
> + {
> + .entity = UVC_GUID_UVC_CAMERA,
> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> + .index = 21,
> + .size = 10,
> + .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
> + | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> + | UVC_CTRL_FLAG_GET_DEF
> + | UVC_CTRL_FLAG_AUTO_UPDATE,
> + },
> };
>
> static const u32 uvc_control_classes[] = {
> @@ -603,6 +621,44 @@ static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
> return out_mapping;
> }
>
> +static int uvc_get_rect(struct uvc_control_mapping *mapping, u8 query,
> + const void *uvc_in, size_t v4l2_size, void *v4l2_out)
> +{
> + const struct uvc_rect *uvc_rect = uvc_in;
> + struct v4l2_rect *v4l2_rect = v4l2_out;
> +
> + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> + return -EINVAL;
> +
> + if (uvc_rect->left > uvc_rect->right ||
> + uvc_rect->top > uvc_rect->bottom)
> + return -EIO;
> +
> + v4l2_rect->top = uvc_rect->top;
> + v4l2_rect->left = uvc_rect->left;
> + v4l2_rect->height = uvc_rect->bottom - uvc_rect->top + 1;
> + v4l2_rect->width = uvc_rect->right - uvc_rect->left + 1;
> +
> + return 0;
> +}
> +
> +static int uvc_set_rect(struct uvc_control_mapping *mapping, size_t v4l2_size,
> + const void *v4l2_in, void *uvc_out)
> +{
> + struct uvc_rect *uvc_rect = uvc_out;
> + const struct v4l2_rect *v4l2_rect = v4l2_in;
> +
> + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> + return -EINVAL;
> +
> + uvc_rect->top = max(0xffff, v4l2_rect->top);
> + uvc_rect->left = max(0xffff, v4l2_rect->left);
> + uvc_rect->bottom = max(0xffff, v4l2_rect->height + v4l2_rect->top - 1);
> + uvc_rect->right = max(0xffff, v4l2_rect->width + v4l2_rect->left - 1);
As already remarked all 4 lines should be min() not max()
Also this might just be me, but I have a preference for writing top + height
for the bottom rather then writing height + top, since the window starts with
skippig top pixels and then has height pixels filled in. And same for
calculating rect->width. IOW I have a preference for writing this as:
uvc_rect->bottom = min(0xffff, v4l2_rect->top + v4l2_rect->height - 1);
uvc_rect->right = min(0xffff, v4l2_rect->left + v4l2_rect->width - 1);
As I said this might just be me, but to me the above reads more naturally.
> +
> + return 0;
> +}
> +
> static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> {
> .id = V4L2_CID_BRIGHTNESS,
> @@ -897,6 +953,28 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
> .filter_mapping = uvc_ctrl_filter_plf_mapping,
> },
> + {
> + .id = V4L2_CID_UVC_REGION_OF_INTEREST_RECT,
> + .entity = UVC_GUID_UVC_CAMERA,
> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> + .size = sizeof(struct uvc_rect) * 8,
> + .offset = 0,
> + .v4l2_type = V4L2_CTRL_TYPE_RECT,
> + .data_type = UVC_CTRL_DATA_TYPE_RECT,
> + .get = uvc_get_rect,
> + .set = uvc_set_rect,
> + .name = "Region Of Interest Rectangle",
> + },
> + {
> + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> + .entity = UVC_GUID_UVC_CAMERA,
> + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> + .size = 16,
> + .offset = 64,
> + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> + .name = "Region Of Interest Auto Controls",
> + },
> };
>
> /* ------------------------------------------------------------------------
> @@ -1465,6 +1543,9 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
>
> static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
> {
> + if (mapping->v4l2_type == V4L2_CTRL_TYPE_RECT)
> + return sizeof(struct v4l2_rect);
> +
> if (uvc_ctrl_mapping_is_compound(mapping))
> return DIV_ROUND_UP(mapping->size, 8);
>
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 8aca1a2fe587..d910a5e5b514 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -294,6 +294,13 @@ struct uvc_streaming_header {
> u8 bTriggerUsage;
> };
>
> +struct uvc_rect {
> + u16 top;
> + u16 left;
> + u16 bottom;
> + u16 right;
> +} __packed;
> +
This should probably be grouped togather with uvc_status_* structs which are
also marked __packed because they represent hw API rather then just host
in memory structures.
> enum uvc_buffer_state {
> UVC_BUF_STATE_IDLE = 0,
> UVC_BUF_STATE_QUEUED = 1,
> diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
> index 2ff0e8a3a683..2afb4420e6c4 100644
> --- a/include/uapi/linux/usb/video.h
> +++ b/include/uapi/linux/usb/video.h
> @@ -104,6 +104,7 @@
> #define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f
> #define UVC_CT_ROLL_RELATIVE_CONTROL 0x10
> #define UVC_CT_PRIVACY_CONTROL 0x11
> +#define UVC_CT_REGION_OF_INTEREST_CONTROL 0x14
>
> /* A.9.5. Processing Unit Control Selectors */
> #define UVC_PU_CONTROL_UNDEFINED 0x00
> diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> index f86185456dc5..cbe15bca9569 100644
> --- a/include/uapi/linux/uvcvideo.h
> +++ b/include/uapi/linux/uvcvideo.h
> @@ -16,6 +16,7 @@
> #define UVC_CTRL_DATA_TYPE_BOOLEAN 3
> #define UVC_CTRL_DATA_TYPE_ENUM 4
> #define UVC_CTRL_DATA_TYPE_BITMASK 5
> +#define UVC_CTRL_DATA_TYPE_RECT 6
>
> /* Control flags */
> #define UVC_CTRL_FLAG_SET_CUR (1 << 0)
> @@ -38,6 +39,18 @@
>
> #define UVC_MENU_NAME_LEN 32
>
> +/* V4L2 driver-specific controls */
> +#define V4L2_CID_UVC_REGION_OF_INTEREST_RECT (V4L2_CID_USER_UVC_BASE + 1)
> +#define V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (V4L2_CID_USER_UVC_BASE + 2)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE (1 << 0)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS (1 << 1)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE (1 << 2)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS (1 << 3)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT (1 << 4)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK (1 << 5)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION (1 << 6)
> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY (1 << 7)
> +
Hmm, shoudn't these be standardized. At least the ROI rect control seems like
something which could be standardized ?
Was using driver specific CIDs for this discussed with Hans Verkuil ?
> struct uvc_menu_info {
> __u32 value;
> __u8 name[UVC_MENU_NAME_LEN];
> diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
> index 974fd254e573..6c91d6fa4708 100644
> --- a/include/uapi/linux/v4l2-controls.h
> +++ b/include/uapi/linux/v4l2-controls.h
> @@ -215,6 +215,13 @@ enum v4l2_colorfx {
> */
> #define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0)
>
> +/*
> + * The base for the uvc driver controls.
> + * See linux/uvcvideo.h for the list of controls.
> + * We reserve 64 controls for this driver.
> + */
> +#define V4L2_CID_USER_UVC_BASE (V4L2_CID_USER_BASE + 0x11e0)
> +
> /* MPEG-class control IDs */
> /* The MPEG controls are applicable to all codec controls
> * and the 'MPEG' part of the define is historical */
> @@ -1089,6 +1096,8 @@ enum v4l2_auto_focus_range {
>
> #define V4L2_CID_HDR_SENSOR_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
>
> +/* CAMERA-class private control IDs */
> +
> /* FM Modulator class control IDs */
>
> #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
>
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 19/19] media: uvcvideo: document UVC v1.5 ROI
2024-11-14 19:10 ` [PATCH v15 19/19] media: uvcvideo: document " Ricardo Ribalda
@ 2024-12-09 14:36 ` Hans de Goede
2024-12-09 15:22 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 14:36 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Ricardo Ribalda, Sakari Ailus, Hans Verkuil
Cc: Yunke Cao, linux-media, linux-kernel, Yunke Cao,
Sergey Senozhatsky
Hi,
On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> From: Yunke Cao <yunkec@google.com>
>
> Added documentation of V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
> V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
>
> An example of a userspace implementing this feature can be found at:
> https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/release-R121-15699.B/camera/hal/usb/
>
> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
> Signed-off-by: Yunke Cao <yunkec@google.com>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---> .../userspace-api/media/drivers/uvcvideo.rst | 64 ++++++++++++++++++++++
> 1 file changed, 64 insertions(+)
>
> diff --git a/Documentation/userspace-api/media/drivers/uvcvideo.rst b/Documentation/userspace-api/media/drivers/uvcvideo.rst
> index a290f9fadae9..1cdcd45907a3 100644
> --- a/Documentation/userspace-api/media/drivers/uvcvideo.rst
> +++ b/Documentation/userspace-api/media/drivers/uvcvideo.rst
> @@ -181,6 +181,7 @@ Argument: struct uvc_xu_control_mapping
> UVC_CTRL_DATA_TYPE_BOOLEAN Boolean
> UVC_CTRL_DATA_TYPE_ENUM Enumeration
> UVC_CTRL_DATA_TYPE_BITMASK Bitmask
> + UVC_CTRL_DATA_TYPE_RECT Rectangular area
>
>
> UVCIOC_CTRL_QUERY - Query a UVC XU control
> @@ -255,3 +256,66 @@ Argument: struct uvc_xu_control_query
> __u8 query Request code to send to the device
> __u16 size Control data size (in bytes)
> __u8 *data Control value
> +
> +
> +Driver-specific V4L2 controls
> +-----------------------------
> +
> +The uvcvideo driver implements the following UVC-specific controls:
> +
> +``V4L2_CID_UVC_REGION_OF_INTEREST_RECT (struct)``
> + This control determines the region of interest (ROI). ROI is a
> + rectangular area represented by a struct :c:type:`v4l2_rect`. The
> + rectangle is in global sensor coordinates and pixel units. It is
Maybe: "The rectangle is in global sensor coordinates using pixel units" ?
being "in pixel units" sounds a bit weird and had me confused for a moment.
> + independent of the field of view, not impacted by any cropping or
> + scaling.
> +
> + Use ``V4L2_CTRL_WHICH_MIN_VAL`` and ``V4L2_CTRL_WHICH_MAX_VAL`` to query
> + the range of rectangle sizes.
> +
> + Setting a ROI allows the camera to optimize the capture for the region.
> + The value of ``V4L2_CID_REGION_OF_INTEREST_AUTO`` control determines
> + the detailed behavior.
> +
> + An example of use of this control, can be found in the:
> + `Chrome OS USB camera HAL.
> + <https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/release-R121-15699.B/camera/hal/usb/>`
Hmm, not sure we want this in the API documentation. OTOH why not ? Anyone else
have an opinion on this ?
> +
> +
> +``V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (bitmask)``
> + This determines which, if any, on-board features should track to the
> + Region of Interest specified by the current value of
> + ``V4L2_CID_UVD__REGION_OF_INTEREST_RECT``.
> +
> + Max value is a mask indicating all supported Auto Controls.
> +
> +.. flat-table::
> + :header-rows: 0
> + :stub-columns: 0
> +
> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE``
> + - Setting this bit causes automatic exposure to track the region of
> + interest instead of the whole image.
> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS``
> + - Setting this bit causes automatic iris to track the region of interest
> + instead of the whole image.
> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE``
> + - Setting this bit causes automatic white balance to track the region
> + of interest instead of the whole image.
> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS``
> + - Setting this bit causes automatic focus adjustment to track the region
> + of interest instead of the whole image.
> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT``
> + - Setting this bit causes automatic face detection to track the region of
> + interest instead of the whole image.
> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK``
> + - Setting this bit enables automatic face detection and tracking. The
> + current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by
> + the driver.
> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION``
> + - Setting this bit enables automatic image stabilization. The
> + current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by
> + the driver.
This one I do not understand. Since the ROI is not a crop, I don't see how
this interacts with image-stabilization. Typically digital image-stabilization
uses a moving slightly smaller crop of the full sensor rectangle which it moves
around in realtime to compensate for camera movements.
So I wonder what this is expected to do. Does this set the ROI to the image
stabilization crop ? I guess that combined with reading back the ROI that might be
somewhat useful to follow what the image stabilization code is doing.
OTOH this does not seem useful for using as region for AEC / AWB ?
> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY``
> + - Setting this bit enables automatically capture the specified region
> + with higher quality if possible.
>
Otherwise this looks good to me. But I would still like to see
a discussion about using UVC custom ctrls instead of something standardized
for this. Although I guess maybe that already happened before I got involved ?
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 14/19] media: uvcvideo: Use the camera to clamp compound controls
2024-12-09 14:05 ` Hans de Goede
@ 2024-12-09 14:46 ` Ricardo Ribalda
0 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2024-12-09 14:46 UTC (permalink / raw)
To: Hans de Goede
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Ricardo Ribalda,
Sakari Ailus, Hans Verkuil, Yunke Cao, linux-media, linux-kernel
On Mon, 9 Dec 2024 at 15:05, Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> > Compound controls cannot e reliable clamped. There is plenty of space
> > for interpretation for the device manufacturer.
> >
> > When we write a compound control, let the camera do the clamping and
> > return back to the user the value used by the device.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> > 1 file changed, 12 insertions(+)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index 0dae5e8c3ca0..72ed7dc9cfc1 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -2339,6 +2339,18 @@ int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
> >
> > ctrl->dirty = 1;
> > ctrl->modified = 1;
> > +
> > + /*
> > + * Compound controls cannot reliable clamp the value when they are
> > + * written to the device. Let the device do the clamping and read back
> > + * the value that the device is using. We do not need to return an
> > + * error if this fails.
> > + */
> > + if (uvc_ctrl_mapping_is_compound(mapping) &&
> > + uvc_ctrl_is_readable(V4L2_CTRL_WHICH_CUR_VAL, ctrl, mapping))
> > + uvc_mapping_get_xctrl_compound(chain, ctrl, mapping,
> > + V4L2_CTRL_WHICH_CUR_VAL, xctrl);
> > +
>
> I do not believe that this actually works / does what you want it to do.
>
> At this point we have only updated in memory structures for the control
> and not send anything to camera.
>
> Querying the control to return the actual achieved values to userspace
> only makes sense after uvc_ctrl_commit() has succeeded, unless I am
> missing something ?
You are absolutely correct. Sorry about that.
Let's drop it for now.
Thanks!
>
> Regards,
>
> Hans
>
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 19/19] media: uvcvideo: document UVC v1.5 ROI
2024-12-09 14:36 ` Hans de Goede
@ 2024-12-09 15:22 ` Ricardo Ribalda
2024-12-09 15:31 ` Hans de Goede
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-12-09 15:22 UTC (permalink / raw)
To: Hans de Goede
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Ricardo Ribalda,
Sakari Ailus, Hans Verkuil, Yunke Cao, linux-media, linux-kernel,
Yunke Cao, Sergey Senozhatsky
Hi Hans
On Mon, 9 Dec 2024 at 15:36, Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> > From: Yunke Cao <yunkec@google.com>
> >
> > Added documentation of V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
> > V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
> >
> > An example of a userspace implementing this feature can be found at:
> > https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/release-R121-15699.B/camera/hal/usb/
> >
> > Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> > Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
> > Signed-off-by: Yunke Cao <yunkec@google.com>
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---> .../userspace-api/media/drivers/uvcvideo.rst | 64 ++++++++++++++++++++++
> > 1 file changed, 64 insertions(+)
> >
> > diff --git a/Documentation/userspace-api/media/drivers/uvcvideo.rst b/Documentation/userspace-api/media/drivers/uvcvideo.rst
> > index a290f9fadae9..1cdcd45907a3 100644
> > --- a/Documentation/userspace-api/media/drivers/uvcvideo.rst
> > +++ b/Documentation/userspace-api/media/drivers/uvcvideo.rst
> > @@ -181,6 +181,7 @@ Argument: struct uvc_xu_control_mapping
> > UVC_CTRL_DATA_TYPE_BOOLEAN Boolean
> > UVC_CTRL_DATA_TYPE_ENUM Enumeration
> > UVC_CTRL_DATA_TYPE_BITMASK Bitmask
> > + UVC_CTRL_DATA_TYPE_RECT Rectangular area
> >
> >
> > UVCIOC_CTRL_QUERY - Query a UVC XU control
> > @@ -255,3 +256,66 @@ Argument: struct uvc_xu_control_query
> > __u8 query Request code to send to the device
> > __u16 size Control data size (in bytes)
> > __u8 *data Control value
> > +
> > +
> > +Driver-specific V4L2 controls
> > +-----------------------------
> > +
> > +The uvcvideo driver implements the following UVC-specific controls:
> > +
> > +``V4L2_CID_UVC_REGION_OF_INTEREST_RECT (struct)``
> > + This control determines the region of interest (ROI). ROI is a
> > + rectangular area represented by a struct :c:type:`v4l2_rect`. The
> > + rectangle is in global sensor coordinates and pixel units. It is
>
> Maybe: "The rectangle is in global sensor coordinates using pixel units" ?
>
> being "in pixel units" sounds a bit weird and had me confused for a moment.
>
> > + independent of the field of view, not impacted by any cropping or
> > + scaling.
> > +
> > + Use ``V4L2_CTRL_WHICH_MIN_VAL`` and ``V4L2_CTRL_WHICH_MAX_VAL`` to query
> > + the range of rectangle sizes.
> > +
> > + Setting a ROI allows the camera to optimize the capture for the region.
> > + The value of ``V4L2_CID_REGION_OF_INTEREST_AUTO`` control determines
> > + the detailed behavior.
> > +
> > + An example of use of this control, can be found in the:
> > + `Chrome OS USB camera HAL.
> > + <https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/release-R121-15699.B/camera/hal/usb/>`
>
> Hmm, not sure we want this in the API documentation. OTOH why not ? Anyone else
> have an opinion on this ?
Laurent requested this:
https://lore.kernel.org/linux-media/20231218034413.GN5290@pendragon.ideasonboard.com/
>
> > +
> > +
> > +``V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (bitmask)``
> > + This determines which, if any, on-board features should track to the
> > + Region of Interest specified by the current value of
> > + ``V4L2_CID_UVD__REGION_OF_INTEREST_RECT``.
> > +
> > + Max value is a mask indicating all supported Auto Controls.
> > +
> > +.. flat-table::
> > + :header-rows: 0
> > + :stub-columns: 0
> > +
> > + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE``
> > + - Setting this bit causes automatic exposure to track the region of
> > + interest instead of the whole image.
> > + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS``
> > + - Setting this bit causes automatic iris to track the region of interest
> > + instead of the whole image.
> > + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE``
> > + - Setting this bit causes automatic white balance to track the region
> > + of interest instead of the whole image.
> > + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS``
> > + - Setting this bit causes automatic focus adjustment to track the region
> > + of interest instead of the whole image.
> > + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT``
> > + - Setting this bit causes automatic face detection to track the region of
> > + interest instead of the whole image.
> > + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK``
> > + - Setting this bit enables automatic face detection and tracking. The
> > + current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by
> > + the driver.
> > + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION``
> > + - Setting this bit enables automatic image stabilization. The
> > + current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by
> > + the driver.
>
> This one I do not understand. Since the ROI is not a crop, I don't see how
> this interacts with image-stabilization. Typically digital image-stabilization
> uses a moving slightly smaller crop of the full sensor rectangle which it moves
> around in realtime to compensate for camera movements.
>
> So I wonder what this is expected to do. Does this set the ROI to the image
> stabilization crop ? I guess that combined with reading back the ROI that might be
> somewhat useful to follow what the image stabilization code is doing.
>
> OTOH this does not seem useful for using as region for AEC / AWB ?
Unfortunately, the standard is not very verbose about this:
https://ibb.co/VppnQ43
What about:
- ``Image Stabilization`` bit from the UVC's bmAutoControls Region of
Interest Control.
?
>
>
> > + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY``
> > + - Setting this bit enables automatically capture the specified region
> > + with higher quality if possible.
> >
>
> Otherwise this looks good to me. But I would still like to see
> a discussion about using UVC custom ctrls instead of something standardized
> for this. Although I guess maybe that already happened before I got involved ?
Seems like both Hans V and Laurent preferred uvc custom controls:
https://lore.kernel.org/linux-media/a0fe2b49-12b7-8eaf-c3ef-7af1a247e595@xs4all.nl/
>
> Regards,
>
> Hans
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-12-09 14:22 ` Hans de Goede
@ 2024-12-09 15:23 ` Ricardo Ribalda
2024-12-09 15:28 ` Hans de Goede
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2024-12-09 15:23 UTC (permalink / raw)
To: Hans de Goede
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Ricardo Ribalda,
Sakari Ailus, Hans Verkuil, Yunke Cao, linux-media, linux-kernel,
Yunke Cao
Hi Hans
On Mon, 9 Dec 2024 at 15:22, Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
> > From: Yunke Cao <yunkec@google.com>
> >
> > Implement support for ROI as described in UVC 1.5:
> > 4.2.2.1.20 Digital Region of Interest (ROI) Control
> >
> > ROI control is implemented using V4L2 control API as
> > two UVC-specific controls:
> > V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
> > V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
> >
> > Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> > Signed-off-by: Yunke Cao <yunkec@google.com>
> > ---
> > drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++++++++++++++++++++
> > drivers/media/usb/uvc/uvcvideo.h | 7 ++++
> > include/uapi/linux/usb/video.h | 1 +
> > include/uapi/linux/uvcvideo.h | 13 ++++++
> > include/uapi/linux/v4l2-controls.h | 9 +++++
> > 5 files changed, 111 insertions(+)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index f262e05ad3a8..5b619ef40dd3 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -358,6 +358,24 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > .flags = UVC_CTRL_FLAG_GET_CUR
> > | UVC_CTRL_FLAG_AUTO_UPDATE,
> > },
> > + /*
> > + * UVC_CTRL_FLAG_AUTO_UPDATE is needed because the RoI may get updated
> > + * by sensors.
> > + * "This RoI should be the same as specified in most recent SET_CUR
> > + * except in the case where the ‘Auto Detect and Track’ and/or
> > + * ‘Image Stabilization’ bit have been set."
> > + * 4.2.2.1.20 Digital Region of Interest (ROI) Control
> > + */
> > + {
> > + .entity = UVC_GUID_UVC_CAMERA,
> > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > + .index = 21,
> > + .size = 10,
> > + .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
> > + | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> > + | UVC_CTRL_FLAG_GET_DEF
> > + | UVC_CTRL_FLAG_AUTO_UPDATE,
> > + },
> > };
> >
> > static const u32 uvc_control_classes[] = {
> > @@ -603,6 +621,44 @@ static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
> > return out_mapping;
> > }
> >
> > +static int uvc_get_rect(struct uvc_control_mapping *mapping, u8 query,
> > + const void *uvc_in, size_t v4l2_size, void *v4l2_out)
> > +{
> > + const struct uvc_rect *uvc_rect = uvc_in;
> > + struct v4l2_rect *v4l2_rect = v4l2_out;
> > +
> > + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> > + return -EINVAL;
> > +
> > + if (uvc_rect->left > uvc_rect->right ||
> > + uvc_rect->top > uvc_rect->bottom)
> > + return -EIO;
> > +
> > + v4l2_rect->top = uvc_rect->top;
> > + v4l2_rect->left = uvc_rect->left;
> > + v4l2_rect->height = uvc_rect->bottom - uvc_rect->top + 1;
> > + v4l2_rect->width = uvc_rect->right - uvc_rect->left + 1;
> > +
> > + return 0;
> > +}
> > +
> > +static int uvc_set_rect(struct uvc_control_mapping *mapping, size_t v4l2_size,
> > + const void *v4l2_in, void *uvc_out)
> > +{
> > + struct uvc_rect *uvc_rect = uvc_out;
> > + const struct v4l2_rect *v4l2_rect = v4l2_in;
> > +
> > + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect)))
> > + return -EINVAL;
> > +
> > + uvc_rect->top = max(0xffff, v4l2_rect->top);
> > + uvc_rect->left = max(0xffff, v4l2_rect->left);
> > + uvc_rect->bottom = max(0xffff, v4l2_rect->height + v4l2_rect->top - 1);
> > + uvc_rect->right = max(0xffff, v4l2_rect->width + v4l2_rect->left - 1);
>
> As already remarked all 4 lines should be min() not max()
>
> Also this might just be me, but I have a preference for writing top + height
> for the bottom rather then writing height + top, since the window starts with
> skippig top pixels and then has height pixels filled in. And same for
> calculating rect->width. IOW I have a preference for writing this as:
>
> uvc_rect->bottom = min(0xffff, v4l2_rect->top + v4l2_rect->height - 1);
> uvc_rect->right = min(0xffff, v4l2_rect->left + v4l2_rect->width - 1);
>
> As I said this might just be me, but to me the above reads more naturally.
>
>
>
>
> > +
> > + return 0;
> > +}
> > +
> > static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > {
> > .id = V4L2_CID_BRIGHTNESS,
> > @@ -897,6 +953,28 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
> > .filter_mapping = uvc_ctrl_filter_plf_mapping,
> > },
> > + {
> > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_RECT,
> > + .entity = UVC_GUID_UVC_CAMERA,
> > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > + .size = sizeof(struct uvc_rect) * 8,
> > + .offset = 0,
> > + .v4l2_type = V4L2_CTRL_TYPE_RECT,
> > + .data_type = UVC_CTRL_DATA_TYPE_RECT,
> > + .get = uvc_get_rect,
> > + .set = uvc_set_rect,
> > + .name = "Region Of Interest Rectangle",
> > + },
> > + {
> > + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO,
> > + .entity = UVC_GUID_UVC_CAMERA,
> > + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
> > + .size = 16,
> > + .offset = 64,
> > + .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
> > + .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > + .name = "Region Of Interest Auto Controls",
> > + },
> > };
> >
> > /* ------------------------------------------------------------------------
> > @@ -1465,6 +1543,9 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> >
> > static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping)
> > {
> > + if (mapping->v4l2_type == V4L2_CTRL_TYPE_RECT)
> > + return sizeof(struct v4l2_rect);
> > +
> > if (uvc_ctrl_mapping_is_compound(mapping))
> > return DIV_ROUND_UP(mapping->size, 8);
> >
> > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > index 8aca1a2fe587..d910a5e5b514 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -294,6 +294,13 @@ struct uvc_streaming_header {
> > u8 bTriggerUsage;
> > };
> >
> > +struct uvc_rect {
> > + u16 top;
> > + u16 left;
> > + u16 bottom;
> > + u16 right;
> > +} __packed;
> > +
>
> This should probably be grouped togather with uvc_status_* structs which are
> also marked __packed because they represent hw API rather then just host
> in memory structures.
>
> > enum uvc_buffer_state {
> > UVC_BUF_STATE_IDLE = 0,
> > UVC_BUF_STATE_QUEUED = 1,
> > diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
> > index 2ff0e8a3a683..2afb4420e6c4 100644
> > --- a/include/uapi/linux/usb/video.h
> > +++ b/include/uapi/linux/usb/video.h
> > @@ -104,6 +104,7 @@
> > #define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f
> > #define UVC_CT_ROLL_RELATIVE_CONTROL 0x10
> > #define UVC_CT_PRIVACY_CONTROL 0x11
> > +#define UVC_CT_REGION_OF_INTEREST_CONTROL 0x14
> >
> > /* A.9.5. Processing Unit Control Selectors */
> > #define UVC_PU_CONTROL_UNDEFINED 0x00
> > diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> > index f86185456dc5..cbe15bca9569 100644
> > --- a/include/uapi/linux/uvcvideo.h
> > +++ b/include/uapi/linux/uvcvideo.h
> > @@ -16,6 +16,7 @@
> > #define UVC_CTRL_DATA_TYPE_BOOLEAN 3
> > #define UVC_CTRL_DATA_TYPE_ENUM 4
> > #define UVC_CTRL_DATA_TYPE_BITMASK 5
> > +#define UVC_CTRL_DATA_TYPE_RECT 6
> >
> > /* Control flags */
> > #define UVC_CTRL_FLAG_SET_CUR (1 << 0)
> > @@ -38,6 +39,18 @@
> >
> > #define UVC_MENU_NAME_LEN 32
> >
> > +/* V4L2 driver-specific controls */
> > +#define V4L2_CID_UVC_REGION_OF_INTEREST_RECT (V4L2_CID_USER_UVC_BASE + 1)
> > +#define V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (V4L2_CID_USER_UVC_BASE + 2)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE (1 << 0)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS (1 << 1)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE (1 << 2)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS (1 << 3)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT (1 << 4)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK (1 << 5)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION (1 << 6)
> > +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY (1 << 7)
> > +
>
> Hmm, shoudn't these be standardized. At least the ROI rect control seems like
> something which could be standardized ?
I believe that back in 2022 we deciced to go with custom controls:
https://lore.kernel.org/linux-media/a0fe2b49-12b7-8eaf-c3ef-7af1a247e595@xs4all.nl/
>
> Was using driver specific CIDs for this discussed with Hans Verkuil ?
>
> > struct uvc_menu_info {
> > __u32 value;
> > __u8 name[UVC_MENU_NAME_LEN];
> > diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
> > index 974fd254e573..6c91d6fa4708 100644
> > --- a/include/uapi/linux/v4l2-controls.h
> > +++ b/include/uapi/linux/v4l2-controls.h
> > @@ -215,6 +215,13 @@ enum v4l2_colorfx {
> > */
> > #define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0)
> >
> > +/*
> > + * The base for the uvc driver controls.
> > + * See linux/uvcvideo.h for the list of controls.
> > + * We reserve 64 controls for this driver.
> > + */
> > +#define V4L2_CID_USER_UVC_BASE (V4L2_CID_USER_BASE + 0x11e0)
> > +
> > /* MPEG-class control IDs */
> > /* The MPEG controls are applicable to all codec controls
> > * and the 'MPEG' part of the define is historical */
> > @@ -1089,6 +1096,8 @@ enum v4l2_auto_focus_range {
> >
> > #define V4L2_CID_HDR_SENSOR_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
> >
> > +/* CAMERA-class private control IDs */
> > +
> > /* FM Modulator class control IDs */
> >
> > #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
> >
>
>
> Regards,
>
> Hans
>
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI
2024-12-09 15:23 ` Ricardo Ribalda
@ 2024-12-09 15:28 ` Hans de Goede
0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 15:28 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Ricardo Ribalda,
Sakari Ailus, Hans Verkuil, Yunke Cao, linux-media, linux-kernel,
Yunke Cao
Hi Ricardo,
On 9-Dec-24 4:23 PM, Ricardo Ribalda wrote:
> Hi Hans
>
> On Mon, 9 Dec 2024 at 15:22, Hans de Goede <hdegoede@redhat.com> wrote:
<snip>
>>> diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
>>> index f86185456dc5..cbe15bca9569 100644
>>> --- a/include/uapi/linux/uvcvideo.h
>>> +++ b/include/uapi/linux/uvcvideo.h
>>> @@ -16,6 +16,7 @@
>>> #define UVC_CTRL_DATA_TYPE_BOOLEAN 3
>>> #define UVC_CTRL_DATA_TYPE_ENUM 4
>>> #define UVC_CTRL_DATA_TYPE_BITMASK 5
>>> +#define UVC_CTRL_DATA_TYPE_RECT 6
>>>
>>> /* Control flags */
>>> #define UVC_CTRL_FLAG_SET_CUR (1 << 0)
>>> @@ -38,6 +39,18 @@
>>>
>>> #define UVC_MENU_NAME_LEN 32
>>>
>>> +/* V4L2 driver-specific controls */
>>> +#define V4L2_CID_UVC_REGION_OF_INTEREST_RECT (V4L2_CID_USER_UVC_BASE + 1)
>>> +#define V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (V4L2_CID_USER_UVC_BASE + 2)
>>> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE (1 << 0)
>>> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS (1 << 1)
>>> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE (1 << 2)
>>> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS (1 << 3)
>>> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT (1 << 4)
>>> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK (1 << 5)
>>> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION (1 << 6)
>>> +#define V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY (1 << 7)
>>> +
>>
>> Hmm, shoudn't these be standardized. At least the ROI rect control seems like
>> something which could be standardized ?
>
> I believe that back in 2022 we deciced to go with custom controls:
> https://lore.kernel.org/linux-media/a0fe2b49-12b7-8eaf-c3ef-7af1a247e595@xs4all.nl/
Ok that is good enough for me. I just wanted to make sure this was already looked
at as a possible generic ctrl.
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v15 19/19] media: uvcvideo: document UVC v1.5 ROI
2024-12-09 15:22 ` Ricardo Ribalda
@ 2024-12-09 15:31 ` Hans de Goede
0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2024-12-09 15:31 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Ricardo Ribalda,
Sakari Ailus, Hans Verkuil, Yunke Cao, linux-media, linux-kernel,
Yunke Cao, Sergey Senozhatsky
Hi,
On 9-Dec-24 4:22 PM, Ricardo Ribalda wrote:
> Hi Hans
>
> On Mon, 9 Dec 2024 at 15:36, Hans de Goede <hdegoede@redhat.com> wrote:
>>
>> Hi,
>>
>> On 14-Nov-24 8:10 PM, Ricardo Ribalda wrote:
>>> From: Yunke Cao <yunkec@google.com>
>>>
>>> Added documentation of V4L2_CID_UVC_REGION_OF_INTEREST_RECT and
>>> V4L2_CID_UVC_REGION_OF_INTEREST_AUTO.
>>>
>>> An example of a userspace implementing this feature can be found at:
>>> https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/release-R121-15699.B/camera/hal/usb/
>>>
>>> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
>>> Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
>>> Signed-off-by: Yunke Cao <yunkec@google.com>
>>> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
>>> ---> .../userspace-api/media/drivers/uvcvideo.rst | 64 ++++++++++++++++++++++
>>> 1 file changed, 64 insertions(+)
>>>
>>> diff --git a/Documentation/userspace-api/media/drivers/uvcvideo.rst b/Documentation/userspace-api/media/drivers/uvcvideo.rst
>>> index a290f9fadae9..1cdcd45907a3 100644
>>> --- a/Documentation/userspace-api/media/drivers/uvcvideo.rst
>>> +++ b/Documentation/userspace-api/media/drivers/uvcvideo.rst
>>> @@ -181,6 +181,7 @@ Argument: struct uvc_xu_control_mapping
>>> UVC_CTRL_DATA_TYPE_BOOLEAN Boolean
>>> UVC_CTRL_DATA_TYPE_ENUM Enumeration
>>> UVC_CTRL_DATA_TYPE_BITMASK Bitmask
>>> + UVC_CTRL_DATA_TYPE_RECT Rectangular area
>>>
>>>
>>> UVCIOC_CTRL_QUERY - Query a UVC XU control
>>> @@ -255,3 +256,66 @@ Argument: struct uvc_xu_control_query
>>> __u8 query Request code to send to the device
>>> __u16 size Control data size (in bytes)
>>> __u8 *data Control value
>>> +
>>> +
>>> +Driver-specific V4L2 controls
>>> +-----------------------------
>>> +
>>> +The uvcvideo driver implements the following UVC-specific controls:
>>> +
>>> +``V4L2_CID_UVC_REGION_OF_INTEREST_RECT (struct)``
>>> + This control determines the region of interest (ROI). ROI is a
>>> + rectangular area represented by a struct :c:type:`v4l2_rect`. The
>>> + rectangle is in global sensor coordinates and pixel units. It is
>>
>> Maybe: "The rectangle is in global sensor coordinates using pixel units" ?
>>
>> being "in pixel units" sounds a bit weird and had me confused for a moment.
>>
>>> + independent of the field of view, not impacted by any cropping or
>>> + scaling.
>>> +
>>> + Use ``V4L2_CTRL_WHICH_MIN_VAL`` and ``V4L2_CTRL_WHICH_MAX_VAL`` to query
>>> + the range of rectangle sizes.
>>> +
>>> + Setting a ROI allows the camera to optimize the capture for the region.
>>> + The value of ``V4L2_CID_REGION_OF_INTEREST_AUTO`` control determines
>>> + the detailed behavior.
>>> +
>>> + An example of use of this control, can be found in the:
>>> + `Chrome OS USB camera HAL.
>>> + <https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/release-R121-15699.B/camera/hal/usb/>`
>>
>> Hmm, not sure we want this in the API documentation. OTOH why not ? Anyone else
>> have an opinion on this ?
>
> Laurent requested this:
> https://lore.kernel.org/linux-media/20231218034413.GN5290@pendragon.ideasonboard.com/
Ok, keeping this as is works for me.
>>> +
>>> +
>>> +``V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (bitmask)``
>>> + This determines which, if any, on-board features should track to the
>>> + Region of Interest specified by the current value of
>>> + ``V4L2_CID_UVD__REGION_OF_INTEREST_RECT``.
>>> +
>>> + Max value is a mask indicating all supported Auto Controls.
>>> +
>>> +.. flat-table::
>>> + :header-rows: 0
>>> + :stub-columns: 0
>>> +
>>> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_EXPOSURE``
>>> + - Setting this bit causes automatic exposure to track the region of
>>> + interest instead of the whole image.
>>> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_IRIS``
>>> + - Setting this bit causes automatic iris to track the region of interest
>>> + instead of the whole image.
>>> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_WHITE_BALANCE``
>>> + - Setting this bit causes automatic white balance to track the region
>>> + of interest instead of the whole image.
>>> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_FOCUS``
>>> + - Setting this bit causes automatic focus adjustment to track the region
>>> + of interest instead of the whole image.
>>> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_FACE_DETECT``
>>> + - Setting this bit causes automatic face detection to track the region of
>>> + interest instead of the whole image.
>>> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK``
>>> + - Setting this bit enables automatic face detection and tracking. The
>>> + current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by
>>> + the driver.
>>> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION``
>>> + - Setting this bit enables automatic image stabilization. The
>>> + current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by
>>> + the driver.
>>
>> This one I do not understand. Since the ROI is not a crop, I don't see how
>> this interacts with image-stabilization. Typically digital image-stabilization
>> uses a moving slightly smaller crop of the full sensor rectangle which it moves
>> around in realtime to compensate for camera movements.
>>
>> So I wonder what this is expected to do. Does this set the ROI to the image
>> stabilization crop ? I guess that combined with reading back the ROI that might be
>> somewhat useful to follow what the image stabilization code is doing.
>>
>> OTOH this does not seem useful for using as region for AEC / AWB ?
>
> Unfortunately, the standard is not very verbose about this:
> https://ibb.co/VppnQ43
>
> What about:
>
> - ``Image Stabilization`` bit from the UVC's bmAutoControls Region of
> Interest Control.
> > ?
I have no strong preference for either the current wording or the new
wording you just suggested. Either one seems pretty vague / unclear to me,
but I realize that is just the result of the specification being unclear
on this point.
So use what you think is best and then we'll just have to live with
this being a bit vague.
>>> + * - ``V4L2_UVC_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY``
>>> + - Setting this bit enables automatically capture the specified region
>>> + with higher quality if possible.
>>>
>>
>> Otherwise this looks good to me. But I would still like to see
>> a discussion about using UVC custom ctrls instead of something standardized
>> for this. Although I guess maybe that already happened before I got involved ?
>
> Seems like both Hans V and Laurent preferred uvc custom controls:
>
> https://lore.kernel.org/linux-media/a0fe2b49-12b7-8eaf-c3ef-7af1a247e595@xs4all.nl
Ack.
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
end of thread, other threads:[~2024-12-09 15:31 UTC | newest]
Thread overview: 62+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-14 19:10 [PATCH v15 00/19] media: uvcvideo: Implement UVC v1.5 ROI Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 01/19] media: uvcvideo: Fix event flags in uvc_ctrl_send_events Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 02/19] media: v4l2_ctrl: Add V4L2_CTRL_TYPE_RECT Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 03/19] media: v4l2-ctrls: add support for V4L2_CTRL_WHICH_MIN/MAX_VAL Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 04/19] media: vivid: Add a rectangle control Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 05/19] media: uvcvideo: Handle uvc menu translation inside uvc_get_le_value Ricardo Ribalda
2024-11-25 15:50 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 06/19] media: uvcvideo: Handle uvc menu translation inside uvc_set_le_value Ricardo Ribalda
2024-11-25 15:58 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 07/19] media: uvcvideo: refactor uvc_ioctl_g_ext_ctrls Ricardo Ribalda
2024-11-25 16:01 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 08/19] media: uvcvideo: uvc_ioctl_(g|s)_ext_ctrls: handle NoP case Ricardo Ribalda
2024-11-25 16:01 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 09/19] media: uvcvideo: Support any size for mapping get/set Ricardo Ribalda
2024-12-09 8:56 ` Yunke Cao
2024-12-09 12:49 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 10/19] media: uvcvideo: Factor out clamping from uvc_ctrl_set Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
2024-12-09 12:57 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 11/19] media: uvcvideo: add support for compound controls Ricardo Ribalda
2024-12-09 13:35 ` Hans de Goede
2024-12-09 13:58 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 12/19] media: uvcvideo: Factor out query_boundaries from query_ctrl Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
2024-12-09 13:38 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 13/19] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL Ricardo Ribalda
2024-12-09 13:47 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 14/19] media: uvcvideo: Use the camera to clamp compound controls Ricardo Ribalda
2024-12-09 14:05 ` Hans de Goede
2024-12-09 14:46 ` Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 15/19] media: uvcvideo: let v4l2_query_v4l2_ctrl() work with v4l2_query_ext_ctrl Ricardo Ribalda
2024-12-09 8:50 ` Yunke Cao
2024-12-09 14:08 ` Hans de Goede
2024-12-09 14:12 ` Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 16/19] media: uvcvideo: Introduce uvc_mapping_v4l2_size Ricardo Ribalda
2024-12-09 8:51 ` Yunke Cao
2024-12-09 14:09 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 17/19] media: uvcvideo: Add sanity check to uvc_ioctl_xu_ctrl_map Ricardo Ribalda
2024-11-29 8:15 ` Ricardo Ribalda
2024-12-09 14:11 ` Hans de Goede
2024-12-09 14:15 ` Ricardo Ribalda
2024-11-14 19:10 ` [PATCH v15 18/19] media: uvcvideo: implement UVC v1.5 ROI Ricardo Ribalda
2024-11-14 19:53 ` Gergo Koteles
2024-11-14 20:03 ` Ricardo Ribalda
2024-11-14 20:16 ` Gergo Koteles
2024-11-14 20:28 ` Ricardo Ribalda
2024-11-15 0:04 ` Gergo Koteles
2024-11-15 8:22 ` Ricardo Ribalda
2024-11-18 15:59 ` Hans de Goede
2024-11-18 16:16 ` Ricardo Ribalda Delgado
2024-11-25 14:27 ` Hans de Goede
2024-12-02 8:02 ` Yunke Cao
2024-12-02 9:26 ` Ricardo Ribalda
2024-12-06 7:50 ` Yunke Cao
2024-12-09 14:22 ` Hans de Goede
2024-12-09 15:23 ` Ricardo Ribalda
2024-12-09 15:28 ` Hans de Goede
2024-11-14 19:10 ` [PATCH v15 19/19] media: uvcvideo: document " Ricardo Ribalda
2024-12-09 14:36 ` Hans de Goede
2024-12-09 15:22 ` Ricardo Ribalda
2024-12-09 15:31 ` Hans de Goede
2024-12-09 8:53 ` [PATCH v15 00/19] media: uvcvideo: Implement " Yunke Cao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox