2.15. V4L2 控制

2.15.1. 简介

V4L2 控制 API 看起来足够简单,但很快就变得很难在驱动程序中正确实现。 但是,处理控件所需的大部分代码实际上并非特定于驱动程序,可以移动到 V4L 核心框架。

毕竟,驱动程序开发人员唯一感兴趣的部分是

  1. 如何添加控件?

  2. 如何设置控件的值?(即 s_ctrl)

偶尔

  1. 如何获取控件的值?(即 g_volatile_ctrl)

  2. 如何验证用户建议的控件值?(即 try_ctrl)

其余部分是可以在中心完成的事情。

创建控制框架是为了在中心位置实现有关控件的 V4L2 规范的所有规则。 并使驱动程序开发人员的生活尽可能轻松。

请注意,控制框架依赖于 V4L2 驱动程序的 v4l2_device 结构和子设备驱动程序的 struct v4l2_subdev 结构。

2.15.2. 框架中的对象

有两个主要对象

v4l2_ctrl 对象描述控件属性并跟踪控件的值(当前值和建议的新值)。

v4l2_ctrl_handler 是跟踪控件的对象。 它维护一个它拥有的 v4l2_ctrl 对象列表和另一个对控件的引用列表,可能指向其他处理程序拥有的控件。

2.15.3. V4L2 和子设备驱动程序的基本用法

  1. 准备驱动程序

#include <media/v4l2-ctrls.h>

1.1) 将处理程序添加到驱动程序的顶层结构

对于 V4L2 驱动程序

struct foo_dev {
        ...
        struct v4l2_device v4l2_dev;
        ...
        struct v4l2_ctrl_handler ctrl_handler;
        ...
};

对于子设备驱动程序

struct foo_dev {
        ...
        struct v4l2_subdev sd;
        ...
        struct v4l2_ctrl_handler ctrl_handler;
        ...
};

1.2) 初始化处理程序

v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);

第二个参数是一个提示,告诉函数该处理程序预计处理多少个控件。 它将基于此信息分配一个哈希表。 这只是一个提示。

1.3) 将控制处理程序挂接到驱动程序中

对于 V4L2 驱动程序

foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;

对于子设备驱动程序

foo->sd.ctrl_handler = &foo->ctrl_handler;

1.4) 最后清理处理程序

v4l2_ctrl_handler_free(&foo->ctrl_handler);
  1. 添加控件

通过调用 v4l2_ctrl_new_std() 添加非菜单控件

struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
                const struct v4l2_ctrl_ops *ops,
                u32 id, s32 min, s32 max, u32 step, s32 def);

通过调用 v4l2_ctrl_new_std_menu() 添加菜单和整数菜单控件

struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
                const struct v4l2_ctrl_ops *ops,
                u32 id, s32 max, s32 skip_mask, s32 def);

通过调用 v4l2_ctrl_new_std_menu_items() 添加具有驱动程序特定菜单的菜单控件

struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(
                struct v4l2_ctrl_handler *hdl,
                const struct v4l2_ctrl_ops *ops, u32 id, s32 max,
                s32 skip_mask, s32 def, const char * const *qmenu);

通过调用 v4l2_ctrl_new_std_compound() 添加标准复合控件

struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
                const struct v4l2_ctrl_ops *ops, u32 id,
                const union v4l2_ctrl_ptr p_def);

通过调用 v4l2_ctrl_new_int_menu() 添加具有驱动程序特定菜单的整数菜单控件

struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
                const struct v4l2_ctrl_ops *ops,
                u32 id, s32 max, s32 def, const s64 *qmenu_int);

这些函数通常在 v4l2_ctrl_handler_init() 之后立即调用

static const s64 exp_bias_qmenu[] = {
       -2, -1, 0, 1, 2
};
static const char * const test_pattern[] = {
        "Disabled",
        "Vertical Bars",
        "Solid Black",
        "Solid White",
};

v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
                V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
                V4L2_CID_CONTRAST, 0, 255, 1, 128);
v4l2_ctrl_new_std_menu(&foo->ctrl_handler, &foo_ctrl_ops,
                V4L2_CID_POWER_LINE_FREQUENCY,
                V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
                V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
v4l2_ctrl_new_int_menu(&foo->ctrl_handler, &foo_ctrl_ops,
                V4L2_CID_EXPOSURE_BIAS,
                ARRAY_SIZE(exp_bias_qmenu) - 1,
                ARRAY_SIZE(exp_bias_qmenu) / 2 - 1,
                exp_bias_qmenu);
v4l2_ctrl_new_std_menu_items(&foo->ctrl_handler, &foo_ctrl_ops,
                V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0,
                0, test_pattern);
...
if (foo->ctrl_handler.error) {
        int err = foo->ctrl_handler.error;

        v4l2_ctrl_handler_free(&foo->ctrl_handler);
        return err;
}

v4l2_ctrl_new_std() 函数返回指向新控件的 v4l2_ctrl 指针,但是如果不需要在控件操作之外访问该指针,则无需存储它。

v4l2_ctrl_new_std() 函数将根据控件 ID 填充大多数字段,但最小值、最大值、步长和默认值除外。 这些在最后四个参数中传递。 这些值是特定于驱动程序的,而诸如类型、名称、标志之类的控件属性都是全局的。 控件的当前值将设置为默认值。

v4l2_ctrl_new_std_menu() 函数非常相似,但用于菜单控件。 没有最小参数,因为对于菜单控件,该参数始终为 0,并且没有步长,而是有一个 skip_mask 参数:如果位 X 为 1,则跳过菜单项 X。

v4l2_ctrl_new_int_menu() 函数创建一个新的标准整数菜单控件,其中菜单中包含驱动程序特定的项目。 它与 v4l2_ctrl_new_std_menu 的不同之处在于它没有掩码参数,而是将一个有符号的 64 位整数数组作为最后一个参数,该数组构成一个精确的菜单项列表。

v4l2_ctrl_new_std_menu_items() 函数与 v4l2_ctrl_new_std_menu 非常相似,但是采用了一个额外的参数 qmenu,该参数是用于其他标准菜单控件的驱动程序特定菜单。 此控件的一个很好的例子是捕获/显示/传感器设备的测试模式控件,这些设备具有生成测试模式的功能。 这些测试模式是硬件特定的,因此菜单的内容会因设备而异。

请注意,如果发生错误,该函数将返回 NULL 或错误,并将 ctrl_handler->error 设置为错误代码。 如果已经设置了 ctrl_handler->error,那么它将只返回而不执行任何操作。 如果无法分配内部数据结构,则 v4l2_ctrl_handler_init 也是如此。

这使得初始化处理程序并添加所有控件,最后只检查错误代码变得很容易。 节省了很多重复的错误检查。

建议以升序控件 ID 添加控件:这样会更快一些。

  1. 可选地强制初始控件设置

v4l2_ctrl_handler_setup(&foo->ctrl_handler);

这将无条件地为所有控件调用 s_ctrl。 实际上,这会将硬件初始化为默认的控件值。 建议您这样做,因为这可以确保内部数据结构和硬件同步。

  1. 最后:实现 v4l2_ctrl_ops

static const struct v4l2_ctrl_ops foo_ctrl_ops = {
        .s_ctrl = foo_s_ctrl,
};

通常,您只需要 s_ctrl

static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
{
        struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);

        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                write_reg(0x123, ctrl->val);
                break;
        case V4L2_CID_CONTRAST:
                write_reg(0x456, ctrl->val);
                break;
        }
        return 0;
}

使用 v4l2_ctrl 指针作为参数调用控制操作。 新的控件值已经过验证,因此您所需要做的就是实际更新硬件寄存器。

您完成了! 这对于我们拥有的大多数驱动程序来说已经足够了。 无需对控件值进行任何验证,或实现 QUERYCTRL、QUERY_EXT_CTRL 和 QUERYMENU。 并且会自动支持 G/S_CTRL 以及 G/TRY/S_EXT_CTRLS。

注意

其余部分讨论了更高级的控制主题和场景。 实际上,如上所述的基本用法对于大多数驱动程序来说已经足够了。

2.15.4. 继承子设备控件

当子设备通过调用 v4l2_device_register_subdev() 注册到 V4L2 驱动程序,并且 v4l2_subdev 和 v4l2_device 的 ctrl_handler 字段都被设置时,子设备的控件也会自动在 V4L2 驱动程序中可用。如果子设备驱动程序包含 V4L2 驱动程序中已存在的控件,则这些控件将被跳过(因此 V4L2 驱动程序始终可以覆盖子设备控件)。

这里发生的是,v4l2_device_register_subdev() 调用 v4l2_ctrl_add_handler() 将子设备的控件添加到 v4l2_device 的控件中。

2.15.5. 访问控制值

以下联合体在控制框架内部用于访问控制值

union v4l2_ctrl_ptr {
        s32 *p_s32;
        s64 *p_s64;
        char *p_char;
        void *p;
};

v4l2_ctrl 结构包含以下字段,可用于访问当前值和新值

