From: Yunke Cao <yunkec@google.com>
To: Hans Verkuil <hverkuil-cisco@xs4all.nl>,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Daniel Scally <dan.scally@ideasonboard.com>
Cc: Tomasz Figa <tfiga@chromium.org>,
Sergey Senozhatsky <senozhatsky@chromium.org>,
Ricardo Ribalda <ribalda@chromium.org>,
linux-media@vger.kernel.org, Yunke Cao <yunkec@google.com>
Subject: [PATCH v14 09/11] media: uvcvideo: implement UVC v1.5 ROI
Date: Fri, 1 Dec 2023 16:19:00 +0900 [thread overview]
Message-ID: <20231201071907.3080126-10-yunkec@google.com> (raw)
In-Reply-To: <20231201071907.3080126-1-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>
---
Changelog since v11:
- No change.
Changelog since v10:
- Moved after the patches adding support for MIN/MAX.
- Clamp the set current value based on MIN/MAX.
- Thanks, Daniel!
Changelog since v9:
- No change.
Changelog since v8:
- No change.
Changelog since v7:
- Fix a few style issues.
- Only allow 4-byte aligned data.
- Add control names.
- Move initialization to 7/10.
drivers/media/usb/uvc/uvc_ctrl.c | 137 +++++++++++++++++++++++++++--
drivers/media/usb/uvc/uvc_v4l2.c | 5 +-
drivers/media/usb/uvc/uvcvideo.h | 12 ++-
include/uapi/linux/usb/video.h | 1 +
include/uapi/linux/uvcvideo.h | 13 +++
include/uapi/linux/v4l2-controls.h | 9 ++
6 files changed, 167 insertions(+), 10 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index c073c2a02102..d405b2a9d477 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[] = {
@@ -459,6 +477,70 @@ static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
data[first+1] = min_t(int, abs(value), 0xff);
}
+static int uvc_to_v4l2_rect(struct v4l2_rect *v4l2_rect,
+ const struct uvc_rect *uvc_rect)
+{
+ if (uvc_rect->bottom < uvc_rect->top ||
+ uvc_rect->right < uvc_rect->left)
+ return -EINVAL;
+
+ 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 v4l2_to_uvc_rect(struct uvc_rect *uvc_rect,
+ const struct v4l2_rect *min_rect,
+ const struct v4l2_rect *max_rect,
+ struct v4l2_rect *v4l2_rect)
+{
+ v4l2_rect->left = clamp_t(s32, v4l2_rect->left, 0, max_rect->width);
+ v4l2_rect->top = clamp_t(s32, v4l2_rect->top, 0, max_rect->height);
+ v4l2_rect->height = clamp_t(s32, v4l2_rect->height,
+ min_rect->height, max_rect->height);
+ v4l2_rect->width = clamp_t(s32, v4l2_rect->width,
+ min_rect->width, max_rect->width);
+
+ uvc_rect->top = v4l2_rect->top;
+ uvc_rect->left = v4l2_rect->left;
+ uvc_rect->bottom = v4l2_rect->height + v4l2_rect->top - 1;
+ uvc_rect->right = v4l2_rect->width + v4l2_rect->left - 1;
+ return 0;
+}
+
+static int uvc_get_compound_rect(struct uvc_control_mapping *mapping,
+ const u8 *data, u8 *data_out)
+{
+ struct uvc_rect *uvc_rect;
+
+ uvc_rect = (struct uvc_rect *)(data + mapping->offset / 8);
+ return uvc_to_v4l2_rect((struct v4l2_rect *)data_out, uvc_rect);
+}
+
+static int uvc_set_compound_rect(struct uvc_control_mapping *mapping,
+ const u8 *data_in, const u8 *data_min,
+ const u8 *data_max, u8 *data)
+{
+ struct uvc_rect *uvc_rect;
+ struct v4l2_rect min_rect, max_rect;
+ int ret;
+
+ uvc_rect = (struct uvc_rect *)(data + mapping->offset / 8);
+
+ ret = uvc_get_compound_rect(mapping, data_min, (u8 *)&min_rect);
+ if (ret)
+ return ret;
+
+ ret = uvc_get_compound_rect(mapping, data_max, (u8 *)&max_rect);
+ if (ret)
+ return ret;
+
+ return v4l2_to_uvc_rect(uvc_rect, &min_rect, &max_rect,
+ (struct v4l2_rect *)data_in);
+}
+
static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
{
.id = V4L2_CID_BRIGHTNESS,
@@ -748,6 +830,29 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
},
+ {
+ .id = V4L2_CID_UVC_REGION_OF_INTEREST_RECT,
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = UVC_CT_REGION_OF_INTEREST_CONTROL,
+ .v4l2_size = sizeof(struct v4l2_rect) * 8,
+ .data_size = sizeof(struct uvc_rect) * 8,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_RECT,
+ .data_type = UVC_CTRL_DATA_TYPE_RECT,
+ .get_compound = uvc_get_compound_rect,
+ .set_compound = uvc_set_compound_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,
+ .data_size = 16,
+ .offset = 64,
+ .v4l2_type = V4L2_CTRL_TYPE_BITMASK,
+ .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
+ .name = "Region Of Interest Auto Controls",
+ },
};
const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
@@ -900,12 +1005,12 @@ static int uvc_get_compound(struct uvc_control_mapping *mapping, const u8 *data,
* and mapping->data_size stored at 'data'.
*/
static int uvc_set_compound(struct uvc_control_mapping *mapping,
- const u8 *data_in, u8 *data)
+ const u8 *data_in, const u8 *data_min,
+ const u8 *data_max, u8 *data)
{
memcpy(data + mapping->offset / 8, data_in, mapping->data_size / 8);
return 0;
}
-
static bool
uvc_ctrl_mapping_is_compound(const struct uvc_control_mapping *mapping)
{
@@ -2100,6 +2205,8 @@ static int __uvc_ctrl_set_compound(struct uvc_control_mapping *mapping,
goto out;
ret = mapping->set_compound(mapping, data,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
__uvc_ctrl_get_compound(mapping, ctrl, UVC_CTRL_DATA_CURRENT, xctrl);
@@ -2224,6 +2331,13 @@ int uvc_ctrl_set(struct uvc_fh *handle,
}
if (uvc_ctrl_mapping_is_compound(mapping)) {
+ /* Populates min/max value cache for clamping. */
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ return ret;
+ }
+
ret = __uvc_ctrl_set_compound(mapping, xctrl, ctrl);
if (ret < 0)
return ret;
@@ -2641,12 +2755,21 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
}
if (uvc_ctrl_mapping_is_compound(map)) {
- if (map->data_size != map->v4l2_size)
- return -EINVAL;
+ switch (map->v4l2_type) {
+ case V4L2_CTRL_TYPE_RECT:
+ /* Only supports 4 bytes-aligned data. */
+ if (WARN_ON(map->offset % 32))
+ return -EINVAL;
+ break;
+ default:
+ if (WARN_ON(map->data_size != map->v4l2_size))
+ return -EINVAL;
+
+ /* Only supports byte-aligned data. */
+ if (WARN_ON(map->offset % 8 || map->data_size % 8))
+ return -EINVAL;
+ }
- /* Only supports byte-aligned data. */
- if (WARN_ON(map->offset % 8 || map->data_size % 8))
- return -EINVAL;
}
if (!map->get && !uvc_ctrl_mapping_is_compound(map))
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 352f62ef02f2..c0a7c0091099 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1053,7 +1053,10 @@ static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
qec->step = qc.step;
qec->default_value = qc.default_value;
qec->flags = qc.flags;
- qec->elem_size = 4;
+ if (qc.type == V4L2_CTRL_TYPE_RECT)
+ qec->elem_size = sizeof(struct v4l2_rect);
+ else
+ qec->elem_size = 4;
qec->elems = 1;
qec->nr_of_dims = 0;
memset(qec->dims, 0, sizeof(qec->dims));
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 6fda40919e7f..18da5e0b8cb2 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -133,8 +133,9 @@ struct uvc_control_mapping {
u8 *data_out);
void (*set)(struct uvc_control_mapping *mapping, s32 value,
u8 *data);
- int (*set_compound)(struct uvc_control_mapping *mapping, const u8 *data_in,
- u8 *data);
+ int (*set_compound)(struct uvc_control_mapping *mapping,
+ const u8 *data_in, const u8 *data_min,
+ const u8 *data_max, u8 *data);
};
struct uvc_control {
@@ -289,6 +290,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..9d1e6085feba 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_CAMERA_UVC_BASE + 1)
+#define V4L2_CID_UVC_REGION_OF_INTEREST_AUTO (V4L2_CID_CAMERA_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 68db66d4aae8..6c7e03d18d79 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1081,6 +1081,15 @@ enum v4l2_auto_focus_range {
#define V4L2_CID_HDR_SENSOR_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
+/* CAMERA-class private control IDs */
+
+/*
+ * 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_CAMERA_UVC_BASE (V4L2_CID_CAMERA_CLASS_BASE + 0x1000)
+
/* FM Modulator class control IDs */
#define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
--
2.43.0.rc2.451.g8631bc7472-goog
next prev parent reply other threads:[~2023-12-01 7:19 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-01 7:18 [PATCH v14 00/11] Implement UVC v1.5 ROI Yunke Cao
2023-12-01 7:18 ` [PATCH v14 01/11] media: v4l2_ctrl: Add V4L2_CTRL_TYPE_RECT Yunke Cao
2023-12-01 8:35 ` Hans Verkuil
2023-12-08 13:41 ` Laurent Pinchart
2023-12-12 1:33 ` Yunke Cao
2023-12-12 1:37 ` Laurent Pinchart
2023-12-01 7:18 ` [PATCH v14 02/11] media: uvcvideo: add uvc_ctrl_get_boundary for getting default value Yunke Cao
2023-12-08 15:13 ` Laurent Pinchart
2023-12-01 7:18 ` [PATCH v14 03/11] media: uvcvideo: introduce __uvc_ctrl_get_std() Yunke Cao
2023-12-08 15:12 ` Laurent Pinchart
2023-12-01 7:18 ` [PATCH v14 04/11] media: uvcvideo: Split uvc_control_mapping.size to v4l2 and data size Yunke Cao
2023-12-08 14:15 ` Laurent Pinchart
2023-12-12 7:59 ` Yunke Cao
2023-12-18 3:17 ` Laurent Pinchart
2023-12-01 7:18 ` [PATCH v14 05/11] media: uvcvideo: Add support for compound controls Yunke Cao
2023-12-06 5:45 ` Dan Carpenter
2023-12-08 15:07 ` Laurent Pinchart
2023-12-13 7:38 ` Yunke Cao
2023-12-18 3:27 ` Laurent Pinchart
2023-12-20 2:28 ` Yunke Cao
2023-12-01 7:18 ` [PATCH v14 06/11] v4l2-ctrls: add support for V4L2_CTRL_WHICH_MIN/MAX_VAL Yunke Cao
2023-12-01 8:32 ` Hans Verkuil
2023-12-05 22:30 ` kernel test robot
2023-12-06 4:34 ` kernel test robot
2023-12-06 5:59 ` kernel test robot
2023-12-08 15:20 ` Laurent Pinchart
2023-12-13 4:06 ` Yunke Cao
2023-12-14 17:34 ` kernel test robot
2023-12-01 7:18 ` [PATCH v14 07/11] media: vivid: Add an rectangle control Yunke Cao
2023-12-01 7:18 ` [PATCH v14 08/11] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL Yunke Cao
2023-12-08 15:26 ` Laurent Pinchart
2023-12-01 7:19 ` Yunke Cao [this message]
2023-12-08 15:43 ` [PATCH v14 09/11] media: uvcvideo: implement UVC v1.5 ROI Laurent Pinchart
2024-03-14 13:24 ` Gergo Koteles
2023-12-01 7:19 ` [PATCH v14 10/11] media: uvcvideo: initilaize ROI control to default value Yunke Cao
2023-12-08 15:50 ` Laurent Pinchart
2023-12-01 7:19 ` [PATCH v14 11/11] media: uvcvideo: document UVC v1.5 ROI Yunke Cao
2023-12-08 16:00 ` Laurent Pinchart
2023-12-12 4:45 ` Yunke Cao
2023-12-18 3:44 ` Laurent Pinchart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231201071907.3080126-10-yunkec@google.com \
--to=yunkec@google.com \
--cc=dan.scally@ideasonboard.com \
--cc=hverkuil-cisco@xs4all.nl \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=ribalda@chromium.org \
--cc=senozhatsky@chromium.org \
--cc=tfiga@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox