| /* Copyright 2023 The ChromiumOS Authors | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| /* Setters for abstract models of V4L2 controls. | |
| * | |
| * If the model has an fd for a kernel device set, then the setters will | |
| * propagate the new values to the kernel. | |
| * | |
| * Return values: | |
| * - on success: true | |
| * - on failure: false | |
| */ | |
| #include "tools/mctk/control.h" | |
| #include <linux/media.h> | |
| #include <linux/types.h> | |
| #include <linux/videodev2.h> | |
| #include <stddef.h> /* size_t */ | |
| #include <sys/ioctl.h> | |
| #include <optional> | |
| #include <string> | |
| #include <vector> | |
| #include "tools/mctk/debug.h" | |
| bool V4lMcControl::WrapIoctl(struct v4l2_ext_control& controls) { | |
| if (fd_ent_.has_value()) { | |
| struct v4l2_ext_controls ext_controls = {}; | |
| ext_controls.which = V4L2_CTRL_WHICH_CUR_VAL; | |
| ext_controls.count = 1; | |
| ext_controls.controls = &controls; | |
| if (ioctl(fd_ent_.value(), VIDIOC_S_EXT_CTRLS, &ext_controls) < 0) { | |
| MCTK_PERROR("VIDIOC_S_EXT_CTRLS"); | |
| MCTK_ERR("Failed setting control " + std::to_string(desc_.id)); | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool V4lMcControl::Set(std::vector<__s32>& values_s32) { | |
| MCTK_ASSERT(!this->IsReadOnly()); | |
| MCTK_ASSERT(this->desc_.type == V4L2_CTRL_TYPE_INTEGER || | |
| this->desc_.type == V4L2_CTRL_TYPE_BOOLEAN || | |
| this->desc_.type == V4L2_CTRL_TYPE_MENU || | |
| this->desc_.type == V4L2_CTRL_TYPE_BUTTON || | |
| this->desc_.type == V4L2_CTRL_TYPE_BITMASK || | |
| this->desc_.type == V4L2_CTRL_TYPE_INTEGER_MENU); | |
| MCTK_ASSERT_EQ(values_s32.size(), this->desc_.elems); | |
| this->values_s32_ = values_s32; | |
| struct v4l2_ext_control ec = {}; | |
| ec.id = this->desc_.id; | |
| ec.size = values_s32.size() * sizeof(values_s32[0]); | |
| ec.ptr = this->values_s32_.data(); | |
| /* Legacy controls are set to a value rather than a pointer */ | |
| if (!this->desc_.nr_of_dims) { | |
| MCTK_ASSERT_EQ(values_s32.size(), 1); | |
| ec.size = 0; | |
| ec.value = this->values_s32_[0]; | |
| } | |
| return WrapIoctl(ec); | |
| } | |
| bool V4lMcControl::Set(std::vector<__s64>& values_s64) { | |
| MCTK_ASSERT(!this->IsReadOnly()); | |
| MCTK_ASSERT_EQ(this->desc_.type, V4L2_CTRL_TYPE_INTEGER64); | |
| MCTK_ASSERT_EQ(values_s64.size(), this->desc_.elems); | |
| this->values_s64_ = values_s64; | |
| struct v4l2_ext_control ec = {}; | |
| ec.id = this->desc_.id; | |
| ec.size = values_s64.size() * sizeof(values_s64[0]); | |
| ec.ptr = this->values_s64_.data(); | |
| /* Legacy controls are set to a value rather than a pointer */ | |
| if (!this->desc_.nr_of_dims) { | |
| MCTK_ASSERT_EQ(values_s64.size(), 1); | |
| ec.size = 0; | |
| ec.value = this->values_s64_[0]; | |
| } | |
| return WrapIoctl(ec); | |
| } | |
| bool V4lMcControl::Set(std::vector<std::string>& values_string) { | |
| MCTK_ASSERT(!this->IsReadOnly()); | |
| MCTK_ASSERT_EQ(this->desc_.type, V4L2_CTRL_TYPE_STRING); | |
| MCTK_ASSERT(this->desc_.elem_size >= 1); | |
| MCTK_ASSERT_EQ(values_string.size(), this->desc_.elems); | |
| /* Check that the new strings aren't overflowing the target. | |
| * Note that they have to be SHORTER than elem_size, because | |
| * elem_size includes the terminating '\0', whereas C++ | |
| * std::string's .size() does not include it. | |
| */ | |
| for (std::string& val : values_string) { | |
| MCTK_ASSERT(val.size() < this->desc_.elem_size); | |
| } | |
| this->values_string_ = values_string; | |
| /* Temporary buffer for uploading to kernel */ | |
| std::vector<char> temp; | |
| temp.resize(this->desc_.elems * this->desc_.elem_size); | |
| for (size_t i = 0; i < this->desc_.elems; i++) { | |
| strncpy(&temp.data()[i * this->desc_.elem_size], | |
| this->values_string_[i].c_str(), this->desc_.elem_size - 1); | |
| } | |
| struct v4l2_ext_control ec = {}; | |
| ec.id = this->desc_.id; | |
| ec.size = this->desc_.elems * this->desc_.elem_size; | |
| ec.string = temp.data(); | |
| return WrapIoctl(ec); | |
| } | |
| bool V4lMcControl::Set(std::vector<__u8>& values_u8) { | |
| MCTK_ASSERT(!this->IsReadOnly()); | |
| MCTK_ASSERT_EQ(this->desc_.type, V4L2_CTRL_TYPE_U8); | |
| MCTK_ASSERT_EQ(values_u8.size(), this->desc_.elems); | |
| this->values_u8_ = values_u8; | |
| struct v4l2_ext_control ec = {}; | |
| ec.id = this->desc_.id; | |
| ec.size = this->desc_.elems * this->desc_.elem_size; | |
| ec.p_u8 = this->values_u8_.data(); | |
| return WrapIoctl(ec); | |
| } | |
| bool V4lMcControl::Set(std::vector<__u16>& values_u16) { | |
| MCTK_ASSERT(!this->IsReadOnly()); | |
| MCTK_ASSERT_EQ(this->desc_.type, V4L2_CTRL_TYPE_U16); | |
| MCTK_ASSERT_EQ(values_u16.size(), this->desc_.elems); | |
| this->values_u16_ = values_u16; | |
| struct v4l2_ext_control ec = {}; | |
| ec.id = this->desc_.id; | |
| ec.size = this->desc_.elems * this->desc_.elem_size; | |
| ec.p_u16 = this->values_u16_.data(); | |
| return WrapIoctl(ec); | |
| } | |
| bool V4lMcControl::Set(std::vector<__u32>& values_u32) { | |
| MCTK_ASSERT(!this->IsReadOnly()); | |
| MCTK_ASSERT_EQ(this->desc_.type, V4L2_CTRL_TYPE_U32); | |
| MCTK_ASSERT_EQ(values_u32.size(), this->desc_.elems); | |
| this->values_u32_ = values_u32; | |
| struct v4l2_ext_control ec = {}; | |
| ec.id = this->desc_.id; | |
| ec.size = this->desc_.elems * this->desc_.elem_size; | |
| ec.p_u32 = this->values_u32_.data(); | |
| return WrapIoctl(ec); | |
| } | |
| #ifdef V4L2_CTRL_TYPE_AREA | |
| bool V4lMcControl::Set(std::vector<struct v4l2_area>& values_area) { | |
| MCTK_ASSERT(!this->IsReadOnly()); | |
| MCTK_ASSERT_EQ(this->desc_.type, V4L2_CTRL_TYPE_AREA); | |
| MCTK_ASSERT_EQ(values_area.size(), this->desc_.elems); | |
| this->values_area_ = values_area; | |
| struct v4l2_ext_control ec = {}; | |
| ec.id = this->desc_.id; | |
| ec.size = this->desc_.elems * this->desc_.elem_size; | |
| ec.p_area = this->values_area_.data(); | |
| return WrapIoctl(ec); | |
| } | |
| #endif /* V4L2_CTRL_TYPE_AREA */ | |
| template <typename T> | |
| bool V4lMcControl::Set(T value) { | |
| std::vector<T> temp = {value}; | |
| return this->Set(temp); | |
| } | |
| template bool V4lMcControl::Set<__s32>(__s32 value); | |
| template bool V4lMcControl::Set<__s64>(__s64 value); |