s32 val;
struct {
        s32 val;
} cur;


union v4l2_ctrl_ptr p_new;
union v4l2_ctrl_ptr p_cur;

如果控件具有简单的 s32 类型,则

&ctrl->val == ctrl->p_new.p_s32
&ctrl->cur.val == ctrl->p_cur.p_s32

对于所有其他类型,请使用 ctrl->p_cur.p。基本上,val 和 cur.val 字段可以被认为是别名,因为它们经常被使用。

在控制操作中,你可以自由使用这些。val 和 cur.val 的含义是不言自明的。p_char 指针指向长度为 ctrl->maximum + 1 的字符缓冲区,并且始终以 0 结尾。

除非控件被标记为易失性,否则 p_cur 字段指向当前缓存的控制值。当你创建一个新控件时,此值与默认值相同。调用 v4l2_ctrl_handler_setup() 后,此值将传递给硬件。通常最好调用此函数。

每当设置新值时,新值会自动缓存。这意味着大多数驱动程序不需要实现 g_volatile_ctrl() 操作。例外情况是返回易失性寄存器的控件,例如持续变化的信号强度读数。在这种情况下,你需要像这样实现 g_volatile_ctrl

static int foo_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                ctrl->val = read_reg(0x123);
                break;
        }
}

请注意,你也在 g_volatile_ctrl 中使用“新值”联合体。一般来说,需要实现 g_volatile_ctrl 的控件是只读控件。如果它们不是只读的,则当控件更改时不会生成 V4L2_EVENT_CTRL_CH_VALUE。

要将控件标记为易失性,你必须设置 V4L2_CTRL_FLAG_VOLATILE

ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
if (ctrl)
        ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;

对于 try/s_ctrl,新值(即用户传递的值)会被填充,你可以在 try_ctrl 中修改它们,或者在 s_ctrl 中设置它们。“cur”联合体包含当前值,你也可以使用它(但不能更改!)。

如果 s_ctrl 返回 0 (OK),则控制框架会将新的最终值复制到“cur”联合体。

在 g_volatile/s/try_ctrl 中,你可以访问同一处理程序拥有的所有控件的值,因为处理程序的锁已被持有。如果你需要访问其他处理程序拥有的控件的值,则必须非常小心,不要引入死锁。

在控制操作之外,你必须通过辅助函数在驱动程序中安全地获取或设置单个控件值

s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);

这些函数通过控制框架,就像 VIDIOC_G/S_CTRL ioctl 一样。但是,不要在控制操作 g_volatile/s/try_ctrl 中使用这些,因为这些辅助函数也会锁定处理程序,这将导致死锁。

你也可以自己获取处理程序锁

mutex_lock(&state->ctrl_handler.lock);
pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
pr_info("Integer value is '%s'\n", ctrl2->cur.val);
mutex_unlock(&state->ctrl_handler.lock);

2.15.7. 自定义控件

可以使用 v4l2_ctrl_new_custom() 创建驱动程序特定的控件

static const struct v4l2_ctrl_config ctrl_filter = {
        .ops = &ctrl_custom_ops,
        .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
        .name = "Spatial Filter",
        .type = V4L2_CTRL_TYPE_INTEGER,
        .flags = V4L2_CTRL_FLAG_SLIDER,
        .max = 15,
        .step = 1,
};

ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_filter, NULL);

最后一个参数是 priv 指针,可以将其设置为驱动程序特定的私有数据。

v4l2_ctrl_config 结构还有一个字段用于设置 is_private 标志。

如果未设置 name 字段,则框架将假定这是一个标准控件,并相应地填充 name、type 和 flags 字段。

2.15.8. 活动和抓取的控件

如果控件之间存在更复杂的关系,则可能需要激活和停用控件。例如,如果 Chroma AGC 控件处于开启状态,则 Chroma Gain 控件处于非活动状态。也就是说,你可以设置它,但只要自动增益控制处于开启状态,硬件就不会使用该值。通常,用户界面可以禁用此类输入字段。

你可以使用 v4l2_ctrl_activate() 设置“活动”状态。默认情况下,所有控件都是活动的。请注意,框架不会检查此标志。它仅用于 GUI。该函数通常在 s_ctrl 中调用。

另一个标志是“抓取”标志。抓取的控件意味着你无法更改它,因为它正在被某些资源使用。典型的例子是 MPEG 比特率控件,在捕获进行时无法更改。

如果使用 v4l2_ctrl_grab() 将控件设置为“抓取”,则如果尝试设置此控件,框架将返回 -EBUSY。v4l2_ctrl_grab() 函数通常在驱动程序启动或停止流式传输时调用。

2.15.9. 控件集群

默认情况下,所有控件都是彼此独立的。但是在更复杂的场景中,你可能会得到从一个控件到另一个控件的依赖关系。在这种情况下,你需要“集群”它们

struct foo {
        struct v4l2_ctrl_handler ctrl_handler;
#define AUDIO_CL_VOLUME (0)
#define AUDIO_CL_MUTE   (1)
        struct v4l2_ctrl *audio_cluster[2];
        ...
};

state->audio_cluster[AUDIO_CL_VOLUME] =
        v4l2_ctrl_new_std(&state->ctrl_handler, ...);
state->audio_cluster[AUDIO_CL_MUTE] =
        v4l2_ctrl_new_std(&state->ctrl_handler, ...);
v4l2_ctrl_cluster(ARRAY_SIZE(state->audio_cluster), state->audio_cluster);

从现在开始,每当设置(或“获取”或“尝试”)属于同一集群的一个或多个控件时,只会调用第一个控件(本例中为“volume”)的控件操作。你实际上创建了一个新的复合控件。类似于 C 中“struct”的工作方式。

因此,当以 V4L2_CID_AUDIO_VOLUME 作为参数调用 s_ctrl 时,你应该设置属于 audio_cluster 的所有两个控件

static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
{
        struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);

        switch (ctrl->id) {
        case V4L2_CID_AUDIO_VOLUME: {
                struct v4l2_ctrl *mute = ctrl->cluster[AUDIO_CL_MUTE];

                write_reg(0x123, mute->val ? 0 : ctrl->val);
                break;
        }
        case V4L2_CID_CONTRAST:
                write_reg(0x456, ctrl->val);
                break;
        }
        return 0;
}

在上面的示例中,以下对于 VOLUME 情况是等效的

ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME]
ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]

实际上,像这样使用集群数组会变得非常繁琐。因此,可以使用以下等效方法

struct {
        /* audio cluster */
        struct v4l2_ctrl *volume;
        struct v4l2_ctrl *mute;
};

匿名结构用于清楚地“集群”这两个控件指针,但它没有其他用途。效果与创建包含两个控件指针的数组相同。所以你可以直接这样做

state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
v4l2_ctrl_cluster(2, &state->volume);

在 foo_s_ctrl 中,你可以直接使用这些指针:state->mute->val。

请注意,集群中的控件可能为 NULL。例如,如果由于某种原因从未添加静音(因为硬件不支持该特定功能),则静音将为 NULL。因此,在这种情况下,我们有一个包含 2 个控件的集群,其中实际上只实例化了 1 个。唯一的限制是集群的第一个控件必须始终存在,因为它是集群的“主”控件。主控件是标识集群并提供用于该集群的 v4l2_ctrl_ops 结构指针的控件。

显然,集群数组中的所有控件都必须初始化为有效的控件或 NULL。

在极少数情况下,你可能想知道用户实际明确设置了集群中的哪些控件。为此,你可以检查每个控件的“is_new”标志。例如,在音量/静音集群的情况下,如果用户仅为静音调用 VIDIOC_S_CTRL,则静音控件的“is_new”标志将被设置。如果用户为静音和音量控件调用 VIDIOC_S_EXT_CTRLS,则两个控件的“is_new”标志都将为 1。

v4l2_ctrl_handler_setup() 调用时,“is_new”标志始终为 1。

2.15.10. 使用自动集群处理自动增益/增益类型控件

一种常见的控件集群类型是处理“auto-foo/foo”类型控件的集群。典型的例子是自动增益/增益、自动曝光/曝光、自动白平衡/红色平衡/蓝色平衡。在所有情况下,你都有一个控件来确定另一个控件是由硬件自动处理,还是由用户手动控制。

如果集群处于自动模式,则手动控件应标记为非活动状态和易失性。读取易失性控件时,g_volatile_ctrl 操作应返回硬件自动模式自动设置的值。

如果将集群置于手动模式,则手动控件应再次变为活动状态,并且清除易失性标志(因此,在手动模式下不再调用 g_volatile_ctrl)。此外,在切换到手动模式之前,将由自动模式确定的当前值复制为新的手动值。

最后,应为自动控件设置 V4L2_CTRL_FLAG_UPDATE,因为更改该控件会影响手动控件的控件标志。

为了简化此操作,引入了 v4l2_ctrl_cluster 的特殊变体

void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
                            u8 manual_val, bool set_volatile);

