[{"id":16603,"web_url":"https://patchwork.libcamera.org/comment/16603/","msgid":"<YIeJA7WjUU8ltlk/@pendragon.ideasonboard.com>","date":"2021-04-27T03:46:11","subject":"Re: [libcamera-devel] [PATCH v2 3/7] libcamera: V4L2Device: Support\n\tv4l2 menu control","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Hiro,\n\nThank you for the patch.\n\nOn Wed, Apr 21, 2021 at 01:23:42PM +0900, Hirokazu Honda wrote:\n> This adds a support of v4l2 menu.\n> \n> Signed-off-by: Hirokazu Honda <hiroh@chromium.org>\n> ---\n>  include/libcamera/internal/v4l2_controls.h |  1 +\n>  include/libcamera/internal/v4l2_device.h   |  3 +\n>  src/libcamera/v4l2_controls.cpp            | 10 ++-\n>  src/libcamera/v4l2_device.cpp              | 90 ++++++++++++++++++++--\n>  4 files changed, 98 insertions(+), 6 deletions(-)\n> \n> diff --git a/include/libcamera/internal/v4l2_controls.h b/include/libcamera/internal/v4l2_controls.h\n> index 0851b8dd..c42f2529 100644\n> --- a/include/libcamera/internal/v4l2_controls.h\n> +++ b/include/libcamera/internal/v4l2_controls.h\n> @@ -24,6 +24,7 @@ class V4L2ControlInfo : public ControlInfo\n>  {\n>  public:\n>  \tV4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl);\n> +\tV4L2ControlInfo(const ControlInfo &ctrl);\n\nThe purpose of the V4L2ControlInfo class is to provide an easy way to\nconstruct a ControlInfo from v4l2_query_ext_ctrl. It has no data member,\nso it's really only a convenience constructor. If we need to make\ncopies, let's use the base ControlInfo class. That's what we store in\nthe ControlInfoMap.\n\n>  };\n>  \n>  } /* namespace libcamera */\n> diff --git a/include/libcamera/internal/v4l2_device.h b/include/libcamera/internal/v4l2_device.h\n> index 4cce3840..2436a83c 100644\n> --- a/include/libcamera/internal/v4l2_device.h\n> +++ b/include/libcamera/internal/v4l2_device.h\n> @@ -53,6 +53,9 @@ protected:\n>  \tint fd() const { return fd_; }\n>  \n>  private:\n> +\tbool createV4L2ControlInfoForMenu(const v4l2_query_ext_ctrl &ctrl,\n> +\t\t\t\t\t  V4L2ControlInfo &v4l2CtrlInfo);\n> +\n>  \tvoid listControls();\n>  \tvoid updateControls(ControlList *ctrls,\n>  \t\t\t    const std::vector<v4l2_ext_control> &v4l2Ctrls);\n> diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp\n> index 3f8ec6ca..2c965cfa 100644\n> --- a/src/libcamera/v4l2_controls.cpp\n> +++ b/src/libcamera/v4l2_controls.cpp\n> @@ -73,9 +73,12 @@ ControlType v4l2_ctrl_type(const struct v4l2_query_ext_ctrl &ctrl)\n>  \t\treturn ControlTypeInteger64;\n>  \n>  \tcase V4L2_CTRL_TYPE_MENU:\n> +\tcase V4L2_CTRL_TYPE_INTEGER_MENU:\n> +\t\treturn ControlTypeMenu;\n> +\n>  \tcase V4L2_CTRL_TYPE_BUTTON:\n>  \tcase V4L2_CTRL_TYPE_BITMASK:\n> -\tcase V4L2_CTRL_TYPE_INTEGER_MENU:\n> +\n>  \t\t/*\n>  \t\t * More precise types may be needed, for now use a 32-bit\n>  \t\t * integer type.\n> @@ -148,4 +151,9 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)\n>  \t}\n>  }\n>  \n> +V4L2ControlInfo::V4L2ControlInfo(const ControlInfo &ctrl)\n> +\t: ControlInfo(ctrl)\n> +{\n> +}\n> +\n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp\n> index 8f29cd7f..585e527b 100644\n> --- a/src/libcamera/v4l2_device.cpp\n> +++ b/src/libcamera/v4l2_device.cpp\n> @@ -459,6 +459,47 @@ int V4L2Device::ioctl(unsigned long request, void *argp)\n>   * \\return The device node path\n>   */\n>  \n> +bool V4L2Device::createV4L2ControlInfoForMenu(const v4l2_query_ext_ctrl &ctrl,\n> +\t\t\t\t\t      V4L2ControlInfo &v4l2CtrlInfo)\n> +{\n> +\tASSERT(ctrl.type == V4L2_CTRL_TYPE_MENU ||\n> +\t       ctrl.type == V4L2_CTRL_TYPE_INTEGER_MENU);\n> +\tconst bool isName = ctrl.type == V4L2_CTRL_TYPE_MENU;\n> +\n> +\tstd::vector<ControlValue> values;\n> +\tv4l2_querymenu menu;\n> +\tmemset(&menu, 0, sizeof(menu));\n> +\tmenu.id = ctrl.id;\n> +\tfor (menu.index = ctrl.minimum;\n> +\t     static_cast<int>(menu.index) <= ctrl.maximum; menu.index++) {\n> +\t\tif (ioctl(VIDIOC_QUERYMENU, &menu) != 0)\n> +\t\t\tcontinue;\n> +\t\tControlMenu ctrlMenu;\n> +\t\tctrlMenu.index = static_cast<int32_t>(menu.index);\n> +\t\tctrlMenu.isName = isName;\n> +\t\tif (isName) {\n> +\t\t\tstrcpy(ctrlMenu.name,\n> +\t\t\t       reinterpret_cast<const char *>(menu.name));\n> +\t\t} else {\n> +\t\t\tctrlMenu.value = menu.value;\n> +\t\t}\n> +\n> +\t\tvalues.push_back(ControlValue(ctrlMenu));\n> +\t}\n> +\n> +\tif (values.empty()) {\n> +\t\tLOG(V4L2, Error)\n> +\t\t\t<< \"No applicable value: \" << utils::hex(ctrl.id);\n> +\t\treturn false;\n> +\t}\n> +\n> +\tv4l2CtrlInfo = V4L2ControlInfo(\n> +\t\tControlInfo(libcamera::Span<const ControlValue>(\n> +\t\t\tvalues.data(), values.size())));\n\nThere's no need to go through V4L2ControlInfo here, ControlInfo is all\nyou need.\n\n> +\n> +\treturn true;\n> +}\n> +\n>  /**\n>   * \\fn V4L2Device::fd()\n>   * \\brief Retrieve the V4L2 device file descriptor\n> @@ -474,7 +515,6 @@ void V4L2Device::listControls()\n>  \tControlInfoMap::Map ctrls;\n>  \tstruct v4l2_query_ext_ctrl ctrl = {};\n>  \n> -\t/* \\todo Add support for menu controls. */\n>  \twhile (1) {\n>  \t\tctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL |\n>  \t\t\t   V4L2_CTRL_FLAG_NEXT_COMPOUND;\n> @@ -485,15 +525,20 @@ void V4L2Device::listControls()\n>  \t\t    ctrl.flags & V4L2_CTRL_FLAG_DISABLED)\n>  \t\t\tcontinue;\n>  \n> +\t\tV4L2ControlInfo v4l2CtrlInfo(ControlInfo(0));\n\nThat seems like a hack :-)\n\n>  \t\tswitch (ctrl.type) {\n>  \t\tcase V4L2_CTRL_TYPE_INTEGER:\n>  \t\tcase V4L2_CTRL_TYPE_BOOLEAN:\n> -\t\tcase V4L2_CTRL_TYPE_MENU:\n>  \t\tcase V4L2_CTRL_TYPE_BUTTON:\n>  \t\tcase V4L2_CTRL_TYPE_INTEGER64:\n>  \t\tcase V4L2_CTRL_TYPE_BITMASK:\n> -\t\tcase V4L2_CTRL_TYPE_INTEGER_MENU:\n>  \t\tcase V4L2_CTRL_TYPE_U8:\n> +\t\t\tv4l2CtrlInfo = V4L2ControlInfo(ctrl);\n> +\t\t\tbreak;\n> +\t\tcase V4L2_CTRL_TYPE_MENU:\n> +\t\tcase V4L2_CTRL_TYPE_INTEGER_MENU:\n> +\t\t\tif (!createV4L2ControlInfoForMenu(ctrl, v4l2CtrlInfo))\n> +\t\t\t\tcontinue;\n>  \t\t\tbreak;\n>  \t\t/* \\todo Support other control types. */\n>  \t\tdefault:\n> @@ -503,10 +548,13 @@ void V4L2Device::listControls()\n>  \t\t\tcontinue;\n>  \t\t}\n>  \n> +\t\tLOG(V4L2, Debug) << \"Control: \" << ctrl.name\n> +\t\t\t\t << \" (\" << utils::hex(ctrl.id) << \")\";\n> +\n>  \t\tcontrolIds_.emplace_back(std::make_unique<V4L2ControlId>(ctrl));\n>  \t\tcontrolInfo_.emplace(ctrl.id, ctrl);\n>  \n> -\t\tctrls.emplace(controlIds_.back().get(), V4L2ControlInfo(ctrl));\n> +\t\tctrls.emplace(controlIds_.back().get(), std::move(v4l2CtrlInfo));\n>  \t}\n>  \n>  \tcontrols_ = std::move(ctrls);\n> @@ -539,7 +587,39 @@ void V4L2Device::updateControls(ControlList *ctrls,\n>  \t\tcase ControlTypeInteger64:\n>  \t\t\tnewValue.set<int64_t>(v4l2Ctrl.value64);\n>  \t\t\tbreak;\n> -\n> +\t\tcase ControlTypeMenu:\n> +\t\t\tswitch (v4l2Ctrl.id) {\n> +\t\t\tcase V4L2_CID_TEST_PATTERN: {\n\nLet's keep specific control IDs out of this code, it should be\nimplemented generically for all menu controls.\n\n> +\t\t\t\tControlMenu menu;\n> +\t\t\t\tmenu.index = v4l2Ctrl.value;\n> +\t\t\t\tmenu.isName = true;\n> +\n> +\t\t\t\tbool found = false;\n> +\t\t\t\tfor (const ControlValue &validValue : it->second.values()) {\n> +\t\t\t\t\tconst auto &ctrlMenu = validValue.get<ControlMenu>();\n> +\t\t\t\t\tif (!ctrlMenu.isName)\n> +\t\t\t\t\t\tcontinue;\n> +\t\t\t\t\tif (menu.index == ctrlMenu.index) {\n> +\t\t\t\t\t\tstrcpy(menu.name, ctrlMenu.name);\n> +\t\t\t\t\t\tfound = true;\n> +\t\t\t\t\t\tbreak;\n> +\t\t\t\t\t}\n> +\t\t\t\t}\n> +\n> +\t\t\t\tif (!found) {\n> +\t\t\t\t\tLOG(V4L2, Error)\n> +\t\t\t\t\t\t<< \"Matched value is not found\"\n> +\t\t\t\t\t\t<< \", index=\" << menu.index;\n> +\t\t\t\t\tcontinue;\n> +\t\t\t\t}\n> +\n> +\t\t\t\tnewValue.set<ControlMenu>(menu);\n> +\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\tdefault:\n> +\t\t\t\tLOG(V4L2, Error) << \"Unknown id: \" << v4l2Ctrl.id;\n> +\t\t\t\tbreak;\n> +\t\t\t}\n>  \t\tcase ControlTypeByte:\n>  \t\t\t/*\n>  \t\t\t * No action required, the VIDIOC_[GS]_EXT_CTRLS ioctl","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 83903BDCA6\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 27 Apr 2021 03:46:19 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0291668880;\n\tTue, 27 Apr 2021 05:46:19 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9A65B60512\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 27 Apr 2021 05:46:17 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 05D88E9;\n\tTue, 27 Apr 2021 05:46:16 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"c1u5XTg2\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1619495177;\n\tbh=6iLbsRldjybFBOqyrhKJYF0M5o16BimsnECzsDsErEQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=c1u5XTg2HUHzyV1dmuVnCP7S9VblnBBkHpNltpFFbUvWzZIjwlRUvPJCqoTwa1S3N\n\tO2Q0UibHP2M+pdTPeZxFeGBjXnwmG83Yo5MmecbNsiceaZ9+oveFdpLds9XXljTKGm\n\t6/87BxLLsMXIXufCpGdGxHm6xohGUq4dOuYfZBOQ=","Date":"Tue, 27 Apr 2021 06:46:11 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Hirokazu Honda <hiroh@chromium.org>","Message-ID":"<YIeJA7WjUU8ltlk/@pendragon.ideasonboard.com>","References":"<20210421042346.312854-1-hiroh@chromium.org>\n\t<20210421042346.312854-4-hiroh@chromium.org>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210421042346.312854-4-hiroh@chromium.org>","Subject":"Re: [libcamera-devel] [PATCH v2 3/7] libcamera: V4L2Device: Support\n\tv4l2 menu control","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]