From patchwork Tue Jun 28 07:56:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunke Cao X-Patchwork-Id: 12897865 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DDCBECCA479 for ; Tue, 28 Jun 2022 07:57:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243017AbiF1H5n (ORCPT ); Tue, 28 Jun 2022 03:57:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52738 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244237AbiF1H5a (ORCPT ); Tue, 28 Jun 2022 03:57:30 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8954015FE3 for ; Tue, 28 Jun 2022 00:57:29 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-317ae1236feso96451617b3.11 for ; Tue, 28 Jun 2022 00:57:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=vidUQ6634eXhp1fGkyEdit5h9h06vPof5t7hW8Xapx8=; b=Y0Gox8tGRBHj/fFanZd0obWyk4RAlzy5YJuSEBqBkbmOYgTCnI0MaVea/rwohQikCv 4F79qATAsQHjKHe6R2S+2VM5IO9T0Q1+TFS4ADS9QsLY6QGtprxCyT0nvehCMl1jkN1z kiQjyhRgdfZBS39hvLBx2jkpHOhM8MEODoqCfVuKk+L7CEdFg/7U2fF62fr9c3oyg/yF A4TaSQSGes8dRcdJoqGZg69WqGo/NcgZP76CWgPVpPYHUwk4Bk9U0TBzDc0QQjVKxdL/ hpi7Wy2jlSJgT4qXLUj5QonbeyWb4H3y7kn+Ptb+XnTo1zgdMeYkOtSVDNcxczBFtzVW vz2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=vidUQ6634eXhp1fGkyEdit5h9h06vPof5t7hW8Xapx8=; b=2F/2YNiLwa8+cAUOleWUB+tR0lWEUaMQAT/B7b4VALrgweAHIaGrH1/EEKKSGSpN2U Wcma/RjjpGbGsFsdvKDGobiY2y+uV3Kghyvwsu5aoy2O1WW/FZeXo2HWKZbBpmxH4REZ i8mnfGuPIJRh4dj/d1URnDfPSAcjeLGRh/NdqJh5GBqWxL988sVl9R3aZyk47i9myKEx YO1pDJoYiy6aEvu3EwcleEBTp2d1AE61saAbTiS/RNPq01JqduMHuCSqY4uaAg5hKth/ 9js94FXyAtiP/XupcDy8bPwmRHcJcdsx6BxZ6zjoO3Hh7v/zjkOhEmQurxvMiXevswtn DyIg== X-Gm-Message-State: AJIora89bQEjvjB+ihI2xn9PMHBu3SkNMPv+lEMP8rx8JNAd30RoSprO 5MsV8rT1PdgP93OdZVu7TfOvVlp3n1E= X-Google-Smtp-Source: AGRyM1tLTzbM093e3x1DgbhA6nMfSR/9j5jZaQLPAgPI04rutjngIaemwASbUGi4cBscKabO1YxrwWDdbr4= X-Received: from yunkec1.tok.corp.google.com ([2401:fa00:8f:203:983d:14d6:e059:135f]) (user=yunkec job=sendgmr) by 2002:a5b:c43:0:b0:66c:a2a6:5a44 with SMTP id d3-20020a5b0c43000000b0066ca2a65a44mr12802791ybr.568.1656403048839; Tue, 28 Jun 2022 00:57:28 -0700 (PDT) Date: Tue, 28 Jun 2022 16:56:59 +0900 In-Reply-To: <20220628075705.2278044-1-yunkec@google.com> Message-Id: <20220628075705.2278044-2-yunkec@google.com> Mime-Version: 1.0 References: <20220628075705.2278044-1-yunkec@google.com> X-Mailer: git-send-email 2.37.0.rc0.161.g10f37bed90-goog Subject: [PATCH v7 1/7] media: v4l2_ctrl: Add V4L2_CTRL_TYPE_RECT From: Yunke Cao To: Hans Verkuil , Laurent Pinchart , Nicolas Dufresne , Mauro Carvalho Chehab Cc: Tomasz Figa , Sergey Senozhatsky , Ricardo Ribalda , linux-media@vger.kernel.org, Yunke Cao Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add p_rect to struct v4l2_ext_control with basic support in v4l2-ctrls. Reviewed-by: Ricardo Ribalda Signed-off-by: Yunke Cao Reviewed-by: Laurent Pinchart --- .../media/v4l/vidioc-g-ext-ctrls.rst | 4 ++++ .../media/videodev2.h.rst.exceptions | 1 + drivers/media/v4l2-core/v4l2-ctrls-core.c | 20 +++++++++++++++++++ include/media/v4l2-ctrls.h | 2 ++ include/uapi/linux/videodev2.h | 2 ++ 5 files changed, 29 insertions(+) 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 29971a45a2d4..7473baa4e977 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -189,6 +189,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/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 9cbb7a0c354a..7b423475281d 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -147,6 +147,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 949c1884d9c1..35d43ba650db 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -84,6 +84,11 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, return ptr1.p_u16[idx] == ptr2.p_u16[idx]; case V4L2_CTRL_TYPE_U32: return ptr1.p_u32[idx] == ptr2.p_u32[idx]; + case V4L2_CTRL_TYPE_RECT: + return ptr1.p_rect->top == ptr2.p_rect->top && + ptr1.p_rect->left == ptr2.p_rect->left && + ptr1.p_rect->height == ptr2.p_rect->height && + ptr1.p_rect->width == ptr2.p_rect->width; default: if (ctrl->is_int) return ptr1.p_s32[idx] == ptr2.p_s32[idx]; @@ -307,6 +312,11 @@ static void std_log(const struct v4l2_ctrl *ctrl) case V4L2_CTRL_TYPE_VP9_FRAME: pr_cont("VP9_FRAME"); 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; @@ -525,6 +535,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; @@ -888,6 +899,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; } @@ -1455,6 +1472,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 b3ce438f1329..919e104de50b 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -58,6 +58,7 @@ struct video_device; * @p_hdr10_cll: Pointer to an HDR10 Content Light Level structure. * @p_hdr10_mastering: Pointer to an HDR10 Mastering Display structure. * @p_area: Pointer to an area. + * @p_rect: Pointer to a rectangle. * @p: Pointer to a compound value. * @p_const: Pointer to a constant compound value. */ @@ -87,6 +88,7 @@ union v4l2_ctrl_ptr { struct v4l2_ctrl_hdr10_cll_info *p_hdr10_cll; struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering; struct v4l2_area *p_area; + 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 343b95107fce..2e36bb610ea6 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1754,6 +1754,7 @@ struct v4l2_ext_control { __u16 __user *p_u16; __u32 __user *p_u32; 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 *p_h264_pps; struct v4l2_ctrl_h264_scaling_matrix __user *p_h264_scaling_matrix; @@ -1813,6 +1814,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, From patchwork Tue Jun 28 07:57:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunke Cao X-Patchwork-Id: 12897866 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 957B7CCA47E for ; Tue, 28 Jun 2022 07:57:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243166AbiF1H5n (ORCPT ); Tue, 28 Jun 2022 03:57:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52814 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245258AbiF1H5e (ORCPT ); Tue, 28 Jun 2022 03:57:34 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F248615FCC for ; Tue, 28 Jun 2022 00:57:33 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id z188-20020a2565c5000000b0066c086258ddso9243435ybb.9 for ; Tue, 28 Jun 2022 00:57:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=OqDXLLw2gE6LQdAoQryltTRk36RdCADaFwUGEHVSOFw=; b=lvx8Eq2c2z7wJL13ExsGRrVD+J5W7bjUHw8XK27bKlM6dNf1HfnltTuJQ5vnnItG1F P1H2saKf+Ae/+2Njq9XarXNmSY1p0BJVJjh0ELTTzsmS+IFe4b+OefY6IRa+pZ6GNKYn oLUcQEyGuuov9X0Kg5ConWElpc0tQpzUtDKvCGhAiDED04As+QwZxEj/D1qsFDw18GbP YwyaXyYprxbqtTUjC3MQMrCyqjHt/6tiGgbeT6QKd10LriQb+bPy0IrxZJ43qN9Vqfn5 LcN492aJB+n91BkgdSr7oRwAuQXXreIP8mwNJOtllC+sq7yNsiFnteRMfUWxcMY01plw /Q5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=OqDXLLw2gE6LQdAoQryltTRk36RdCADaFwUGEHVSOFw=; b=xz78qV4m5b9NEjl5hC5J9jUfpQB79dUTEH22G9sugYpWXO+dt8jQChTB+xgVKL7ObI NOWCvOwipFHvN6K2MHAckCuFG1akOspbq6Ts75AuuOHcUU46nilzRVO2meuuUyAcxhZB +DkKq/Mb4xyoOtNBNY2b4Bj0yq5P6ueByq/Y5z4iO/Sw3CIcckc8RRf18X5TK3slT0Po 4GUZ/I+jUSyMZrUw2w9YLGnbvV4ACyd3IefmzGTFpTLyLfpLGc5BpCS+9XhzkqLSY6yo A7zZgddbfmGxhtFqmY4HFv5Pypvs/2ZDMVWY7hk1PY60h3Jl/jk0jjZDBO4+cK4sKeU7 Jg1w== X-Gm-Message-State: AJIora/Q3a2O3pQdO41g1n6itnyheCzcVPZPKe6Ed/WePPF2ExUUJL1p dQU0E9D3uB1oPoPY6RH7D6ai06WYBm4= X-Google-Smtp-Source: AGRyM1s6eRUV406pXEDDD57cJuAJRvis8QgsmqE6fK30UleksKv+k/BrCuMrWwRHTaI/ZIVhJTgfLHWKnfU= X-Received: from yunkec1.tok.corp.google.com ([2401:fa00:8f:203:983d:14d6:e059:135f]) (user=yunkec job=sendgmr) by 2002:a05:6902:1186:b0:64e:b02c:4f99 with SMTP id m6-20020a056902118600b0064eb02c4f99mr17855922ybu.165.1656403053324; Tue, 28 Jun 2022 00:57:33 -0700 (PDT) Date: Tue, 28 Jun 2022 16:57:00 +0900 In-Reply-To: <20220628075705.2278044-1-yunkec@google.com> Message-Id: <20220628075705.2278044-3-yunkec@google.com> Mime-Version: 1.0 References: <20220628075705.2278044-1-yunkec@google.com> X-Mailer: git-send-email 2.37.0.rc0.161.g10f37bed90-goog Subject: [PATCH v7 2/7] media: uvcvideo: add uvc_ctrl_get_fixed for getting default value From: Yunke Cao To: Hans Verkuil , Laurent Pinchart , Nicolas Dufresne , Mauro Carvalho Chehab Cc: Tomasz Figa , Sergey Senozhatsky , Ricardo Ribalda , linux-media@vger.kernel.org, Yunke Cao Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Introduce a new uvc_ctrl_get_fixed. It simply calls query_v4l2_ctrl() for now, but is easier to extend to support compound controls and V4L2_CTRL_WHICH_MIN/MAX_VAL in the following patches. Reviewed-by: Ricardo Ribalda Signed-off-by: Yunke Cao --- drivers/media/usb/uvc/uvc_ctrl.c | 13 +++++++++++++ drivers/media/usb/uvc/uvc_v4l2.c | 6 +----- drivers/media/usb/uvc/uvcvideo.h | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 0e78233fc8a0..772d9d28a520 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1697,6 +1697,19 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); } +int uvc_ctrl_get_fixed(struct uvc_video_chain *chain, + struct v4l2_ext_control *xctrl) +{ + struct v4l2_queryctrl qc = { .id = xctrl->id }; + int ret = uvc_query_v4l2_ctrl(chain, &qc); + + if (ret < 0) + return ret; + + xctrl->value = qc.default_value; + return 0; +} + int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl) { diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 648dcd579e81..0366d05895a9 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -1042,15 +1042,11 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, 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); + ret = uvc_ctrl_get_fixed(chain, ctrl); if (ret < 0) { ctrls->error_idx = i; return ret; } - - ctrl->value = qc.default_value; } return 0; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index c5b4febd2d94..ba028ba7c34e 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -901,6 +901,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle) } int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); +int uvc_ctrl_get_fixed(struct uvc_video_chain *chain, + struct v4l2_ext_control *xctrl); int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl); int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, bool read); From patchwork Tue Jun 28 07:57:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunke Cao X-Patchwork-Id: 12897867 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1BF19CCA479 for ; Tue, 28 Jun 2022 07:57:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243494AbiF1H5o (ORCPT ); Tue, 28 Jun 2022 03:57:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52908 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343882AbiF1H5k (ORCPT ); Tue, 28 Jun 2022 03:57:40 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0B58E13FA7 for ; Tue, 28 Jun 2022 00:57:39 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id g34-20020a635662000000b0040d1da6ada4so6309583pgm.1 for ; Tue, 28 Jun 2022 00:57:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=nDIjOO1xzDSFkJrFVqULQeNIM6YoCDnuWCLYEys0a9A=; b=Cnj4hGwjSJCIGj0QhB/tLYOGT5tKyaCf4YfQTlE9oL7u/MTVIhdu22oa0y0/ZzXMAX NbqoNYTog2GmUan+NSKPHySQUMklAJbtYxR0f0uceCbJDQxDh04QTCP/5gHAZhGVAjQb /rXIN0sqT6JX3AjyJobB/eb/mVReAMzmyuZyV6L0QcX+UlNFwsDrkSobRRjJwfFZEM2C /gKblFyAS85g+pr0GHkesc9TxS71LSImYG1vNMSDdjf9C4/DAPJNqrbkPhUKhdEgBtNm UnVi3ShnCRhHQs7Eq+oTOnkXX9zO6DKKRzqRwRxiVMyEuI1OcUa1sNVNSDgIDunYwu3j 2wrw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=nDIjOO1xzDSFkJrFVqULQeNIM6YoCDnuWCLYEys0a9A=; b=qi7onUn6bupZODKN5zIJgSPmE4JQ8whublx4cfPBvAx94+EiO2Bi/mkKg3ZJ4qy5Sv pVMqdnqKknTU98l3Plw/fGU0DpDMgeFkaviFDTRJ4n0YS+Tn1vYyYUrXYOnzwE4RwNq7 qBtnIgbz6zGrmAvteuW3qElaBZfjgvVVR5NQG1J9Lbyi8IqUkL7WdMwVL6BQ+YuqUYSR qNPCTfjWt5MGc2457ULccetdPz2LEMIiHwaFvCBbG4PebxvmWKaTNPhdaMPNx9ArRlw8 xSP3ZvWBZJ6OQKKUKYyA9OWjJCXfgDdumwHe5l/KCOrXSUpt3lG/dkPaLwgrD8yW4gH+ 1MpA== X-Gm-Message-State: AJIora8dDe6a8GioSUAwse9MLw7121frS9f4tZU4qGKDCXt6afckQx+w O6YOzNKhDLFQET1KIgmaatMN5ptXwSM= X-Google-Smtp-Source: AGRyM1tkkWEAvE5UIZEyYncX4CMycuzxlZrLRdmhrajFGUb/H92RSM1aWNNA4FrM8deU8cAUqtNDSqill3U= X-Received: from yunkec1.tok.corp.google.com ([2401:fa00:8f:203:983d:14d6:e059:135f]) (user=yunkec job=sendgmr) by 2002:a17:903:32c4:b0:16a:4227:cd68 with SMTP id i4-20020a17090332c400b0016a4227cd68mr3649688plr.173.1656403058576; Tue, 28 Jun 2022 00:57:38 -0700 (PDT) Date: Tue, 28 Jun 2022 16:57:01 +0900 In-Reply-To: <20220628075705.2278044-1-yunkec@google.com> Message-Id: <20220628075705.2278044-4-yunkec@google.com> Mime-Version: 1.0 References: <20220628075705.2278044-1-yunkec@google.com> X-Mailer: git-send-email 2.37.0.rc0.161.g10f37bed90-goog Subject: [PATCH v7 3/7] media: uvcvideo: Add support for compound controls From: Yunke Cao To: Hans Verkuil , Laurent Pinchart , Nicolas Dufresne , Mauro Carvalho Chehab Cc: Tomasz Figa , Sergey Senozhatsky , Ricardo Ribalda , linux-media@vger.kernel.org, Yunke Cao Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Supports getting/setting current value. Supports getting default value. Handles V4L2_CTRL_FLAG_NEXT_COMPOUND. Signed-off-by: Yunke Cao Reviewed-by: Ricardo Ribalda --- drivers/media/usb/uvc/uvc_ctrl.c | 279 ++++++++++++++++++++++++++----- drivers/media/usb/uvc/uvcvideo.h | 4 + 2 files changed, 238 insertions(+), 45 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 772d9d28a520..508ee04afbcd 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -815,6 +815,34 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, } } +/* Extract the byte array specified by mapping->offset and mapping->size + * stored at 'data' to the output array 'data_out'. + */ +static int uvc_get_array(struct uvc_control_mapping *mapping, const u8 *data, + u8 *data_out) +{ + // Only supports byte-aligned data. + if (WARN_ON(mapping->offset % 8 || mapping->size % 8)) + return -EINVAL; + + memcpy(data_out, data + mapping->offset / 8, mapping->size / 8); + return 0; +} + +/* Copy the byte array 'data_in' to the destination specified by mapping->offset + * and mapping->size stored at 'data'. + */ +static int uvc_set_array(struct uvc_control_mapping *mapping, const u8 *data_in, + u8 *data) +{ + // Only supports byte-aligned data. + if (WARN_ON(mapping->offset % 8 || mapping->size % 8)) + return -EINVAL; + + memcpy(data + mapping->offset / 8, data_in, mapping->size / 8); + return 0; +} + /* ------------------------------------------------------------------------ * Terminal and unit management */ @@ -831,7 +859,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; @@ -846,14 +874,18 @@ 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) && + ((map->v4l2_type < V4L2_CTRL_COMPOUND_TYPES && + next) || + (map->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES && + next_compound))) { *control = ctrl; *mapping = map; } @@ -867,6 +899,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; @@ -875,12 +908,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); @@ -943,6 +977,39 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, return 0; } +static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain, + struct uvc_control *ctrl) +{ + int ret = 0; + + if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) + return -EACCES; + + if (ctrl->loaded) + return 0; + + if (ctrl->entity->get_cur) { + ret = ctrl->entity->get_cur(chain->dev, + ctrl->entity, + ctrl->info.selector, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), + ctrl->info.size); + } else { + ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, + ctrl->entity->id, chain->dev->intfnum, + ctrl->info.selector, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), + ctrl->info.size); + } + + if (ret < 0) + return ret; + + ctrl->loaded = 1; + + return ret; +} + static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, const u8 *data) { @@ -963,35 +1030,19 @@ static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, return value; } -static int __uvc_ctrl_get(struct uvc_video_chain *chain, - struct uvc_control *ctrl, struct uvc_control_mapping *mapping, - s32 *value) +static int __uvc_ctrl_get_std(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + s32 *value) { int ret; - if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) - return -EACCES; - - if (!ctrl->loaded) { - if (ctrl->entity->get_cur) { - ret = ctrl->entity->get_cur(chain->dev, - ctrl->entity, - ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - } else { - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, - ctrl->entity->id, - chain->dev->intfnum, - ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - } - if (ret < 0) - return ret; + if (mapping->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES) + return -EINVAL; - ctrl->loaded = 1; - } + ret = __uvc_ctrl_load_cur(chain, ctrl); + if (ret < 0) + return ret; *value = __uvc_ctrl_get_value(mapping, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); @@ -999,6 +1050,57 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, return 0; } +static int __uvc_ctrl_get_compound_to_user(struct uvc_control_mapping *mapping, + struct uvc_control *ctrl, + int id, + struct v4l2_ext_control *xctrl) +{ + int ret, size; + u8 *data; + + if (WARN_ON(!mapping->size % 8)) + return -EINVAL; + + size = mapping->size / 8; + if (xctrl->size < size) { + xctrl->size = size; + return -ENOSPC; + } + + data = kmalloc(size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = mapping->get_array(mapping, uvc_ctrl_data(ctrl, id), data); + if (ret < 0) + goto out; + + ret = copy_to_user(xctrl->ptr, data, size) ? -EFAULT : 0; + +out: + kfree(data); + return ret; +} + +static int __uvc_ctrl_get_compound(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + struct v4l2_ext_control *xctrl) +{ + int ret; + + if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES) + return -EINVAL; + + ret = __uvc_ctrl_load_cur(chain, ctrl); + if (ret < 0) + return ret; + + return __uvc_ctrl_get_compound_to_user(mapping, ctrl, + UVC_CTRL_DATA_CURRENT, + xctrl); +} + static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, u32 found_id) { @@ -1102,10 +1204,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; + s32 val = 0; + + if (master_map->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES) + return -EINVAL; + + ret = __uvc_ctrl_get_std(chain, master_ctrl, master_map, &val); if (ret < 0) return ret; @@ -1113,6 +1220,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) @@ -1346,11 +1462,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 (mapping->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES || + __uvc_ctrl_get_std(chain, ctrl, mapping, &val) == 0) changes |= V4L2_EVENT_CTRL_CH_VALUE; uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); @@ -1517,7 +1634,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 (mapping->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES || + __uvc_ctrl_get_std(handle->chain, ctrl, mapping, &val) == 0) changes |= V4L2_EVENT_CTRL_CH_VALUE; uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, @@ -1647,7 +1765,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; } @@ -1694,11 +1812,14 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, if (ctrl == NULL) return -EINVAL; - return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); + if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES) + return __uvc_ctrl_get_std(chain, ctrl, mapping, &xctrl->value); + else + return __uvc_ctrl_get_compound(chain, ctrl, mapping, xctrl); } -int uvc_ctrl_get_fixed(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl) +int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain, + struct v4l2_ext_control *xctrl) { struct v4l2_queryctrl qc = { .id = xctrl->id }; int ret = uvc_query_v4l2_ctrl(chain, &qc); @@ -1710,6 +1831,56 @@ int uvc_ctrl_get_fixed(struct uvc_video_chain *chain, return 0; } +int uvc_ctrl_get_fixed(struct uvc_video_chain *chain, + struct v4l2_ext_control *xctrl) +{ + struct uvc_control *ctrl; + struct uvc_control_mapping *mapping; + 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 (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES) + return __uvc_ctrl_get_fixed_std(chain, xctrl); + + if (!ctrl->cached) { + ret = uvc_ctrl_populate_cache(chain, ctrl); + if (ret < 0) + return ret; + } + + return __uvc_ctrl_get_compound_to_user(mapping, ctrl, UVC_CTRL_DATA_DEF, + xctrl); +} + +int __uvc_ctrl_set_compound(struct uvc_control_mapping *mapping, + struct v4l2_ext_control *xctrl, + struct uvc_control *ctrl) +{ + int ret; + u8 *data; + + data = kmalloc(xctrl->size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = copy_from_user(data, xctrl->ptr, xctrl->size); + if (ret < 0) + goto out; + + ret = mapping->set_array(mapping, data, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + +out: + kfree(data); + return ret; +} + int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl) { @@ -1820,8 +1991,14 @@ int uvc_ctrl_set(struct uvc_fh *handle, ctrl->info.size); } - mapping->set(mapping, value, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES) { + mapping->set(mapping, value, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + } else { + ret = __uvc_ctrl_set_compound(mapping, xctrl, ctrl); + if (ret < 0) + return ret; + } if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) ctrl->handle = handle; @@ -2220,10 +2397,14 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, return -ENOMEM; } - if (map->get == NULL) + if (!map->get && map->v4l2_type < V4L2_CTRL_COMPOUND_TYPES) map->get = uvc_get_le_value; - if (map->set == NULL) + if (!map->set && map->v4l2_type < V4L2_CTRL_COMPOUND_TYPES) map->set = uvc_set_le_value; + if (!map->get_array && map->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES) + map->get_array = uvc_get_array; + if (!map->set_array && map->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES) + map->set_array = uvc_set_array; for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) { if (V4L2_CTRL_ID2WHICH(uvc_control_classes[i]) == @@ -2233,6 +2414,14 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, } } + if (map->v4l2_type < V4L2_CTRL_COMPOUND_TYPES && + WARN_ON(!map->get || !map->set)) + return -EINVAL; + + if (map->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES && + WARN_ON(!map->get_array || !map->set_array)) + return -EINVAL; + list_add_tail(&map->list, &ctrl->info.mappings); uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n", uvc_map_get_name(map), ctrl->info.entity, diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index ba028ba7c34e..2f9b75faae83 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -262,8 +262,12 @@ struct uvc_control_mapping { s32 (*get)(struct uvc_control_mapping *mapping, u8 query, const u8 *data); + int (*get_array)(struct uvc_control_mapping *mapping, const u8 *data, + u8 *data_out); void (*set)(struct uvc_control_mapping *mapping, s32 value, u8 *data); + int (*set_array)(struct uvc_control_mapping *mapping, const u8 *data_in, + u8 *data); }; struct uvc_control { From patchwork Tue Jun 28 07:57:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yunke Cao X-Patchwork-Id: 12897868 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 89CB6C433EF for ; Tue, 28 Jun 2022 07:58:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243087AbiF1H6E (ORCPT ); Tue, 28 Jun 2022 03:58:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52970 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243551AbiF1H5p (ORCPT ); Tue, 28 Jun 2022 03:57:45 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3394313FA7 for ; Tue, 28 Jun 2022 00:57:44 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-31ba792c793so46924127b3.20 for ; Tue, 28 Jun 2022 00:57:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=aIbHKbVVcaZVM4752YjpEFdZQCRYFrEKvf1iqr1v6tU=; b=oydepxdL9EIhOyT5K3L5QeA343Lx3DF8Irejv8eqsq3/bc8so60fhsTQgZbd6nLC1s XuniwmgfE1TU28yCEj2OieNEwPcRv91aSSThdyLieCBieedd3atoqFYd+u4P8mwoq/LK qrS0lsVZlsNm/n0Q9lbjz24CzVIN2KBeTzzU86/gO/aHYv0JAFQcv6RTD5QE0iifZV+1 mFk0c+J5xxV3yAAW48fBHgu+LUwIJTQDN4cF4U1iU2NBnH474yZHctw2xPk8VOhSp1dQ 4hQnZueRqekvFesibX1K2qCuxdquuAuHOHC59b6KbvIoJTrAbHGbe8KE8hsCCXLa7FPb ljXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=aIbHKbVVcaZVM4752YjpEFdZQCRYFrEKvf1iqr1v6tU=; b=J484YFp9EcqF51EHzbxCieBtIIGQHB9MtdDIHQS+80aADkAzBtOb47Tdb0FY8IiEUJ bCGoo1jaA58oIfzrvspjxdT1OFgx+YW4Hlc1mTlqpPbSkFNQMVBUlyGtKBmXpPv4FeSD bPCAShHzWlfXS3IiRlMuASVwgEH50GieJYPI7XhQfi0Kw1gVc4j/2s0Fd4qplwqDRp3D WzeMUYDhPoAI2IEgSgcI5anrG9CxxpqoDjmFJWjVrRMEN5eaXtypfy4P7u/83yKjn0y/ U8xPJpbp0bM6O3JYJsZor8pJQWNbwMNi5LRzWZ/fuNvMvXQGnUnauqa7+Wd8r1op79f+ lTPA== X-Gm-Message-State: AJIora8uPrwDHLskCnRA/Tc8LVw1eDbNcH3EdD3XUr0mAig++b8ifHxN 2s7vE4eWuWpSAQS2W3bn7wJvx0P0OMo= X-Google-Smtp-Source: AGRyM1tIowpdcqdpLuYbwAevXdRvy74xHNPctloEva3gHz6Xql2Qf7Cl9gYrDFed21UMy7D8XSxIMF1l4bI= X-Received: from yunkec1.tok.corp.google.com ([2401:fa00:8f:203:983d:14d6:e059:135f]) (user=yunkec job=sendgmr) by 2002:a81:990f:0:b0:2f8:c347:d11a with SMTP id q15-20020a81990f000000b002f8c347d11amr20012421ywg.507.1656403063541; Tue, 28 Jun 2022 00:57:43 -0700 (PDT) Date: Tue, 28 Jun 2022 16:57:02 +0900 In-Reply-To: <20220628075705.2278044-1-yunkec@google.com> Message-Id: <20220628075705.2278044-5-yunkec@google.com> Mime-Version: 1.0 References: <20220628075705.2278044-1-yunkec@google.com> X-Mailer: git-send-email 2.37.0.rc0.161.g10f37bed90-goog Subject: [PATCH v7 4/7] media: uvcvideo: implement UVC v1.5 ROI From: Yunke Cao To: Hans Verkuil , Laurent Pinchart , Nicolas Dufresne , Mauro Carvalho Chehab Cc: Tomasz Figa , Sergey Senozhatsky , Ricardo Ribalda , linux-media@vger.kernel.org, Yunke Cao Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org 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. Signed-off-by: Yunke Cao Reviewed-by: Ricardo Ribalda --- drivers/media/usb/uvc/uvc_ctrl.c | 146 ++++++++++++++++++++++++++++- drivers/media/usb/uvc/uvc_v4l2.c | 5 +- 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 | 8 ++ 6 files changed, 178 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 508ee04afbcd..00482269233a 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -355,6 +355,23 @@ 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[] = { @@ -429,6 +446,64 @@ static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, data[first+1] = min_t(int, abs(value), 0xff); } +static void uvc_to_v4l2_rect(struct v4l2_rect *v4l2_rect, + const struct uvc_rect *uvc_rect) +{ + 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; +} + +static int v4l2_to_uvc_rect(struct uvc_rect *uvc_rect, + const struct v4l2_rect *v4l2_rect) +{ + // Safely converts s32 and u32 to u16. + if (v4l2_rect->top > U16_MAX || v4l2_rect->top < 0 || + v4l2_rect->left > U16_MAX || v4l2_rect->left < 0 || + v4l2_rect->height > U16_MAX || v4l2_rect->height == 0 || + v4l2_rect->width > U16_MAX || v4l2_rect->width == 0 || + v4l2_rect->height + v4l2_rect->top - 1 > U16_MAX || + v4l2_rect->width + v4l2_rect->left - 1 > U16_MAX) + return -ERANGE; + + 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_array_rect(struct uvc_control_mapping *mapping, + const u8 *data, u8 *data_out) +{ + struct uvc_rect *uvc_rect; + + if (WARN_ON(mapping->offset % 8 || mapping->size % 8)) + return -EINVAL; + if (WARN_ON(mapping->size / 8 != sizeof(struct uvc_rect))) + return -EINVAL; + + uvc_rect = (struct uvc_rect *)(data + mapping->offset / 8); + uvc_to_v4l2_rect((struct v4l2_rect *)data_out, uvc_rect); + + return 0; +} + +static int uvc_set_array_rect(struct uvc_control_mapping *mapping, + const u8 *data_in, u8 *data) +{ + struct uvc_rect *uvc_rect; + + if (WARN_ON(mapping->offset % 8 || mapping->size % 8)) + return -EINVAL; + if (WARN_ON(mapping->size / 8 != sizeof(struct uvc_rect))) + return -EINVAL; + + uvc_rect = (struct uvc_rect *)(data + mapping->offset / 8); + return v4l2_to_uvc_rect(uvc_rect, (struct v4l2_rect *)data_in); +} + static const struct uvc_control_mapping uvc_ctrl_mappings[] = { { .id = V4L2_CID_BRIGHTNESS, @@ -728,6 +803,26 @@ 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, + .size = 64, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_RECT, + .data_type = UVC_CTRL_DATA_TYPE_RECT, + .get_array = uvc_get_array_rect, + .set_array = uvc_set_array_rect, + }, + { + .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, + }, }; /* ------------------------------------------------------------------------ @@ -1061,7 +1156,16 @@ static int __uvc_ctrl_get_compound_to_user(struct uvc_control_mapping *mapping, if (WARN_ON(!mapping->size % 8)) return -EINVAL; - size = mapping->size / 8; + switch (mapping->v4l2_type) { + case V4L2_CTRL_TYPE_RECT: + size = sizeof(struct v4l2_rect); + break; + + default: + size = mapping->size / 8; + break; + } + if (xctrl->size < size) { xctrl->size = size; return -ENOSPC; @@ -2578,6 +2682,40 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev, } } +static int uvc_ctrl_init_roi(struct uvc_device *dev, struct uvc_control *ctrl) +{ + int ret; + + ret = uvc_query_ctrl(dev, UVC_GET_DEF, ctrl->entity->id, dev->intfnum, + UVC_CT_REGION_OF_INTEREST_CONTROL, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF), + ctrl->info.size); + if (ret) + goto out; + + /* + * Most firmwares have wrong GET_CURRENT configuration. E.g. it's + * below GET_MIN, or have rectangle coordinates mixed up. This + * causes problems sometimes, because we are unable to set + * auto-controls value without first setting ROI rectangle to + * valid configuration. + * + * We expect that default configuration is always correct and + * is within the GET_MIN / GET_MAX boundaries. + * + * Set current ROI configuration to GET_DEF, so that we will + * always have properly configured ROI. + */ + ret = uvc_query_ctrl(dev, UVC_SET_CUR, 1, dev->intfnum, + UVC_CT_REGION_OF_INTEREST_CONTROL, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF), + ctrl->info.size); +out: + if (ret) + dev_err(&dev->udev->dev, "Failed to fixup ROI (%d).\n", ret); + return ret; +} + /* * Add control information and hardcoded stock control mappings to the given * device. @@ -2590,6 +2728,7 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, const struct uvc_control_mapping *mapping = uvc_ctrl_mappings; const struct uvc_control_mapping *mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings); + const u8 camera_entity[16] = UVC_GUID_UVC_CAMERA; /* XU controls initialization requires querying the device for control * information. As some buggy UVC devices will crash when queried @@ -2610,6 +2749,11 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, * GET_INFO on standard controls. */ uvc_ctrl_get_flags(chain->dev, ctrl, &ctrl->info); + + if (ctrl->info.selector == + UVC_CT_REGION_OF_INTEREST_CONTROL && + uvc_entity_match_guid(ctrl->entity, camera_entity)) + uvc_ctrl_init_roi(chain->dev, ctrl); break; } } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 0366d05895a9..aad61af36271 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -998,7 +998,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 2f9b75faae83..9ff95bbad251 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -431,6 +431,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 bfdae12cdacf..9076a444758a 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 8288137387c0..e2feee15cb1b 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) @@ -36,6 +37,18 @@ UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES | \ UVC_CTRL_FLAG_GET_DEF) +/* V4L2 private 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[32]; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index dfff69ed88f7..d85be46e46f2 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1013,6 +1013,14 @@ enum v4l2_auto_focus_range { #define V4L2_CID_CAMERA_SENSOR_ROTATION (V4L2_CID_CAMERA_CLASS_BASE+35) +/* CAMERA-class private control IDs */ + +/* + * The base for the uvc driver controls. See linux/uvcvideo.h for the list + * of controls. We reserve 16 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) From patchwork Tue Jun 28 07:57:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunke Cao X-Patchwork-Id: 12897871 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8FF23C43334 for ; Tue, 28 Jun 2022 07:58:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243298AbiF1H6b (ORCPT ); Tue, 28 Jun 2022 03:58:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53676 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243365AbiF1H6Q (ORCPT ); Tue, 28 Jun 2022 03:58:16 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8CC5F20BD9 for ; Tue, 28 Jun 2022 00:57:49 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id w2-20020a626202000000b00527c208de00so694138pfb.1 for ; Tue, 28 Jun 2022 00:57:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=VvL5gVoIL3eoBNrL2FJqLysW4R1e+12Zx3kRpKutZRA=; b=BP1T+hgTHigxfHzvN5OU80imwgOjGvyH+KUyzXkdWVuBV5NZfMBQctMwiiNue4PzDF GA1eOzPg+5I1yYF6U4fycPrJia0D6ooF6WheQoRsuEeeK2IntphFLC9Zf0tRAUWrNsPB DWpl6K6RO1dMBydYZs/oQMUPW/LrPGD0XzkHlaXbCGAqBEgLzU+y9Yx1xxZKRZMy/Cv7 tEv9Ol9kSmver4Ln+/Y+jga1JAtT077jbJ5Lih5koWDQC1MjXho7Zcd9C/oWyyS3952o ZfAPeJtQ67bybhzUoQvQfWcz4w3BBagoBQFgAqO7Az1BwurJErtwn2kh5b639v+R6RRK lcKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=VvL5gVoIL3eoBNrL2FJqLysW4R1e+12Zx3kRpKutZRA=; b=6+pibdEfcRDTc9a3gtVdqpXYcmfnvohAW6oRCl0J+vt3oWZK+Pa5JjCfTGqFs1IPzY lcMkkSzC7qZUZ+ONKEP4AckHP5SevWzwlc7cihOneJ2z4ubeDd68SPQjAPVUCIKmsF2E 30LW+vvD1Zv9GIFpqpxdwIX8p09FAu3/NC/aa1TAgqRC8jk5Bqhw5xd5ly69r9PnFG8r n4u22MHbQ/f2TZamN/+i8QmM9aTdL1/yz9iay7st0gu3d+1lzxqr5ob3IooQPrrxOiHa h4lsDC5PAzPO+c02oJ9zPauwc0Lm7kx5uNuNgOTyQvo8FAdbceMgxU4+Z1wszet5JyIi 2BvA== X-Gm-Message-State: AJIora930qBsY+UGf81PU4rENCcwxCdaWCccJ5gBv0u3/xfmlqEoQnOU 4i+cO6SE7nznGgq2tqmoITLHClBDQ/o= X-Google-Smtp-Source: AGRyM1u2H88Z/C6p9tMntILFedMKyFYZSlIDSgSE100IXXFcElCBubMdV4le6UZC0f2v3m2frP5LdWaAcxw= X-Received: from yunkec1.tok.corp.google.com ([2401:fa00:8f:203:983d:14d6:e059:135f]) (user=yunkec job=sendgmr) by 2002:a17:90b:3147:b0:1ee:d3a3:f24f with SMTP id ip7-20020a17090b314700b001eed3a3f24fmr162093pjb.1.1656403068583; Tue, 28 Jun 2022 00:57:48 -0700 (PDT) Date: Tue, 28 Jun 2022 16:57:03 +0900 In-Reply-To: <20220628075705.2278044-1-yunkec@google.com> Message-Id: <20220628075705.2278044-6-yunkec@google.com> Mime-Version: 1.0 References: <20220628075705.2278044-1-yunkec@google.com> X-Mailer: git-send-email 2.37.0.rc0.161.g10f37bed90-goog Subject: [PATCH v7 5/7] v4l2-ctrls: add support for V4L2_CTRL_WHICH_MIN/MAX_VAL From: Yunke Cao To: Hans Verkuil , Laurent Pinchart , Nicolas Dufresne , Mauro Carvalho Chehab Cc: Tomasz Figa , Sergey Senozhatsky , Ricardo Ribalda , linux-media@vger.kernel.org, Yunke Cao Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Hans Verkuil Add the capability of retrieving the min and max values of a compound control. Signed-off-by: Hans Verkuil Signed-off-by: Yunke Cao --- git am from https://lore.kernel.org/all/20191119113457.57833-3-hverkuil-cisco@xs4all.nl/ -Fixed some merge conflits. -Fixed the build error in drivers/media/platform/qcom/venus. .../media/v4l/vidioc-g-ext-ctrls.rst | 7 +- .../media/videodev2.h.rst.exceptions | 2 + drivers/media/i2c/imx214.c | 5 +- .../media/platform/qcom/venus/venc_ctrls.c | 4 + drivers/media/v4l2-core/v4l2-ctrls-api.c | 51 +++++-- drivers/media/v4l2-core/v4l2-ctrls-core.c | 135 ++++++++++++++++-- drivers/media/v4l2-core/v4l2-ioctl.c | 4 +- include/media/v4l2-ctrls.h | 32 ++++- include/uapi/linux/videodev2.h | 2 + 9 files changed, 214 insertions(+), 28 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 7473baa4e977..65a5f878cc28 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -284,14 +284,17 @@ 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, ``V4L2_CTRL_WHICH_MIN_VAL`` will return the minimum + value of the control, ``V4L2_CTRL_WHICH_MAX_VAL`` will return the maximum 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 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. 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/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 7b423475281d..e2dde31d76df 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -553,6 +553,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 83c1737abeec..aa0bfd18f7b7 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -1037,7 +1037,10 @@ static int imx214_probe(struct i2c_client *client) imx214->unit_size = v4l2_ctrl_new_std_compound(&imx214->ctrls, 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)); + ret = imx214->ctrls.error; if (ret) { dev_err(&client->dev, "%s control init failed (%d)\n", diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index ed44e5800759..4af8f9ca12a6 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -579,10 +579,14 @@ 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(NULL), + 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(NULL), + v4l2_ctrl_ptr_create(NULL), v4l2_ctrl_ptr_create(NULL)); v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index db9baa0bd05f..8a9c816b0dab 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -97,6 +97,28 @@ 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) +{ + int idx; + + for (idx = 0; idx < ctrl->elems; idx++) + ctrl->type_ops->minimum(ctrl, idx, 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) +{ + int idx; + + for (idx = 0; idx < ctrl->elems; idx++) + ctrl->type_ops->maximum(ctrl, idx, ctrl->p_new); + + return ptr_to_user(c, ctrl, ctrl->p_new); +} + /* Helper function: copy the caller-provider value to the given control value */ static int user_to_ptr(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl, @@ -220,8 +242,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", @@ -335,8 +357,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; } @@ -356,10 +378,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); @@ -399,13 +423,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++) @@ -432,6 +457,10 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, ret = def_to_user(cs->controls + idx, ref->ctrl); else if (is_request && ref->valid_p_req) 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 @@ -523,9 +552,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 35d43ba650db..8c5828c7c6d3 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -186,6 +186,28 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 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 std_init(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { @@ -224,6 +246,82 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, } } +static void std_minimum(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + switch (ctrl->type) { + case V4L2_CTRL_TYPE_STRING: + idx *= ctrl->elem_size; + memset(ptr.p_char + idx, ' ', ctrl->minimum); + ptr.p_char[idx + ctrl->minimum] = '\0'; + break; + case V4L2_CTRL_TYPE_INTEGER64: + ptr.p_s64[idx] = ctrl->minimum; + break; + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_INTEGER_MENU: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BITMASK: + case V4L2_CTRL_TYPE_BOOLEAN: + ptr.p_s32[idx] = ctrl->minimum; + break; + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_CTRL_CLASS: + ptr.p_s32[idx] = 0; + break; + case V4L2_CTRL_TYPE_U8: + ptr.p_u8[idx] = ctrl->minimum; + break; + case V4L2_CTRL_TYPE_U16: + ptr.p_u16[idx] = ctrl->minimum; + break; + case V4L2_CTRL_TYPE_U32: + ptr.p_u32[idx] = ctrl->minimum; + break; + default: + std_min_compound(ctrl, idx, ptr); + break; + } +} + +static void std_maximum(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + switch (ctrl->type) { + case V4L2_CTRL_TYPE_STRING: + idx *= ctrl->elem_size; + memset(ptr.p_char + idx, ' ', ctrl->maximum); + ptr.p_char[idx + ctrl->maximum] = '\0'; + break; + case V4L2_CTRL_TYPE_INTEGER64: + ptr.p_s64[idx] = ctrl->maximum; + break; + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_INTEGER_MENU: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BITMASK: + case V4L2_CTRL_TYPE_BOOLEAN: + ptr.p_s32[idx] = ctrl->maximum; + break; + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_CTRL_CLASS: + ptr.p_s32[idx] = 0; + break; + case V4L2_CTRL_TYPE_U8: + ptr.p_u8[idx] = ctrl->maximum; + break; + case V4L2_CTRL_TYPE_U16: + ptr.p_u16[idx] = ctrl->maximum; + break; + case V4L2_CTRL_TYPE_U32: + ptr.p_u32[idx] = ctrl->maximum; + break; + default: + std_max_compound(ctrl, idx, ptr); + break; + } +} + static void std_log(const struct v4l2_ctrl *ctrl) { union v4l2_ctrl_ptr ptr = ctrl->p_cur; @@ -986,6 +1084,8 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, static const struct v4l2_ctrl_type_ops std_type_ops = { .equal = std_equal, .init = std_init, + .minimum = std_minimum, + .maximum = std_maximum, .log = std_log, .validate = std_validate, }; @@ -1368,7 +1468,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; @@ -1515,7 +1618,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, sz_extra += 2 * tot_ctrl_size; if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) - sz_extra += elem_size; + sz_extra += elem_size * 3; ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL); if (ctrl == NULL) { @@ -1565,6 +1668,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size; memcpy(ctrl->p_def.p, p_def.p_const, elem_size); } + if (type >= V4L2_CTRL_COMPOUND_TYPES && + p_min.p_const && p_max.p_const) { + ctrl->p_min.p = ctrl->p_cur.p + 2 * tot_ctrl_size; + memcpy(ctrl->p_min.p, p_min.p_const, elem_size); + ctrl->p_max.p = ctrl->p_cur.p + 3 * tot_ctrl_size; + memcpy(ctrl->p_max.p, p_max.p_const, elem_size); + } for (idx = 0; idx < elems; idx++) { ctrl->type_ops->init(ctrl, idx, ctrl->p_cur); @@ -1617,7 +1727,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; @@ -1642,7 +1753,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); @@ -1675,7 +1787,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); @@ -1707,7 +1820,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); @@ -1715,7 +1829,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; @@ -1729,7 +1845,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); @@ -1753,7 +1869,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 21470de62d72..0f713b9a95f9 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 919e104de50b..c8ab8c44d7c6 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -131,6 +131,8 @@ struct v4l2_ctrl_ops { * * @equal: return true if both values are equal. * @init: initialize the value. + * @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. Return 0 on success and a negative value * otherwise. @@ -141,6 +143,10 @@ struct v4l2_ctrl_type_ops { union v4l2_ctrl_ptr ptr2); void (*init)(const struct v4l2_ctrl *ctrl, u32 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, u32 idx, union v4l2_ctrl_ptr ptr); @@ -237,6 +243,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. @@ -292,6 +304,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; }; @@ -398,6 +412,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. @@ -427,6 +443,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; @@ -696,17 +714,21 @@ 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 to compound controls, thanks + * to the @p_def/min/max field. Use v4l2_ctrl_ptr_create() to create + * @p_def/min/max from a pointer. Use v4l2_ctrl_ptr_create(NULL) if the + * default/min/max value of the compound control should be all zeroes. * */ 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 2e36bb610ea6..134f6a65eacc 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1796,6 +1796,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, From patchwork Tue Jun 28 07:57:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunke Cao X-Patchwork-Id: 12897872 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B63B2C433EF for ; Tue, 28 Jun 2022 07:58:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243310AbiF1H6c (ORCPT ); Tue, 28 Jun 2022 03:58:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53964 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243514AbiF1H6V (ORCPT ); Tue, 28 Jun 2022 03:58:21 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4AAE022B3F for ; Tue, 28 Jun 2022 00:57:54 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id li4-20020a17090b48c400b001eeec855ae1so1879048pjb.3 for ; Tue, 28 Jun 2022 00:57:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=BVnCtq4DRmPQW5iFurXbHjb7kWgxbL0xarKsJFp9Ck4=; b=TS+p2JsiWhwAX2uA9migG+CHniNgSrHwwCQlyxfVdeJ59DiYoRpF8XqKj8d3mgssCG eWGb/VCsW4AS2af9wSNocj/PthX6495Ku/1j2jaexJ6VELKY2kPqcuitLNwk/864DEaq WfuPKSyZpnh5EePAwW9MRiBo2V67SpAmLs58DcfUwPXmj6wvUCrOJC0jgg/jAjolNA2K fFM+GUwElrurc6T7brts50eG5GJtAAapJ+t8+NL9HCAPusdTq7yG+Z/MRbaNhhFw2Lrv hBh9x6L1R5sFOqoTWkYigixwyu4wjbptdrACjuMLv8faUXvTxgVhLWRap/4F65Lke+Ma vpyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=BVnCtq4DRmPQW5iFurXbHjb7kWgxbL0xarKsJFp9Ck4=; b=EDvhrgfDNuGqVE54KbhzwokP3pCRqpWx0UJk5uNmBegaFjCUGNSmxieRzhTxtUEddb nGUCjG5TEazdSop7yp0ACQKqo1nygJJcu/4UBVGKCI6fkSLMeHjFPcEEcf2FjVt9Mmvz eWcxAIUf+lW1Oj1R4hJw9VYBB0qnd+LNjvPfnyOawvCgS3fWGQmtZDpuCi/cqRRIat3n 29Fm59WGMSQo6N5vHsmJgZ9ndYKiVvNwZN/VuRkNqvOgYy5nX+RAjr31lv0RvamQOagj mYvk/ZUGoxyOz2XVJaGkScxSSMtT0UXfUyTWkujT1UfsxKzdFE8fVUYLFyWEK0Y1m64t svdg== X-Gm-Message-State: AJIora+P2yp0zusa23GRSrID7ut22L6TOeZosfVDZI0g8oEg+I5TF64M k+JP5btyottoNKv5JwGcxfcTNDX2Shs= X-Google-Smtp-Source: AGRyM1v2n//BOzFWYUoP9dCqHyfTQakFN+97p2nIduvFwMUfVNKjEaGtygMXMm3GJh+Tf39cEzwBAOCpQLI= X-Received: from yunkec1.tok.corp.google.com ([2401:fa00:8f:203:983d:14d6:e059:135f]) (user=yunkec job=sendgmr) by 2002:a17:902:7105:b0:168:dfe3:66e0 with SMTP id a5-20020a170902710500b00168dfe366e0mr3715978pll.88.1656403073833; Tue, 28 Jun 2022 00:57:53 -0700 (PDT) Date: Tue, 28 Jun 2022 16:57:04 +0900 In-Reply-To: <20220628075705.2278044-1-yunkec@google.com> Message-Id: <20220628075705.2278044-7-yunkec@google.com> Mime-Version: 1.0 References: <20220628075705.2278044-1-yunkec@google.com> X-Mailer: git-send-email 2.37.0.rc0.161.g10f37bed90-goog Subject: [PATCH v7 6/7] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL From: Yunke Cao To: Hans Verkuil , Laurent Pinchart , Nicolas Dufresne , Mauro Carvalho Chehab Cc: Tomasz Figa , Sergey Senozhatsky , Ricardo Ribalda , linux-media@vger.kernel.org, Yunke Cao Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add support for V4L2_CTRL_WHICH_MIN/MAX_VAL in uvc driver. It is useful for the V4L2_CID_UVC_REGION_OF_INTEREST_RECT control. Signed-off-by: Yunke Cao Reviewed-by: Ricardo Ribalda --- drivers/media/usb/uvc/uvc_ctrl.c | 73 ++++++++++++++++++++++++++------ drivers/media/usb/uvc/uvc_v4l2.c | 11 +++-- drivers/media/usb/uvc/uvcvideo.h | 3 +- 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 00482269233a..b569d6824ac1 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1923,7 +1923,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, } int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl) + struct v4l2_ext_control *xctrl, u32 v4l2_which) { struct v4l2_queryctrl qc = { .id = xctrl->id }; int ret = uvc_query_v4l2_ctrl(chain, &qc); @@ -1931,16 +1931,69 @@ int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain, if (ret < 0) return ret; - xctrl->value = qc.default_value; + switch (v4l2_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; + default: + return -EINVAL; + } + return 0; } +static int __uvc_ctrl_get_fixed_compound(struct uvc_video_chain *chain, + struct uvc_control_mapping *mapping, + struct uvc_control *ctrl, + u32 v4l2_which, + struct v4l2_ext_control *xctrl) +{ + int ret; + u32 flag, id; + + if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES) + return -EINVAL; + + switch (v4l2_which) { + case V4L2_CTRL_WHICH_DEF_VAL: + flag = UVC_CTRL_FLAG_GET_DEF; + id = UVC_CTRL_DATA_DEF; + break; + case V4L2_CTRL_WHICH_MIN_VAL: + flag = UVC_CTRL_FLAG_GET_MIN; + id = UVC_CTRL_DATA_MIN; + break; + case V4L2_CTRL_WHICH_MAX_VAL: + flag = UVC_CTRL_FLAG_GET_MAX; + id = UVC_CTRL_DATA_MAX; + break; + default: + return -EINVAL; + } + + if (!(ctrl->info.flags & flag) && flag != UVC_CTRL_FLAG_GET_DEF) + return -EACCES; + + if (!ctrl->cached) { + ret = uvc_ctrl_populate_cache(chain, ctrl); + if (ret < 0) + return ret; + } + + return __uvc_ctrl_get_compound_to_user(mapping, ctrl, id, xctrl); +} + int uvc_ctrl_get_fixed(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl) + struct v4l2_ext_control *xctrl, u32 v4l2_which) { struct uvc_control *ctrl; struct uvc_control_mapping *mapping; - int ret; if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) return -EACCES; @@ -1950,16 +2003,10 @@ int uvc_ctrl_get_fixed(struct uvc_video_chain *chain, return -EINVAL; if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES) - return __uvc_ctrl_get_fixed_std(chain, xctrl); + return __uvc_ctrl_get_fixed_std(chain, xctrl, v4l2_which); - if (!ctrl->cached) { - ret = uvc_ctrl_populate_cache(chain, ctrl); - if (ret < 0) - return ret; - } - - return __uvc_ctrl_get_compound_to_user(mapping, ctrl, UVC_CTRL_DATA_DEF, - xctrl); + return __uvc_ctrl_get_fixed_compound(chain, mapping, ctrl, v4l2_which, + xctrl); } int __uvc_ctrl_set_compound(struct uvc_control_mapping *mapping, diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index aad61af36271..004e3b764737 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -1043,16 +1043,21 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, if (ret < 0) return ret; - if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) { + switch (ctrls->which) { + case V4L2_CTRL_WHICH_DEF_VAL: + case V4L2_CTRL_WHICH_MIN_VAL: + case V4L2_CTRL_WHICH_MAX_VAL: for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_get_fixed(chain, ctrl); + ret = uvc_ctrl_get_fixed(chain, ctrl, ctrls->which); if (ret < 0) { ctrls->error_idx = i; return ret; } } - return 0; + + default: + break; } ret = uvc_ctrl_begin(chain); diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 9ff95bbad251..54cc47bc2d33 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -913,7 +913,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle) int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); int uvc_ctrl_get_fixed(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl); + struct v4l2_ext_control *xctrl, + u32 v4l2_which); int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl); int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, bool read); From patchwork Tue Jun 28 07:57:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunke Cao X-Patchwork-Id: 12897873 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 97843C433EF for ; Tue, 28 Jun 2022 07:58:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243813AbiF1H6f (ORCPT ); Tue, 28 Jun 2022 03:58:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53924 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243547AbiF1H6a (ORCPT ); Tue, 28 Jun 2022 03:58:30 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9A5A1275EC for ; Tue, 28 Jun 2022 00:57:59 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-3177d1fe9f1so97374727b3.0 for ; Tue, 28 Jun 2022 00:57:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=YOI77sIxA3gB3oIq55SWWisUXhJh1xYbLqE4v0RQ7AE=; b=oOPX6XcooxqNpwInCROAq6DJqyogzPBaOagU8vVGofNg6+fRgHwzzEBXfdsxuiV7XY TYcoAEEZAwGtNeQ/5c8fVUoIImguiKklDR0WANFX3iQBcMox76SNtxJaPB9PTM+1uVsn QorGWqRehkE20CYYc/6wqOYaQ2G+Gm5kgBJKRHpjsd+2zMzWiIOTW9yA6dBMzd5D4ffY 393yNZCScxCLt49eGHZw/+w7TZVlnHfSRzCothVsp6vh00GCUElS3zpOuA132rNB/M73 SvKeVXRUd0TqWXGD+hAkPolFAkan5Q23OvN0Nfo3Q1NRglSynHI60u0bHiJqu3s2RmDZ f/MQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=YOI77sIxA3gB3oIq55SWWisUXhJh1xYbLqE4v0RQ7AE=; b=rHaADZ3GXcTQNfDhfbNOvtErPi+YYN0FVriAtgCTQ5i/K4SHO9rkE+lBOjZHjvDVr5 gTXh50YO2DE4SNwUh+dibVem5lEWJjRMxqGoLfVjKoZWaeT4tAVULEv5GhzPCEdSi/mE tFY1pjdCxBdPX4zmYn2md7JRoJnnQRZxSjD0gi0RKUMu0SjkPOE1jfII7oPBJD4FDMqm 0Wdg/b7k4VIs91e5lFR+M4ta1q+VqdGqKznC4slpBgmw0iWVTABXHeHE2uazhrfTwTzG eSEMYZ9BKG8FxISRPnGBdarMdW/u2aWb2wjprhUANfKlKkRg+IVt7p2BijEHqsIyzYYn g+YA== X-Gm-Message-State: AJIora9EbHl5nVjJ9tdDvsasSZ5GE101CalZhm/YvsQzCBUUoeCSdrHt NQZviuRzOyVLPmaFZvVrfgDydrWS2Pc= X-Google-Smtp-Source: AGRyM1sY6sTM0O9UImy0pP4uGpaiyLk7pOJyye890ciGRTRDoAqC16iGDiVC221K26m5g89hp359XMkBfso= X-Received: from yunkec1.tok.corp.google.com ([2401:fa00:8f:203:983d:14d6:e059:135f]) (user=yunkec job=sendgmr) by 2002:a25:d705:0:b0:66a:1c7d:55ed with SMTP id o5-20020a25d705000000b0066a1c7d55edmr18388961ybg.21.1656403078912; Tue, 28 Jun 2022 00:57:58 -0700 (PDT) Date: Tue, 28 Jun 2022 16:57:05 +0900 In-Reply-To: <20220628075705.2278044-1-yunkec@google.com> Message-Id: <20220628075705.2278044-8-yunkec@google.com> Mime-Version: 1.0 References: <20220628075705.2278044-1-yunkec@google.com> X-Mailer: git-send-email 2.37.0.rc0.161.g10f37bed90-goog Subject: [PATCH v7 7/7] media: uvcvideo: document UVC v1.5 ROI From: Yunke Cao To: Hans Verkuil , Laurent Pinchart , Nicolas Dufresne , Mauro Carvalho Chehab Cc: Tomasz Figa , Sergey Senozhatsky , Ricardo Ribalda , linux-media@vger.kernel.org, Yunke Cao Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Added documentation of V4L2_CID_UVC_REGION_OF_INTEREST_RECT and V4L2_CID_UVC_REGION_OF_INTEREST_AUTO. Signed-off-by: Yunke Cao Reviewed-by: Ricardo Ribalda --- .../userspace-api/media/drivers/uvcvideo.rst | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/Documentation/userspace-api/media/drivers/uvcvideo.rst b/Documentation/userspace-api/media/drivers/uvcvideo.rst index a290f9fadae9..ee4c182aa274 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,63 @@ 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 + +Private V4L2 controls +--------------------- + +A few UVC specific V4L2 control IDs are listed below. + +``V4L2_CID_UVC_REGION_OF_INTEREST_RECT (struct)`` + This control determines the region of interest (ROI). ROI is an + 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. For example, a device can have a minimum + ROI rectangle of 1x1@0x0 and a maximum of 640x480@0x0. + + 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. + + +``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_REGION_OF_INTEREST_AUTO_EXPOSURE`` + - Setting this to true enables automatic exposure time for the specified + region. + * - ``V4L2_REGION_OF_INTEREST_AUTO_IRIS`` + - Setting this to true enables automatic iris aperture for the specified + region. + * - ``V4L2_REGION_OF_INTEREST_AUTO_WHITE_BALANCE`` + - Setting this to true enables automatic white balance adjustment for the + specified region. + * - ``V4L2_REGION_OF_INTEREST_AUTO_FOCUS`` + - Setting this to true enables automatic focus adjustment for the + specified region. + * - ``V4L2_REGION_OF_INTEREST_AUTO_FACE_DETECT`` + - Setting this to true enables automatic face detection for the + specified region. + * - ``V4L2_REGION_OF_INTEREST_AUTO_DETECT_AND_TRACK`` + - Setting this to true enables automatic face detection and tracking. The + current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by + the driver. + * - ``V4L2_REGION_OF_INTEREST_AUTO_IMAGE_STABILIZATION`` + - Setting this to true enables automatic image stabilization. The + current value of ``V4L2_CID_REGION_OF_INTEREST_RECT`` may be updated by + the driver. + * - ``V4L2_REGION_OF_INTEREST_AUTO_HIGHER_QUALITY`` + - Setting this to true enables automatically capture the specified region + with higher quality if possible.