前两个参数与 v4l2_ctrl_cluster 相同。第三个参数告诉框架哪个值将集群切换到手动模式。最后一个参数将可选地为非自动控制设置 V4L2_CTRL_FLAG_VOLATILE 标志。如果它为 false,则手动控制永远不是易失的。如果硬件不提供读取自动模式确定的值的选项(例如,如果自动增益开启,硬件不允许您获取当前的增益值),则通常会使用该选项。

集群的第一个控件被认为是“自动”控件。

使用此函数将确保您无需处理所有复杂的标志和易失性处理。

2.15.11. VIDIOC_LOG_STATUS 支持

此 ioctl 允许您将驱动程序的当前状态转储到内核日志。 v4l2_ctrl_handler_log_status(ctrl_handler, prefix) 可用于将给定处理程序拥有的控件的值转储到日志。您也可以提供前缀。如果前缀没有以空格结尾,则将为您添加“: ”。

2.15.12. 不同视频节点的不同处理程序

通常,V4L2 驱动程序只有一个全局用于所有视频节点的控件处理程序。但是,您也可以为不同的视频节点指定不同的控件处理程序。您可以通过手动设置 struct video_device 的 ctrl_handler 字段来实现。

如果没有涉及子设备,那没有问题,但是如果涉及子设备,则需要阻止子设备控件自动合并到全局控件处理程序。您只需将 struct v4l2_device 中的 ctrl_handler 字段设置为 NULL 即可。现在,v4l2_device_register_subdev() 将不再合并子设备控件。

添加每个子设备后,您必须手动调用 v4l2_ctrl_add_handler,将子设备的控件处理程序 (sd->ctrl_handler) 添加到所需的控件处理程序。此控件处理程序可能是特定于 video_device 的,也可能是特定于 video_device 子集的。例如:无线电设备节点只有音频控件,而视频和 VBI 设备节点共享用于音频和视频控件的相同控件处理程序。

如果希望一个处理程序(例如,用于无线电设备节点)具有另一个处理程序(例如,用于视频设备节点)的子集,则应首先将控件添加到第一个处理程序,将其他控件添加到第二个处理程序,最后将第一个处理程序添加到第二个处理程序。例如

v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_VOLUME, ...);
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...);
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_CONTRAST, ...);
v4l2_ctrl_add_handler(&video_ctrl_handler, &radio_ctrl_handler, NULL);

v4l2_ctrl_add_handler() 的最后一个参数是一个过滤器函数,允许您过滤将添加哪些控件。如果您想添加所有控件,请将其设置为 NULL。

或者您可以将特定控件添加到处理程序

volume = v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_AUDIO_VOLUME, ...);
v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_BRIGHTNESS, ...);
v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_CONTRAST, ...);

您不应该做的是为两个处理程序创建两个相同的控件。例如

v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...);
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_AUDIO_MUTE, ...);

这样做会很糟糕,因为使无线电静音不会更改视频静音控件。规则是为每个可以扭动的硬件“旋钮”设置一个控件。

2.15.13. 查找控件

通常,您自己创建了控件,并且可以将 struct v4l2_ctrl 指针存储到您自己的结构中。

但是,有时您需要从您不拥有的另一个处理程序中查找控件。例如,如果您必须从子设备查找音量控制。

您可以通过调用 v4l2_ctrl_find 来实现

struct v4l2_ctrl *volume;

volume = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_AUDIO_VOLUME);

由于 v4l2_ctrl_find 将锁定处理程序,因此您必须小心使用它的位置。例如,这不是一个好主意

struct v4l2_ctrl_handler ctrl_handler;

v4l2_ctrl_new_std(&ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
v4l2_ctrl_new_std(&ctrl_handler, &video_ops, V4L2_CID_CONTRAST, ...);

...并在 video_ops.s_ctrl 中

case V4L2_CID_BRIGHTNESS:
        contrast = v4l2_find_ctrl(&ctrl_handler, V4L2_CID_CONTRAST);
        ...

当框架调用 s_ctrl 时,ctrl_handler.lock 已被获取,因此尝试从同一处理程序中查找另一个控件将导致死锁。

建议不要从控件操作内部使用此函数。

2.15.14. 防止控件继承

当使用 v4l2_ctrl_add_handler 将一个控件处理程序添加到另一个控件处理程序时,默认情况下,一个控件处理程序中的所有控件都将合并到另一个控件处理程序中。但是,子设备可能具有对于某些高级嵌入式系统有意义的低级控件,但在消费级硬件中使用时则不然。在这种情况下,您希望将这些低级控件保留在子设备本地。您只需将控件的 “is_private” 标志设置为 1 即可实现此目的

static const struct v4l2_ctrl_config ctrl_private = {
        .ops = &ctrl_custom_ops,
        .id = V4L2_CID_...,
        .name = "Some Private Control",
        .type = V4L2_CTRL_TYPE_INTEGER,
        .max = 15,
        .step = 1,
        .is_private = 1,
};

ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_private, NULL);

当调用 v4l2_ctrl_add_handler 时,将跳过这些控件。

2.15.15. V4L2_CTRL_TYPE_CTRL_CLASS 控件

GUI 可以使用此类型的控件来获取控件类的名称。功能齐全的 GUI 可以创建一个具有多个选项卡的对话框,每个选项卡包含属于特定控件类的控件。可以通过查询 ID 为 <控件类 | 1> 的特殊控件来查找每个选项卡的名称。

驱动程序不必关心这一点。每当添加属于新控件类的第一个控件时,框架都会自动添加此类型的控件。

2.15.16. 添加通知回调

有时,当子设备驱动程序的控件发生更改时,平台或桥接驱动程序需要收到通知。您可以通过调用此函数来设置通知回调

void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl,
        void (*notify)(struct v4l2_ctrl *ctrl, void *priv), void *priv);

每当给定控件的值发生更改时,将调用通知回调,并传入一个指向该控件的指针和使用 v4l2_ctrl_notify 传递的 priv 指针。请注意,调用通知函数时会保持控件的处理程序锁。

每个控件处理程序只能有一个通知函数。任何尝试设置另一个通知函数的尝试都将导致 WARN_ON。

2.15.17. v4l2_ctrl 函数和数据结构

union v4l2_ctrl_ptr

指向控件值的指针。

定义:

union v4l2_ctrl_ptr {
    s32 *p_s32;
    s64 *p_s64;
    u8 *p_u8;
    u16 *p_u16;
    u32 *p_u32;
    char *p_char;
    struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence;
    struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture;
    struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quantisation;
    struct v4l2_ctrl_fwht_params *p_fwht_params;
    struct v4l2_ctrl_h264_sps *p_h264_sps;
    struct v4l2_ctrl_h264_pps *p_h264_pps;
    struct v4l2_ctrl_h264_scaling_matrix *p_h264_scaling_matrix;
    struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
    struct v4l2_ctrl_h264_decode_params *p_h264_decode_params;
    struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
    struct v4l2_ctrl_vp8_frame *p_vp8_frame;
    struct v4l2_ctrl_hevc_sps *p_hevc_sps;
    struct v4l2_ctrl_hevc_pps *p_hevc_pps;
    struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
    struct v4l2_ctrl_vp9_compressed_hdr *p_vp9_compressed_hdr_probs;
    struct v4l2_ctrl_vp9_frame *p_vp9_frame;
    struct v4l2_ctrl_hdr10_cll_info *p_hdr10_cll;
    struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
    struct v4l2_area *p_area;
    struct v4l2_ctrl_av1_sequence *p_av1_sequence;
    struct v4l2_ctrl_av1_tile_group_entry *p_av1_tile_group_entry;
    struct v4l2_ctrl_av1_frame *p_av1_frame;
    struct v4l2_ctrl_av1_film_grain *p_av1_film_grain;
    void *p;
    const void *p_const;
};

成员

p_s32

指向 32 位有符号值的指针。

p_s64

指向 64 位有符号值的指针。

p_u8

指向 8 位无符号值的指针。

p_u16

指向 16 位无符号值的指针。

p_u32

指向 32 位无符号值的指针。

p_char

指向字符串的指针。

p_mpeg2_sequence

指向 MPEG2 序列结构的指针。

p_mpeg2_picture

指向 MPEG2 图片结构的指针。

p_mpeg2_quantisation

指向 MPEG2 量化数据结构的指针。

p_fwht_params

指向 FWHT 无状态参数结构的指针。

p_h264_sps

指向 struct v4l2_ctrl_h264_sps 的指针。

p_h264_pps

指向 struct v4l2_ctrl_h264_pps 的指针。

p_h264_scaling_matrix

指向 struct v4l2_ctrl_h264_scaling_matrix 的指针。

p_h264_slice_params

指向 struct v4l2_ctrl_h264_slice_params 的指针。

p_h264_decode_params

指向 struct v4l2_ctrl_h264_decode_params 的指针。

p_h264_pred_weights

指向 struct v4l2_ctrl_h264_pred_weights 的指针。

p_vp8_frame

指向 VP8 帧参数结构的指针。

p_hevc_sps

