From patchwork Thu Jun 20 15:31:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1486 Return-Path: Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 38D1160BA1 for ; Thu, 20 Jun 2019 17:30:42 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay1-d.mail.gandi.net (Postfix) with ESMTPSA id C4140240006; Thu, 20 Jun 2019 15:30:41 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 20 Jun 2019 17:31:41 +0200 Message-Id: <20190620153144.5394-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190620153144.5394-1-jacopo@jmondi.org> References: <20190620153144.5394-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 3/6] libcamera: v4l2_device: Implement get and set controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 Jun 2019 15:30:42 -0000 Implement getControls() and setControls() operations in V4L2Device class. Both operations take a V4L2Controls instance and read or write the V4L2 controls on the V4L2 device. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_device.h | 3 + src/libcamera/v4l2_device.cpp | 193 ++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index 91a72fcecbcc..3af27c9f7af5 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -15,6 +15,7 @@ namespace libcamera { class V4L2ControlInfo; +class V4L2Controls; class V4L2Device : protected Loggable { @@ -23,6 +24,8 @@ public: bool isOpen() const { return fd_ != -1; } const V4L2ControlInfo *getControlInfo(unsigned int id) const; + int getControls(V4L2Controls *ctrls); + int setControls(V4L2Controls *ctrls); const std::string &deviceNode() const { return deviceNode_; } diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index b113ff77e3cf..efe30ef856ae 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -125,6 +125,199 @@ const V4L2ControlInfo *V4L2Device::getControlInfo(unsigned int id) const return &it->second; } +/** + * \brief Read controls from the device + * \param[inout] ctrls The list of controls to read + * + * Read the value of each control contained in \a ctrls, and store the + * value in the corresponding \a ctrls entry. + * + * If an integer number less than the requested number of controls is returned, + * only controls up to that index have been successfully read. + * + * Each V4L2Control instance in \a ctrls should be supported by the device and + * accessible (ie the V4L2_CTRL_FLAG_DISABLED flag should not be set), otherwise + * a negative error code (-EINVAL) is returned + * + * \return 0 on success or an error code otherwise + * \retval -EINVAL One of the control is not supported or not accessible + * \retval i The index of the control that failed + */ +int V4L2Device::getControls(V4L2Controls *ctrls) +{ + unsigned int count = ctrls->size(); + if (count == 0) + return 0; + + const V4L2ControlInfo *controlInfo[count] = {}; + struct v4l2_ext_control v4l2Ctrls[count] = {}; + + for (unsigned int i = 0; i < count; ++i) { + V4L2Control *ctrl = (*ctrls)[i]; + + const V4L2ControlInfo *info = getControlInfo(ctrl->id()); + if (!info) { + LOG(V4L2, Error) + << "Control '" << ctrl->id() << "' not found"; + return -EINVAL; + } + + controlInfo[i] = info; + v4l2Ctrls[i].id = info->id(); + } + + struct v4l2_ext_controls v4l2ExtCtrls = {}; + v4l2ExtCtrls.which = V4L2_CTRL_WHICH_CUR_VAL; + v4l2ExtCtrls.controls = v4l2Ctrls; + v4l2ExtCtrls.count = count; + + int ret = ioctl(VIDIOC_G_EXT_CTRLS, &v4l2ExtCtrls); + if (ret) { + unsigned int errorIdx = v4l2ExtCtrls.error_idx; + + /* Generic validation error. */ + if (errorIdx == count) { + LOG(V4L2, Error) << "Unable to read controls: " + << strerror(ret); + return -EINVAL; + } + + /* A specific control failed. */ + LOG(V4L2, Error) << "Unable to read control " << errorIdx + << ": " << strerror(ret); + return errorIdx; + } + + /* + * For each control read from the device, set the value in the + * V4L2Control provided by the caller. + */ + for (unsigned int i = 0; i < count; ++i) { + struct v4l2_ext_control *v4l2Ctrl = &v4l2Ctrls[i]; + const V4L2ControlInfo *info = controlInfo[i]; + V4L2Control *ctrl = (*ctrls)[i]; + + switch (info->type()) { + case V4L2_CTRL_TYPE_INTEGER64: + ctrl->setValue(v4l2Ctrl->value64); + break; + default: + /* + * \todo To be changed when support for string and + * compound controls will be added. + */ + ctrl->setValue(static_cast(v4l2Ctrl->value)); + break; + } + } + + return 0; +} + +/** + * \brief Write controls to the device + * \param[in] ctrls The list of controls to write + * + * Write the value of each V4L2Control contained in \a ctrls. Each + * control should be initialized by the caller with a value, otherwise + * the result of the operation is undefined. + * + * The value of each control is updated to reflect what has been + * actually applied on the device. + * + * If an integer number less than the requested number of controls is returned, + * only controls up to that index have been successfully applied. + * + * Each V4L2Control instance in \a ctrls should be supported by the device and + * accessible (ie the V4L2_CTRL_FLAG_DISABLED flag should not be set), otherwise + * a negative error code (-EINVAL) is returned + * + * \return 0 on success or an error code otherwise + * \retval -EINVAL One of the control is not supported or not accessible + * \retval i The index of the control that failed + */ +int V4L2Device::setControls(V4L2Controls *ctrls) +{ + unsigned int count = ctrls->size(); + if (count == 0) + return 0; + + const V4L2ControlInfo *controlInfo[count] = {}; + struct v4l2_ext_control v4l2Ctrls[count] = {}; + + for (unsigned int i = 0; i < count; ++i) { + V4L2Control *ctrl = (*ctrls)[i]; + + const V4L2ControlInfo *info = getControlInfo(ctrl->id()); + if (!info) { + LOG(V4L2, Error) + << "Control '" << ctrl->id() << "' not found"; + return -EINVAL; + } + + controlInfo[i] = info; + v4l2Ctrls[i].id = info->id(); + + /* Set the v4l2_ext_control value for the write operation. */ + switch (info->type()) { + case V4L2_CTRL_TYPE_INTEGER64: + v4l2Ctrls[i].value64 = ctrl->value(); + break; + default: + /* + * \todo To be changed when support for string and + * compound controls will be added. + */ + v4l2Ctrls[i].value = static_cast(ctrl->value()); + break; + } + } + + struct v4l2_ext_controls v4l2ExtCtrls = {}; + v4l2ExtCtrls.which = V4L2_CTRL_WHICH_CUR_VAL; + v4l2ExtCtrls.controls = v4l2Ctrls; + v4l2ExtCtrls.count = count; + + int ret = ioctl(VIDIOC_S_EXT_CTRLS, &v4l2ExtCtrls); + if (ret) { + unsigned int errorIdx = v4l2ExtCtrls.error_idx; + + /* Generic validation error. */ + if (errorIdx == count) { + LOG(V4L2, Error) << "Unable to read controls: " + << strerror(ret); + return -EINVAL; + } + + /* A specific control failed. */ + LOG(V4L2, Error) << "Unable to read control " << errorIdx + << ": " << strerror(ret); + return errorIdx; + } + + /* Update the control value to what have actually been applied. */ + for (unsigned int i = 0; i < count; ++i) { + struct v4l2_ext_control *v4l2Ctrl = &v4l2Ctrls[i]; + const V4L2ControlInfo *info = controlInfo[i]; + V4L2Control *ctrl = (*ctrls)[i]; + + switch (info->type()) { + case V4L2_CTRL_TYPE_INTEGER64: + ctrl->setValue(v4l2Ctrl->value64); + break; + default: + /* + * \todo To be changed when support for string and + * compound controls will be added. + */ + ctrl->setValue(static_cast(v4l2Ctrl->value)); + break; + } + } + + return 0; +} + /** * \brief Perform an IOCTL system call on the device node * \param[in] request The IOCTL request code