摘要
我目前正在尝试在Linux内核驱动程序中调用V4L2之后,向V4L2设备添加自定义v4l2_ctrl_handler_setup控件。但是,该控件似乎没有被添加(在运行v4l2-ctl --list-ctrls时不会显示)。下面是我试图采用的一般方法。
static int add_custom_v4l2_ctrls(struct tegracam_device *tc_dev)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct v4l2_ctrl_handler *ctrl_handler = s_data->ctrl_handler;
struct v4l2_ctrl *ctrl;
int err = 0;
static struct v4l2_ctrl_config my_control = {
.ops = &my_custom_ctrl_ops,
.id = TEGRA_CAMERA_CID_BASE+150,
.name = "My control",
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = 0,
.max = 1,
.def = 0,
.step = 1,
};
// Increment number of controls
tc_dev->numctrls++;
s_data->numctrls++;
ctrl = v4l2_ctrl_new_custom(ctrl_handler, &my_control, NULL);
if(ctrl == NULL) {
dev_err(tc_dev->dev, "Failed to init ctrl");
return -EIO;
}
// err = v4l2_ctrl_handler_setup(ctrl_handler);
if(err) {
printk("FAILED");
}
return 0;
}此代码片段在有效调用v4l2_ctrl_handler_setup和v4l2_async_register_subdev之后运行。
问题
是否可以在注册设备后添加自定义V4L2控件?如果是这样,我的方法出了什么问题,导致控件不显示?
更多信息
该驱动程序是使用NVIDIA的Tegracam V2框架实现的,该框架抽象了V4L2设置代码,包括添加控件,目前它没有公开添加自定义V4L2控件的能力,而这正是这种方法背后的原因。
发布于 2021-05-08 04:02:16
在遵循调用堆栈之后,我发现了这个顺序(箭头表示调用,链接指向Linux源代码)。
v4l2_async_register_subdev -> v4l2_async_match_notify -> v4l2_device_register_subdev -> v4l2_ctrl_add_handler
最后一个函数(v4l2_ctrl_add_handler)遍历V4L2控件,并将其从一个处理程序复制到另一个处理程序。
因此,如果在调用v4l2_async_register_subdev之前没有添加V4L2控件,则该控件将不会被复制到不同的设备,因此将不是有效的选项。
总而言之,从我发现的情况来看,不可能在设备注册后添加V4L2控件。
发布于 2021-06-16 20:17:42
这可能来得有点晚,因为您已经标记了一个解决方案,但我相信我有一个解决方案可以帮助您。我将尽我最大的努力来解释我是如何向tegracamv2框架添加自定义控件的。
不幸的是,在v4l2_async_register_subdev注册子设备之后,您不能添加控件,但是,您可以使用tc_dev结构的v4l2sd_internal_ops字段中定义的已注册回调来挂钩到异步框架。这允许您定义自己的控制处理程序,然后将其从it框架添加到控制处理程序,然后将其添加到v4l2设备。
我最近在这个问题上苦苦挣扎,我发现这是我唯一的解决方案,除了在it框架中修补对v4l2_async_register_subdev的调用,并在添加控件后手动调用它(这是未经测试的)。
相关代码(这假设了一个ctrl_config数组,但展示了它的思想。我还假设您已经定义了ctrl_ops和配置。):
static int my_subdev_register(struct v4l2_subdev *sd)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct my_priv *priv = (struct my_priv *)s_data->priv;
struct v4l2_ctrl *ctrl;
int err, i, num_ctrls;
// setup custom controls
num_ctrls = ARRAY_SIZE(ctrl_config_list);
v4l2_ctrl_handler_init(&priv->ctrl_handler, num_ctrls);
for (i = 0; i < num_ctrls; i++) {
ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler,
&ctrl_config_list[i], NULL);
if (ctrl == NULL) {
dev_err(&client->dev, "Failed to init %s ctrl\n",
ctrl_config_list[i].name);
continue;
}
if (err)
return err;
// I believe storing the pointer is technically optional
priv->ctrls[i] = ctrl;
}
priv->num_ctrls = num_ctrls;
//This is where the magic happens
err = v4l2_ctrl_add_handler(
sd->ctrl_handler,
&priv->ctrl_handler,
NULL);
if (err)
goto error;
return 0;
error:
v4l2_ctrl_handler_free(&priv->ctrl_handler);
return err;
}
...
static const struct v4l2_subdev_internal_ops my_subdev_internal_ops = {
.registered = my_subdev_register,
};然后,在探测函数中,在tegracam_device_register之前包含以下内容。(但它不会在tegracam_v4l2subdev_register之前被调用。)
tc_dev->sensor_ops = &my_subdev_internal_ops;https://stackoverflow.com/questions/67387100
复制相似问题