指向 HEVC 序列参数集结构的指针。

p_hevc_pps

指向 HEVC 图片参数集结构的指针。

p_hevc_slice_params

指向 HEVC 切片参数结构的指针。

p_vp9_compressed_hdr_probs

指向 VP9 帧压缩头概率结构的指针。

p_vp9_frame

指向 VP9 帧参数结构的指针。

p_hdr10_cll

指向 HDR10 内容亮度级别结构的指针。

p_hdr10_mastering

指向 HDR10 母版显示结构的指针。

p_area

指向区域的指针。

p_av1_sequence

指向 AV1 序列结构的指针。

p_av1_tile_group_entry

指向 AV1 图块组条目结构的指针。

p_av1_frame

指向 AV1 帧结构的指针。

p_av1_film_grain

指向 AV1 胶片颗粒结构的指针。

p

指向复合值的指针。

p_const

指向常量复合值的指针。

union v4l2_ctrl_ptr v4l2_ctrl_ptr_create(void *ptr)

从 void 指针返回 v4l2_ctrl_ptr 的辅助函数

参数

void *ptr

void 指针

struct v4l2_ctrl_ops

驱动程序必须提供的控件操作。

定义:

struct v4l2_ctrl_ops {
    int (*g_volatile_ctrl)(struct v4l2_ctrl *ctrl);
    int (*try_ctrl)(struct v4l2_ctrl *ctrl);
    int (*s_ctrl)(struct v4l2_ctrl *ctrl);
};

成员

g_volatile_ctrl

获取此控件的新值。通常仅与易失性(且通常是只读的)控件相关,例如返回不断变化的当前信号强度的控件。如果未设置,则将返回当前缓存的值。

try_ctrl

测试控件的值是否有效。仅当通常的最小/最大/步长检查不足时才相关。

s_ctrl

实际设置新的控件值。 s_ctrl 是强制性的。调用这些操作时,会持有 ctrl->handler->lock,因此没有其他人可以访问该处理程序拥有的控件。

struct v4l2_ctrl_type_ops

驱动程序必须提供的控件类型操作。

定义:

struct v4l2_ctrl_type_ops {
    bool (*equal)(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr1, union v4l2_ctrl_ptr ptr2);
    void (*init)(const struct v4l2_ctrl *ctrl, u32 from_idx, union v4l2_ctrl_ptr ptr);
    void (*log)(const struct v4l2_ctrl *ctrl);
    int (*validate)(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr);
};

成员

equal

如果所有 ctrl->elems 数组元素相等,则返回 true。

init

从 from_idx 到 ctrl->elems 初始化数组元素的值。

log

记录值。

validate

验证 ctrl->new_elems 数组元素的值。成功时返回 0,否则返回负值。

v4l2_ctrl_notify_fnc

Typedef:用于通知参数的 typedef,当控件值发生更改时应调用该函数。

语法

void v4l2_ctrl_notify_fnc (struct v4l2_ctrl *ctrl, void *priv)

参数

struct v4l2_ctrl *ctrl

指向 v4l2_ctrl 结构的指针

void *priv

控件私有数据

描述

此 typedef 定义用作 v4l2_ctrl_notify() 的参数,并用作 v4l2_ctrl_handler 结构体的参数。

struct v4l2_ctrl

控件结构。

定义:

struct v4l2_ctrl {
    struct list_head node;
    struct list_head ev_subs;
    struct v4l2_ctrl_handler *handler;
    struct v4l2_ctrl **cluster;
    unsigned int ncontrols;
    unsigned int done:1;
    unsigned int is_new:1;
    unsigned int has_changed:1;
    unsigned int is_private:1;
    unsigned int is_auto:1;
    unsigned int is_int:1;
    unsigned int is_string:1;
    unsigned int is_ptr:1;
    unsigned int is_array:1;
    unsigned int is_dyn_array:1;
    unsigned int has_volatiles:1;
    unsigned int call_notify:1;
    unsigned int manual_mode_value:8;
    const struct v4l2_ctrl_ops *ops;
    const struct v4l2_ctrl_type_ops *type_ops;
    u32 id;
    const char *name;
    enum v4l2_ctrl_type type;
    s64 minimum, maximum, default_value;
    u32 elems;
    u32 elem_size;
    u32 new_elems;
    u32 dims[V4L2_CTRL_MAX_DIMS];
    u32 nr_of_dims;
    union {
        u64 step;
        u64 menu_skip_mask;
    };
    union {
        const char * const *qmenu;
        const s64 *qmenu_int;
    };
    unsigned long flags;
    void *priv;
    void *p_array;
    u32 p_array_alloc_elems;
    s32 val;
    struct {
        s32 val;
    } cur;
    union v4l2_ctrl_ptr p_def;
    union v4l2_ctrl_ptr p_new;
    union v4l2_ctrl_ptr p_cur;
};

成员

node

列表节点。

ev_subs

控件事件订阅列表。

handler

拥有该控件的处理程序。

cluster

指向群组数组的开始位置。

ncontrols

群组数组中控件的数量。

done

内部标志:为每个已处理的控件设置。

is_new

当用户为此控件指定新值时设置。当从 v4l2_ctrl_handler_setup() 调用时也会设置。驱动程序不应设置此标志。

has_changed

当当前值与新值不同时设置。驱动程序不应使用此标志。

is_private

如果设置,则此控件是其处理程序私有的,不会添加到任何其他处理程序。驱动程序可以设置此标志。

is_auto

如果设置,则此控件选择其他群组成员是处于“自动”模式还是“手动”模式。这用于自动增益/增益类型的群组。驱动程序不应直接设置此标志。

is_int

如果设置,则此控件具有简单的整数值(即,它使用 ctrl->val)。

is_string

如果设置,则此控件的类型为 V4L2_CTRL_TYPE_STRING

is_ptr

如果设置,则此控件是一个数组,并且/或类型 >= V4L2_CTRL_COMPOUND_TYPES,并且/或类型为 V4L2_CTRL_TYPE_STRING。换句话说,struct v4l2_ext_control 使用字段 p 指向数据。

is_array

如果设置,则此控件包含 N 维数组。

is_dyn_array

如果设置,则此控件包含动态大小的一维数组。如果设置了此标志,则还会设置 is_array

has_volatiles

如果设置,则群组的一个或多个成员是易变的。驱动程序不应修改此标志。

call_notify

如果设置,则只要控件的值发生更改,就调用处理程序的通知函数。

manual_mode_value

如果设置了 is_auto 标志,则此值是 auto 控件的值,它确定该控件是否处于手动模式。因此,如果 auto 控件的值等于此值,则整个群组处于手动模式。驱动程序不应直接设置此标志。

ops

控件操作。

type_ops

控件类型操作。

id

控件 ID。

name

控件名称。

type

控件类型。

minimum

控件的最小值。

maximum

控件的最大值。

default_value

控件的默认值。

elems

N 维数组中元素的数量。

elem_size

控件的大小(以字节为单位)。

new_elems

p_new 中元素的数量。这与 elems 相同,但动态数组除外。在这种情况下,它在 1 到 p_array_alloc_elems 的范围内。

dims

每个维度的大小。

nr_of_dims

dims 中的维度数。

{unnamed_union}

匿名

step

非菜单控件的控件步长值。

menu_skip_mask

菜单控件的控件跳过掩码。这使得跳过无效的菜单项变得容易。如果设置了位 X,则会跳过菜单项 X。当然,这仅适用于菜单项 <= 32 的菜单。没有接近该数量的菜单,所以这没问题。如果我们将来需要更多,那么必须将其扩展到 u64 或位数组。

{unnamed_union}

匿名

qmenu

所有菜单项的 const char * 数组。为空字符串 (“”) 的数组条目对应于不存在的菜单项(这是除了上面的 menu_skip_mask 之外)。最后一个条目必须为 NULL。仅当 typeV4L2_CTRL_TYPE_MENU 时使用。

qmenu_int

一个用于存储整数菜单项的 64 位整数数组。数组大小必须等于菜单大小,例如: ceil(\frac{maximum - minimum}{step}) + 1。仅当 typeV4L2_CTRL_TYPE_INTEGER_MENU 时使用。

flags

控件的标志。

priv

控件的私有指针。供驱动程序使用。它不受控件框架的影响。请注意,删除控件时不会释放此指针。如果需要这样做,则可以添加一个新的内部位字段,以告知框架释放此指针。

p_array

指向已分配数组的指针。仅当 is_array 为 true 时有效。

p_array_alloc_elems

为当前值和新值分配的数组中的元素数量。因此,p_array 的实际大小为 2 * p_array_alloc_elems * elem_size。仅当 is_array 为 true 时有效。

val

控件的新 s32 值。

cur

用于存储当前值的结构。

cur.val

控件的当前值,如果 type 通过 u32 整数表示(请参阅 enum v4l2_ctrl_type)。

p_def

控件的默认值,通过联合表示,该联合提供了一种通过指针访问控件类型的标准方法(仅适用于复合控件)。

p_new

