Adding custom V4L2 Controls After V4L2 handler setup

1.3k views Asked by At

Summary

I'm currently trying to add custom V4L2 controls to a V4L2 device after v4l2_ctrl_handler_setup is called in a Linux Kernel driver. However the control does not seem to be added (does not show up when running v4l2-ctl --list-ctrls). Below is generally the approach I am trying to take.

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;
}

This code snippet is run after an effective call to v4l2_ctrl_handler_setup and v4l2_async_register_subdev.

Question

Is it possible to add custom V4L2 controls after the device has been registered? If so, what is wrong with my approach which is causing the control to not show up?

More Info

This driver is implemented using NVIDIA's Tegracam V2 framework which abstracts V4L2 setup code including the addition of controls, at the moment it does not expose the ability for adding custom V4L2 controls which is the reasoning behind this approach.

2

There are 2 answers

0
cbolles On BEST ANSWER

After following down the call stack I found this order (arrows represent calls, links are to the Linux source code).

v4l2_async_register_subdev -> v4l2_async_match_notify -> v4l2_device_register_subdev -> v4l2_ctrl_add_handler

The last function (v4l2_ctrl_add_handler) goes through and copies V4L2 controls from one handler to another.

Therefore, if the V4L2 control is not added before v4l2_async_register_subdev is called, then the control will not be copied to the different devices and will therefore not be a valid option available.

So in summation from what I found, no it is not possible to add V4L2 controls after the device has been registered.

1
kakemixen On

This might come a bit late, since you already have marked a solution, but I believe I have a solution that can help. I'm gonna do my best to explain how I went about adding custom controls to the tegracamv2 framework.

You unfortunately cannot add controls after the subdevice is registered by v4l2_async_register_subdev, you can, however, hook into the async framework using the registered callback defined in v4l2sd_internal_ops field of the tc_dev struct. This allows you to define your own control handler and then add it to the control handler from the tegracam framework, which will then be added to the v4l2 device.

I recently struggled with this and I found this to be my only solution apart from patching out the call to v4l2_async_register_subdev in the tegracam framework and calling it manually after adding controls (this is untested).

The related code (This assumed an array of ctrl_config, but showcases the idea. I also assume you have defined ctrl_ops and configs.):

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,
};

In the probe function you then include the following before tegracam_device_register. (But it won't be called before tegracam_v4l2subdev_register.)

tc_dev->sensor_ops = &my_subdev_internal_ops;