控件的新值,通过联合表示,该联合提供了一种通过指针访问控件类型的标准方法。

p_cur

控件的当前值,通过联合表示,该联合提供了一种通过指针访问控件类型的标准方法。

struct v4l2_ctrl_ref

控件引用。

定义:

struct v4l2_ctrl_ref {
    struct list_head node;
    struct v4l2_ctrl_ref *next;
    struct v4l2_ctrl *ctrl;
    struct v4l2_ctrl_helper *helper;
    bool from_other_dev;
    bool req_done;
    bool p_req_valid;
    bool p_req_array_enomem;
    u32 p_req_array_alloc_elems;
    u32 p_req_elems;
    union v4l2_ctrl_ptr p_req;
};

成员

node

已排序列表的列表节点。

next

哈希的单链表节点。

ctrl

实际的控件信息。

helper

指向 helper 结构的指针。在 v4l2-ctrl.cprepare_ext_ctrls 函数中内部使用。

from_other_dev

如果为 true,则 ctrl 是在与 struct v4l2_ctrl_handler 不同的设备中定义的。

req_done

内部标志:如果包含此控件引用的控件处理程序绑定到媒体请求,则当应用控件时会设置此标志。这可以防止两次应用具有多个控件的群组中的控件(当应用群组的第一个控件时,它们都会被应用)。

p_req_valid

如果设置,则 p_req 包含请求的控件值。

p_req_array_enomem

如果设置,则 p_req 无效,因为为数组分配空间失败。尝试读取此值将导致 ENOMEM。仅当 ctrl->is_array 为 true 时有效。

p_req_array_alloc_elems

为数组分配的元素数量。仅当 p_req_valid 和 ctrl->is_array 为 true 时有效。

p_req_elems

p_req 中元素的数量。这与 ctrl->elems 相同,但动态数组除外。在这种情况下,它在 1 到 p_req_array_alloc_elems 的范围内。仅当 p_req_valid 为 true 时有效。

p_req

如果包含此控件引用的控件处理程序绑定到媒体请求,则此指针指向在执行请求时必须应用的控件的值,或者指向请求完成时控件的值。如果 p_req_valid 为 false,则从未为此请求设置此控件,并且当应用此请求时,不会更新该控件。

描述

每个控件处理程序都有一个这些引用的列表。list_head 用于保持所有控件的按控件 ID 排序的列表,而 next 指针用于将控件链接到哈希的存储桶中。

struct v4l2_ctrl_handler

控件处理程序跟踪所有控件:包括处理程序拥有的控件和从其他处理程序继承的控件。

定义:

struct v4l2_ctrl_handler {
    struct mutex _lock;
    struct mutex *lock;
    struct list_head ctrls;
    struct list_head ctrl_refs;
    struct v4l2_ctrl_ref *cached;
    struct v4l2_ctrl_ref **buckets;
    v4l2_ctrl_notify_fnc notify;
    void *notify_priv;
    u16 nr_of_buckets;
    int error;
    bool request_is_queued;
    struct list_head requests;
    struct list_head requests_queued;
    struct media_request_object req_obj;
};

成员

_lock

“lock” 的默认值。

lock

用于控制对此处理程序及其控件的访问的锁。可以在初始化后立即由用户替换。

ctrls

此处理程序拥有的控件列表。

ctrl_refs

控件引用列表。

cached

上次找到的控件引用。通常需要多次使用相同的控件,因此这是一种简单的优化。

buckets

哈希的存储桶。允许快速查找控件。

notify

每当控件值更改时调用的通知回调。请注意,调用通知函数时会持有处理程序的锁!

notify_priv

作为参数传递给 v4l2_ctrl 通知回调。

nr_of_buckets

数组中的存储桶总数。

error

第一次控件添加失败的错误代码。

request_is_queued

如果请求已排队,则为 True。

requests

用于跟踪打开的控件处理程序请求对象的列表。对于父控件处理程序(req_obj.ops == NULL),这是列表头。当删除父控件处理程序时,它必须取消绑定并放置所有这些请求,因为它们引用父控件处理程序。

requests_queued

已排队请求的列表。这确定了应用这些控件的顺序。请求完成后,会将其从此列表中删除。

req_obj

struct media_request_object,用于链接到 struct media_request。此请求对象有一个引用计数。

struct v4l2_ctrl_config

控件配置结构。

定义:

struct v4l2_ctrl_config {
    const struct v4l2_ctrl_ops *ops;
    const struct v4l2_ctrl_type_ops *type_ops;
    u32 id;
    const char *name;
    enum v4l2_ctrl_type type;
    s64 min;
    s64 max;
    u64 step;
    s64 def;
    union v4l2_ctrl_ptr p_def;
    u32 dims[V4L2_CTRL_MAX_DIMS];
    u32 elem_size;
    u32 flags;
    u64 menu_skip_mask;
    const char * const *qmenu;
    const s64 *qmenu_int;
    unsigned int is_private:1;
};

成员

ops

控件操作。

type_ops

控件类型操作。仅复合控件需要。

id

控件 ID。

name

控件名称。

type

控件类型。

min

控件的最小值。

max

控件的最大值。

step

非菜单控件的控件步长值。

def

控件的默认值。

p_def

复合控件的默认控制值。

dims

每个维度的大小。

elem_size

控件的大小(以字节为单位)。

flags

控件的标志。

menu_skip_mask

菜单控件的控制跳过掩码。这使得跳过无效的菜单项变得容易。如果设置了位 X,则跳过菜单项 X。当然,这仅适用于菜单项数量 <= 64 的菜单。没有菜单接近这个数量,所以这是可以的。如果我们将来需要更多,则必须将其扩展为位数组。

qmenu

所有菜单项的 const char * 数组。空字符串 (“”) 的数组条目对应于不存在的菜单项(这是对上面的 menu_skip_mask 的补充)。最后一个条目必须为 NULL。

qmenu_int

类型为 V4L2_CTRL_TYPE_INTEGER_MENU 的所有菜单项的 const s64 整数数组。

is_private

如果设置,则此控件是其处理程序的私有控件,不会添加到任何其他处理程序。

void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags)

根据控件 ID 填充控件字段。

参数

u32 id

控件的 ID

const char **name

指向字符串的指针,该字符串将填充控件的名称

enum v4l2_ctrl_type *type

用于存储控件类型的指针

s64 *min

用于存储控件最小值的指针

s64 *max

用于存储控件最大值的指针

u64 *step

用于存储控件步长的指针

s64 *def

用于存储控件默认值的指针

u32 *flags

用于存储要在控件上使用的标志的指针

描述

这适用于所有标准 V4L2 控件。对于非标准控件,它只会填充给定的参数,并且 name 内容将设置为 NULL

此函数将覆盖 nametypeflags 的内容。minmaxstepdef 的内容可能会根据类型进行修改。

注意

不要在驱动程序中使用!它仅在内部用于向后兼容的控件处理。一旦所有驱动程序都转换为使用新的控件框架,此函数将不再导出。

int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, unsigned int nr_of_controls_hint, struct lock_class_key *key, const char *name)

初始化控制处理程序。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

unsigned int nr_of_controls_hint

此处理程序预期引用的控件数量的提示。这是总数,因此包括任何继承的控件。它不必非常精确,但如果偏差太大,则要么浪费内存(分配了太多存储桶),要么控件查找速度变慢(分配的存储桶不足,因此有更多慢速列表查找)。不过,它始终有效。

struct lock_class_key *key

如果设置了 CONFIG_LOCKDEP,则由锁验证器使用。

const char *name

如果设置了 CONFIG_LOCKDEP,则由锁验证器使用。

描述

注意

永远不要直接使用此调用,始终使用 v4l2_ctrl_handler_init() 宏,该宏隐藏了 keyname 参数。

返回

如果无法分配存储桶,则返回错误。此错误也会存储在 hdl->error 中。

v4l2_ctrl_handler_init

v4l2_ctrl_handler_init (hdl, nr_of_controls_hint)

用于创建静态结构 lock_class_key 并调用 v4l2_ctrl_handler_init_class() 的辅助函数

参数

hdl

控制处理程序。

nr_of_controls_hint

此处理程序预期引用的控件数量的提示。这是总数,因此包括任何继承的控件。它不必非常精确,但如果偏差太大,则要么浪费内存(分配了太多存储桶),要么控件查找速度变慢(分配的存储桶不足,因此有更多慢速列表查找)。不过,它始终有效。

描述

此辅助函数创建一个静态结构 lock_class_key 并调用 v4l2_ctrl_handler_init_class(),为锁验证器提供适当的名称。

使用此辅助函数初始化控制处理程序。

void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)

释放处理程序拥有的所有控件并释放控件列表。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

描述

如果 hdl == NULL,则不执行任何操作。

void v4l2_ctrl_lock(struct v4l2_ctrl *ctrl)

用于锁定与控件关联的处理程序的辅助函数。

参数

struct v4l2_ctrl *ctrl

要锁定的控件。

void v4l2_ctrl_unlock(struct v4l2_ctrl *ctrl)

用于解锁与控件关联的处理程序的辅助函数。

参数

struct v4l2_ctrl *ctrl

要解锁的控件。

int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)

为属于处理程序的所有控件调用 s_ctrl 操作,以将硬件初始化为当前控件值。调用者负责代表 __v4l2_ctrl_handler_setup() 获取控制处理程序互斥锁。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

描述

按钮控件将被跳过,只读控件也是如此。

如果 hdl == NULL,则只返回 0。

int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)

为属于处理程序的所有控件调用 s_ctrl 操作,以将硬件初始化为当前控件值。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

描述

按钮控件将被跳过,只读控件也是如此。

如果 hdl == NULL,则只返回 0。

void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl, const char *prefix)

记录处理程序拥有的所有控件。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

const char *prefix

记录控制值时使用的前缀。如果前缀末尾没有空格,则会在前缀后添加“: ”。 如果 prefix == NULL,则不使用前缀。

描述

用于 VIDIOC_LOG_STATUS。

如果 hdl == NULL,则不执行任何操作。

struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_config *cfg, void *priv)

分配并初始化一个新的自定义 V4L2 控制。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

const struct v4l2_ctrl_config *cfg

控制的配置数据。

void *priv

控制的驱动程序特定私有数据。

描述

如果无法分配 v4l2_ctrl 结构,则返回 NULL,并且 hdl->error 设置为错误代码(如果尚未设置)。

struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id, s64 min, s64 max, u64 step, s64 def)

分配并初始化一个新的标准 V4L2 非菜单控件。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

const struct v4l2_ctrl_ops *ops

控件操作。

u32 id

控件 ID。

s64 min

控件的最小值。

s64 max

控件的最大值。

u64 step

控件的步长值

s64 def

控件的默认值。

描述

如果无法分配 v4l2_ctrl 结构,或者控制 ID 未知,则返回 NULL,并且 hdl->error 设置为相应的错误代码(如果尚未设置)。

如果 id 指的是菜单控件,则此函数将返回 NULL。

添加菜单控件时使用 v4l2_ctrl_new_std_menu()

struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id, u8 max, u64 mask, u8 def)

分配并初始化一个新的标准 V4L2 菜单控件。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

const struct v4l2_ctrl_ops *ops

控件操作。

u32 id

控件 ID。

u8 max

控件的最大值。

u64 mask

菜单控件的控制跳过掩码。这使得跳过无效的菜单项变得容易。如果设置了位 X,则跳过菜单项 X。当然,这仅适用于菜单项数量 <= 64 的菜单。没有菜单接近这个数量,所以这是可以的。如果我们将来需要更多,则必须将其扩展为位数组。

u8 def

控件的默认值。

描述

v4l2_ctrl_new_std() 相同,但 min 设置为 0,并且 mask 值确定要跳过哪些菜单项。

如果 id 指的是非菜单控件,则此函数将返回 NULL。

struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id, u8 max, u64 mask, u8 def, const char *const *qmenu)

使用驱动程序特定菜单创建一个新的标准 V4L2 菜单控件。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

const struct v4l2_ctrl_ops *ops

控件操作。

u32 id

控件 ID。

u8 max

控件的最大值。

u64 mask

菜单控件的控制跳过掩码。这使得跳过无效的菜单项变得容易。如果设置了位 X,则跳过菜单项 X。当然,这仅适用于菜单项数量 <= 64 的菜单。没有菜单接近这个数量,所以这是可以的。如果我们将来需要更多,则必须将其扩展为位数组。

u8 def

控件的默认值。

const char * const *qmenu

新菜单。

描述

v4l2_ctrl_new_std_menu() 相同,但 qmenu 将是此控件的驱动程序特定菜单。

struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id, const union v4l2_ctrl_ptr p_def)

分配并初始化一个新的标准 V4L2 复合控件。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

const struct v4l2_ctrl_ops *ops

控件操作。

u32 id

控件 ID。

const union v4l2_ctrl_ptr p_def

控件的默认值。

描述

v4l2_ctrl_new_std() 相同,但由于 p_def 字段,支持复合控件。 使用 v4l2_ctrl_ptr_create() 从指针创建 p_def。 如果复合控件的默认值应全部为零,则使用 v4l2_ctrl_ptr_create(NULL)。

struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id, u8 max, u8 def, const s64 *qmenu_int)

创建一个新的标准 V4L2 整数菜单控件。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

const struct v4l2_ctrl_ops *ops

控件操作。

u32 id

控件 ID。

u8 max

控件的最大值。

u8 def

控件的默认值。

const s64 *qmenu_int

控件的菜单项。

描述

v4l2_ctrl_new_std_menu() 相同,但 mask 设置为 0,并且它还接受一个整数数组作为参数,该数组确定菜单项。

如果 id 指的是非整数菜单控件,则此函数将返回 NULL

v4l2_ctrl_filter

Typedef:用于定义添加控件处理程序时要使用的过滤器函数的 Typedef。

语法

bool v4l2_ctrl_filter (const struct v4l2_ctrl *ctrl)

参数

const struct v4l2_ctrl *ctrl

指向结构体 v4l2_ctrl 的指针。

int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, struct v4l2_ctrl_handler *add, v4l2_ctrl_filter filter, bool from_other_dev)

将处理程序 add 中的所有控件添加到处理程序 hdl

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

struct v4l2_ctrl_handler *add

您想要添加到 hdl 控制处理程序的控制处理程序。

v4l2_ctrl_filter filter

此函数将过滤应添加哪些控件。

bool from_other_dev

如果为 true,则 add 中的控件是在与 hdl 不同的设备中定义的。

描述

如果两个处理程序中的任何一个是 NULL 指针,则不执行任何操作。如果 filter 为 NULL,则会添加所有控件。否则,只会添加 filter 返回 true 的那些控件。如果发生错误,hdl->error 将设置为错误代码(如果尚未设置)。

bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)

用于无线电控件的标准过滤器。

参数

const struct v4l2_ctrl *ctrl

被过滤的控件。

描述

对于任何对无线电设备节点有效的控件,这将返回 true。这些是所有 V4L2_CID_AUDIO_* 用户控件和所有 FM 发射器类控件。

此函数将与 v4l2_ctrl_add_handler() 一起使用。

void v4l2_ctrl_cluster(unsigned int ncontrols, struct v4l2_ctrl **controls)

将集群中的所有控件标记为属于该集群。

参数

unsigned int ncontrols

此集群中的控件数。

struct v4l2_ctrl **controls

大小为 ncontrols 的集群控制数组。

void v4l2_ctrl_auto_cluster(unsigned int ncontrols, struct v4l2_ctrl **controls, u8 manual_val, bool set_volatile)

将集群中的所有控件标记为属于该集群,并将其设置为自动/手动类型处理。

参数

unsigned int ncontrols

此集群中的控件数。

struct v4l2_ctrl **controls

大小为 ncontrols 的集群控制数组。第一个控件必须是“自动”控件(例如,自动增益、自动曝光等)。

u8 manual_val

集群中第一个控件的值,该值等于手动设置。

bool set_volatile

如果为 true,则除第一个自动控件外的所有控件都将是易失的。

描述

用于控件组,其中一个控件选择一些自动功能,而其他控件仅在自动功能关闭(手动模式)时才处于活动状态。典型示例:自动增益与增益,自动白平衡与红色和蓝色平衡等。

这些控件的行为如下

当自动控件设置为自动时,任何手动控件都将设置为非活动状态,并且任何读取都将调用 g_volatile_ctrl(如果该控件被标记为易失的)。

当自动控件设置为手动时,任何手动控件都将被标记为活动状态,并且任何读取都将仅返回当前值,而无需通过 g_volatile_ctrl。

此外,此函数将在自动控件上设置 V4L2_CTRL_FLAG_UPDATE 标志,如果自动控件处于自动模式,则在手动控件上设置 V4L2_CTRL_FLAG_INACTIVE 标志。

struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)

查找具有给定 ID 的控件。

参数

struct v4l2_ctrl_handler *hdl

控制处理程序。

u32 id

要查找的控件 ID。

描述

如果 hdl == NULL,则也会返回 NULL。将锁定处理程序,因此请勿从 v4l2_ctrl_ops 内部使用。

void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)

使控件处于活动状态或非活动状态。

参数

struct v4l2_ctrl *ctrl

要(取消)激活的控件。

bool active

如果控件应变为活动状态,则为 True。

描述

这将以原子方式设置或清除 V4L2_CTRL_FLAG_INACTIVE 标志。如果 ctrl == NULL,则不执行任何操作。这通常会从 s_ctrl op 中调用。之后将生成 V4L2_EVENT_CTRL 事件。

此函数假定控制处理程序已锁定。

void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)

v4l2_ctrl_grab 的解锁变体。

参数

struct v4l2_ctrl *ctrl

要(取消)激活的控件。

bool grabbed

如果控件应变为已捕获状态,则为 True。

描述

这将以原子方式设置或清除 V4L2_CTRL_FLAG_GRABBED 标志。如果 ctrl == NULL,则不执行任何操作。之后将生成 V4L2_EVENT_CTRL 事件。这通常会在驱动程序中启动或停止流式传输时调用。

此函数假定控制处理程序已由调用方锁定。

void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)

将控件标记为已捕获或未捕获。

参数

struct v4l2_ctrl *ctrl

要(取消)激活的控件。

bool grabbed

如果控件应变为已捕获状态,则为 True。

描述

这将以原子方式设置或清除 V4L2_CTRL_FLAG_GRABBED 标志。如果 ctrl == NULL,则不执行任何操作。之后将生成 V4L2_EVENT_CTRL 事件。这通常会在驱动程序中启动或停止流式传输时调用。

此函数假定控制处理程序未锁定,并且将自行获取锁。

int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, s64 min, s64 max, u64 step, s64 def)

v4l2_ctrl_modify_range() 的解锁变体

参数

struct v4l2_ctrl *ctrl

要更新的控件。

s64 min

控件的最小值。

s64 max

控件的最大值。

u64 step

控件的步长值

s64 def

控件的默认值。

描述

动态更新控件的范围。这适用于控件类型 INTEGER、BOOLEAN、MENU、INTEGER MENU 和 BITMASK。对于菜单控件,step 值被解释为 menu_skip_mask。

如果某个范围参数对于此控件类型无效,则返回错误。

调用方负责代表 __v4l2_ctrl_modify_range() 获取控制处理程序互斥锁。

int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, s64 min, s64 max, u64 step, s64 def)

更新控制的范围。

参数

struct v4l2_ctrl *ctrl

要更新的控件。

s64 min

控件的最小值。

s64 max

控件的最大值。

u64 step

控件的步长值

s64 def

控件的默认值。

描述

动态更新控件的范围。这适用于控件类型 INTEGER、BOOLEAN、MENU、INTEGER MENU 和 BITMASK。对于菜单控件,step 值被解释为 menu_skip_mask。

如果某个范围参数对于此控件类型无效,则返回错误。

此函数假定控制处理程序未锁定,并且将自行获取锁。

int __v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl, u32 dims[V4L2_CTRL_MAX_DIMS])

v4l2_ctrl_modify_dimensions() 的非锁变体。

参数

struct v4l2_ctrl *ctrl

要更新的控件。

u32 dims[V4L2_CTRL_MAX_DIMS]

控制的新维度。

描述

动态更新数组控制的维度。即使维度未更改,数组的元素也会重置为其默认值。

如果 dims 对此控制无效,则会返回错误。

调用者负责代表 __v4l2_ctrl_modify_dimensions() 获取控制处理程序的互斥锁。

注意

当在挂起的请求中使用相同控制时调用此函数未经测试。它应该可以工作(具有错误控制大小的请求会静默地删除该控制),但这会非常令人困惑。

int v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl, u32 dims[V4L2_CTRL_MAX_DIMS])

更新数组控制的维度。

参数

struct v4l2_ctrl *ctrl

要更新的控件。

u32 dims[V4L2_CTRL_MAX_DIMS]

控制的新维度。

描述

动态更新数组控制的维度。即使维度未更改,数组的元素也会重置为其默认值。

如果 dims 对此控制类型无效,则会返回错误。

此函数假定控制处理程序未锁定,并且将自行获取锁。

注意

当在挂起的请求中使用相同控制时调用此函数未经测试。它应该可以工作(具有错误控制大小的请求会静默地删除该控制),但这会非常令人困惑。

void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)

用于为控制设置通知回调的函数。

参数

struct v4l2_ctrl *ctrl

控制。

v4l2_ctrl_notify_fnc notify

回调函数。

void *priv

回调私有句柄,作为参数传递给回调。

描述

此函数为控制设置回调函数。如果 ctrl 为 NULL,则它将不执行任何操作。如果 notify 为 NULL,则将删除通知回调。

只能有一个通知。如果已存在另一个通知,则会发出 WARN_ON,并且该函数将不执行任何操作。

const char *v4l2_ctrl_get_name(u32 id)

获取控制的名称

参数

u32 id

控件 ID。

描述

此函数返回给定控制 ID 的名称,如果它不是已知的控制,则返回 NULL。

const char *const *v4l2_ctrl_get_menu(u32 id)

获取控制的菜单字符串数组

参数

u32 id

控件 ID。

描述

此函数返回给定控制 ID 的以 NULL 结尾的菜单字符串数组名称,如果它不是已知的菜单控制,则返回 NULL。

const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len)

获取控制的整数菜单数组

参数

u32 id

控件 ID。

u32 *len

整数数组的大小。

描述

此函数返回给定控制 ID 的整数数组,如果它不是已知的整数菜单控制,则返回 NULL。

s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)

从驱动程序内部获取控制值的辅助函数。

参数

struct v4l2_ctrl *ctrl

控制。

描述

此函数通过控制框架安全地返回控制的值。此函数将锁定控制的处理程序,因此不能在 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于整数类型控制。

int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)

v4l2_ctrl_s_ctrl() 的非锁变体。

参数

struct v4l2_ctrl *ctrl

控制。

s32 val

新值。

描述

此函数通过控制框架安全地设置控制的新值。此函数假定控制的处理程序已锁定,允许在 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于整数类型控制。

int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)

从驱动程序内部设置控制值的辅助函数。

参数

struct v4l2_ctrl *ctrl

控制。

s32 val

新值。

描述

此函数通过控制框架安全地设置控制的新值。此函数将锁定控制的处理程序,因此不能在 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于整数类型控制。

s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)

从驱动程序内部获取 64 位控制值的辅助函数。

参数

struct v4l2_ctrl *ctrl

控制。

描述

此函数通过控制框架安全地返回控制的值。此函数将锁定控制的处理程序,因此不能在 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于 64 位整数类型控制。

int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)

v4l2_ctrl_s_ctrl_int64() 的非锁变体。

参数

struct v4l2_ctrl *ctrl

控制。

s64 val

新值。

描述

此函数通过控制框架安全地设置控制的新值。此函数假定控制的处理程序已锁定,允许在 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于 64 位整数类型控制。

int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)

从驱动程序内部设置 64 位控制值的辅助函数。

参数

struct v4l2_ctrl *ctrl

控制。

s64 val

新值。

描述

此函数通过控制框架安全地设置控制的新值。此函数将锁定控制的处理程序,因此不能在 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于 64 位整数类型控制。

int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)

v4l2_ctrl_s_ctrl_string() 的非锁定变体。

参数

struct v4l2_ctrl *ctrl

控制。

const char *s

新的字符串。

描述

此函数通过控制框架安全地设置控件的新字符串。此函数假定控件的处理程序已被锁定,允许从 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于字符串类型的控件。

int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)

用于从驱动程序内部设置控件字符串值的辅助函数。

参数

struct v4l2_ctrl *ctrl

控制。

const char *s

新的字符串。

描述

此函数通过控制框架安全地设置控件的新字符串。此函数将锁定控件的处理程序,因此不能从 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于字符串类型的控件。

int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl, enum v4l2_ctrl_type type, const void *p)

设置复合控件的非锁定变体。

参数

struct v4l2_ctrl *ctrl

控制。

enum v4l2_ctrl_type type

数据的类型。

const void *p

新的复合有效载荷。

描述

此函数通过控制框架安全地设置控件的新复合有效载荷。此函数假定控件的处理程序已被锁定,允许从 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于复合类型的控件。

int v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl, enum v4l2_ctrl_type type, const void *p)

用于从驱动程序内部设置复合控件的辅助函数。

参数

struct v4l2_ctrl *ctrl

控制。

enum v4l2_ctrl_type type

数据的类型。

const void *p

新的复合有效载荷。

描述

此函数通过控制框架安全地设置控件的新复合有效载荷。此函数将锁定控件的处理程序,因此不能从 v4l2_ctrl_ops 函数内部使用。

此函数仅适用于复合类型的控件。

void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)

用作 struct v4l2_subscribed_event_ops replace() 的回调的函数

参数

struct v4l2_event *old

指向带有报告事件的 v4l2_event 结构的指针;

const struct v4l2_event *new

指向带有修改事件的 v4l2_event 结构的指针;

void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)

用作 struct v4l2_subscribed_event_ops merge() 的回调的函数

参数

const struct v4l2_event *old

指向带有报告事件的 v4l2_event 结构的指针;

struct v4l2_event *new

指向带有合并事件的 v4l2_event 结构的指针;

int v4l2_ctrl_log_status(struct file *file, void *fh)

用于实现 VIDIOC_LOG_STATUS ioctl 的辅助函数

参数

struct file *file

指向 struct file 的指针

void *fh

未使用。保留只是为了与 struct v4l2_ioctl_ops.vidioc_log_status 期望的参数兼容。

描述

可以用作 vidioc_log_status 函数,该函数仅转储与文件句柄关联的所有控件。

int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)

订阅一个事件

参数

struct v4l2_fh *fh

指向 struct v4l2_fh 的指针

const struct v4l2_event_subscription *sub

指向 struct v4l2_event_subscription 的指针

描述

可以用作 vidioc_subscribe_event 函数,该函数仅订阅控件事件。

__poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)

用作 poll() 回调的函数。该函数仅轮询控件事件。

参数

struct file *file

指向 struct file 的指针

struct poll_table_struct *wait

指向 struct poll_table_struct 的指针

int v4l2_ctrl_request_setup(struct media_request *req, struct v4l2_ctrl_handler *parent)

在请求中应用控件值的辅助函数

参数

struct media_request *req

请求

struct v4l2_ctrl_handler *parent

父控件处理程序(media_request_object_find() 中的 “priv”)

描述

这是一个辅助函数,用于使用请求中包含的控制值调用控制处理程序的 s_ctrl 回调。 请注意,这种在请求中应用控制值的方法仅适用于内存到内存的设备。

void v4l2_ctrl_request_complete(struct media_request *req, struct v4l2_ctrl_handler *parent)

完成控制处理程序请求对象

参数

struct media_request *req

请求

struct v4l2_ctrl_handler *parent

父控件处理程序(media_request_object_find() 中的 “priv”)

描述

此函数应在每个可能与请求对象关联的控制处理程序上调用,即支持请求的驱动程序的控制处理程序。

该函数首先获取控制处理程序中任何易失性控件的值,并将它们附加到请求。然后,该函数完成请求对象。

struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req, struct v4l2_ctrl_handler *parent)

在请求中查找控制处理程序

参数

struct media_request *req

请求

struct v4l2_ctrl_handler *parent

父控件处理程序(media_request_object_find() 中的 “priv”)

描述

此函数在请求中查找控制处理程序。 如果未找到,则可能返回 NULL。 完成后,必须使用返回的处理程序指针调用 v4l2_ctrl_request_hdl_put()

如果请求未处于 VALIDATING 或 QUEUED 状态,则此函数将始终返回 NULL。

请注意,在 VALIDATING 状态下,req_queue_mutex 被持有,因此无法从请求中添加或删除对象。

在 QUEUED 状态下,将由驱动程序来确保这一点。

void v4l2_ctrl_request_hdl_put(struct v4l2_ctrl_handler *hdl)

释放控制处理程序

参数

struct v4l2_ctrl_handler *hdl

释放此控制处理程序

描述

此函数释放先前从 v4l2_ctrl_request_hdl_find() 获取的控制处理程序。

struct v4l2_ctrl *v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)

查找具有给定 ID 的控件。

参数

struct v4l2_ctrl_handler *hdl

来自请求的控制处理程序。

u32 id

要查找的控件的 ID。

描述

如果此控件是请求的一部分,则此函数返回指向该控件的指针,否则返回 NULL。

int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)

用于实现 VIDIOC_QUERYCTRL ioctl 的辅助函数

参数

struct v4l2_ctrl_handler *hdl

指向 struct v4l2_ctrl_handler 的指针

struct v4l2_queryctrl *qc

指向 struct v4l2_queryctrl 的指针

描述

如果 hdl == NULL,则它们都将返回 -EINVAL。

int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)

用于实现 VIDIOC_QUERY_EXT_CTRL ioctl 的辅助函数

参数

struct v4l2_ctrl_handler *hdl

指向 struct v4l2_ctrl_handler 的指针

struct v4l2_query_ext_ctrl *qc

指向 struct v4l2_query_ext_ctrl 的指针

描述

如果 hdl == NULL,则它们都将返回 -EINVAL。

int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)

用于实现 VIDIOC_QUERYMENU ioctl 的辅助函数

参数

struct v4l2_ctrl_handler *hdl

指向 struct v4l2_ctrl_handler 的指针

struct v4l2_querymenu *qm

指向 struct v4l2_querymenu 的指针

描述

如果 hdl == NULL,则它们都将返回 -EINVAL。

int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl)

用于实现 VIDIOC_G_CTRL ioctl 的辅助函数

参数

struct v4l2_ctrl_handler *hdl

指向 struct v4l2_ctrl_handler 的指针

struct v4l2_control *ctrl

指向 struct v4l2_control 的指针

描述

如果 hdl == NULL,则它们都将返回 -EINVAL。

int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl)

用于实现 VIDIOC_S_CTRL ioctl 的辅助函数

参数

struct v4l2_fh *fh

指向 struct v4l2_fh 的指针

struct v4l2_ctrl_handler *hdl

指向 struct v4l2_ctrl_handler 的指针

struct v4l2_control *ctrl

指向 struct v4l2_control 的指针

描述

如果 hdl == NULL,则它们都将返回 -EINVAL。

int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev, struct media_device *mdev, struct v4l2_ext_controls *c)

用于实现 VIDIOC_G_EXT_CTRLS ioctl 的辅助函数

参数

struct v4l2_ctrl_handler *hdl

指向 struct v4l2_ctrl_handler 的指针

struct video_device *vdev

指向 struct video_device 的指针

struct media_device *mdev

指向 struct media_device 的指针

struct v4l2_ext_controls *c

指向 struct v4l2_ext_controls 的指针

描述

如果 hdl == NULL,则它们都将返回 -EINVAL。

int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev, struct media_device *mdev, struct v4l2_ext_controls *c)

用于实现 VIDIOC_TRY_EXT_CTRLS ioctl 的辅助函数

参数

struct v4l2_ctrl_handler *hdl

指向 struct v4l2_ctrl_handler 的指针

struct video_device *vdev

指向 struct video_device 的指针

struct media_device *mdev

指向 struct media_device 的指针

struct v4l2_ext_controls *c

指向 struct v4l2_ext_controls 的指针

描述

如果 hdl == NULL,则它们都将返回 -EINVAL。

int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, struct video_device *vdev, struct media_device *mdev, struct v4l2_ext_controls *c)

用于实现 VIDIOC_S_EXT_CTRLS ioctl 的辅助函数

参数

struct v4l2_fh *fh

指向 struct v4l2_fh 的指针

struct v4l2_ctrl_handler *hdl

指向 struct v4l2_ctrl_handler 的指针

struct video_device *vdev

指向 struct video_device 的指针

struct media_device *mdev

指向 struct media_device 的指针

struct v4l2_ext_controls *c

指向 struct v4l2_ext_controls 的指针

描述

如果 hdl == NULL,则它们都将返回 -EINVAL。

int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub)

用于实现作为 struct v4l2_subdev_core_ops subscribe_event 函数的辅助函数,该函数仅订阅控制事件。

参数

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

struct v4l2_fh *fh

指向 struct v4l2_fh 的指针

struct v4l2_event_subscription *sub

指向 struct v4l2_event_subscription 的指针

int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd)

记录子设备的控制句柄拥有的所有控件。

参数

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ctrl_ops, const struct v4l2_fwnode_device_properties *p)

为设备属性注册控件

参数

struct v4l2_ctrl_handler *hdl

指向要注册控件的 struct v4l2_ctrl_handler 的指针

const struct v4l2_ctrl_ops *ctrl_ops

指向要注册控件的 struct v4l2_ctrl_ops 的指针

const struct v4l2_fwnode_device_properties *p

指向 struct v4l2_fwnode_device_properties 的指针

描述

此函数使用 p 参数中包含的属性值,如果该属性已设置为某个值,则注册与设备属性关联的控件。

当前解析和注册以下 v4l2 控件: - V4L2_CID_CAMERA_ORIENTATION - V4L2_CID_CAMERA_SENSOR_ROTATION;

调用者使用 hdl 控制句柄已注册的控件不会被覆盖。调用者应在调用此函数之前注册他们想要自己处理的控件。

返回

成功时返回 0,失败时返回负错误代码。

bool v4l2_ctrl_type_op_equal(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr1, union v4l2_ctrl_ptr ptr2)

默认的 v4l2_ctrl_type_ops equal 回调。

参数

const struct v4l2_ctrl *ctrl

v4l2_ctrl 指针。

union v4l2_ctrl_ptr ptr1

v4l2 控制值。

union v4l2_ctrl_ptr ptr2

v4l2 控制值。

返回

如果值相等,则为 true,否则为 false。

void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx, union v4l2_ctrl_ptr ptr)

默认的 v4l2_ctrl_type_ops init 回调。

参数

const struct v4l2_ctrl *ctrl

v4l2_ctrl 指针。

u32 from_idx

起始元素索引。

union v4l2_ctrl_ptr ptr

v4l2 控制值。

返回

void

void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)

默认的 v4l2_ctrl_type_ops 日志回调函数。

参数

const struct v4l2_ctrl *ctrl

v4l2_ctrl 指针。

返回

void

int v4l2_ctrl_type_op_validate(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr)

默认的 v4l2_ctrl_type_ops 验证回调函数。

参数

const struct v4l2_ctrl *ctrl

v4l2_ctrl 指针。

union v4l2_ctrl_ptr ptr

v4l2 控制值。

返回

成功时返回 0,失败时返回负错误代码。