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,因此没有 min 参数,并且没有步长,而是一个 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<something>。基本上,val 和 cur.val 字段可以被视为别名,因为它们经常被使用。

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

除非控件被标记为 volatile,否则 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。

要将控件标记为 volatile,您必须设置 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() 设置“active”状态。默认情况下,所有控件都是活动的。请注意,框架不检查此标志。它纯粹是为了 GUI。该函数通常从 s_ctrl 中调用。

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

如果使用 v4l2_ctrl_grab() 将控件设置为“grabbed”,则如果尝试设置此控件,框架将返回 -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,则手动控件永远不会易失性。如果硬件不为您提供读回自动模式确定的值的选项,您通常会使用它(例如,如果自动增益打开,则硬件不允许您获取当前增益值)。

假定集群的第一个控件是“自动”控件。

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

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 为 <control class | 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;
    struct v4l2_rect *p_rect;
    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_rect

指向矩形的指针。

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

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

try_ctrl

测试控件的值是否有效。仅当通常的 min/max/step 检查不足时才相关。

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 (*minimum)(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr);
    void (*maximum)(const struct v4l2_ctrl *ctrl, u32 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。

minimum

将值设置为控件的最小值。

maximum

将值设置为控件的最大值。

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

指向 struct v4l2_ctrl 的指针

void *priv

控件私有数据

说明

此 typedef 定义用作 v4l2_ctrl_notify() 的参数,并作为 struct 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_min;
    union v4l2_ctrl_ptr p_max;
    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

如果设置,则此控件包含动态大小的 1 维数组。如果设置了此项,则也会设置 is_array

has_volatiles

如果设置,则群集的一个或多个成员是 volatile 的。驱动程序不应触摸此标志。

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}

anonymous

step

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

menu_skip_mask

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

{unnamed_union}

anonymous

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_min

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

p_max

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

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

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

from_other_dev

如果为真,则表示 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;
    union v4l2_ctrl_ptr p_min;
    union v4l2_ctrl_ptr p_max;
    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

控件类型 ops。 仅复合控件需要。

id

控件 ID。

name

控件名称。

type

控件类型。

min

控件的最小值。

max

控件的最大值。

step

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

def

控件的默认值。

p_def

复合控件的控件默认值。

p_min

复合控件的控件最小值。

p_max

复合控件的控件最大值。

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,则由锁验证器使用。

说明

注意

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

返回值

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

v4l2_ctrl_handler_init

v4l2_ctrl_handler_init (hdl, nr_of_controls_hint)

辅助函数,用于创建静态 struct lock_class_key 并调用 v4l2_ctrl_handler_init_class()

参数

hdl

控件处理程序。

nr_of_controls_hint

提示此处理程序预计引用的控件数量。 这是总数,因此包括任何继承的控件。 它不必精确,但如果它偏离太远,那么你要么浪费内存(分配了太多的桶),要么控件查找变得更慢(分配的桶不够,因此有更多的慢速列表查找)。 不过,它总是会工作。

说明

此辅助函数创建静态 struct 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 op,以将硬件初始化为当前的控件值。 调用者负责代表 __v4l2_ctrl_handler_setup() 获取控件处理程序互斥锁。

参数

struct v4l2_ctrl_handler *hdl

控件处理程序。

说明

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

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

int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)

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

参数

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, const union v4l2_ctrl_ptr p_min, const union v4l2_ctrl_ptr p_max)

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

参数

struct v4l2_ctrl_handler *hdl

控件处理程序。

const struct v4l2_ctrl_ops *ops

控件操作。

u32 id

控件 ID。

const union v4l2_ctrl_ptr p_def

控件的默认值。

const union v4l2_ctrl_ptr p_min

控件的最小值。

const union v4l2_ctrl_ptr p_max

控件的最大值。

说明

v4l2_ctrl_new_std() 相同,但支持复合控件。要填充 p_defp_minp_max 字段,请使用 v4l2_ctrl_ptr_create() 将指针转换为 const union v4l2_ctrl_ptr。如果您希望复合控件的默认值、最小值或最大值全为零,请使用 v4l2_ctrl_ptr_create(NULL)。如果复合控件未设置 V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX 标志,则它没有最小值和最大值。在这种情况下,只需对 p_minp_max 参数使用 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

指向 struct 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 不同的设备中定义的。

说明

如果两个处理程序中的任何一个是指针,则不执行任何操作。如果 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)

将集群中的所有控件标记为属于该集群,并将其设置为进行 autofoo/foo 类型处理。

参数

unsigned int ncontrols

此集群中控件的数量。

struct v4l2_ctrl **controls

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

u8 manual_val

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

bool set_volatile

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

说明

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

此类控件的行为如下

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

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

此外,如果 autofoo 处于自动模式,此函数将在 autofoo 控件上设置 V4L2_CTRL_FLAG_UPDATE 标志,并在 foo 控件上设置 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。

void v4l2_query_ext_ctrl_to_v4l2_queryctrl(struct v4l2_queryctrl *to, const struct v4l2_query_ext_ctrl *from)

将 qec 转换为 qe。

参数

struct v4l2_queryctrl *to

要写入的 v4l2_queryctrl。

const struct v4l2_query_ext_ctrl *from

要从中读取的 v4l2_query_ext_ctrl。

说明

此函数是一个辅助函数,用于将 v4l2_query_ext_ctrl 转换为 v4l2_queryctrl。

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 log 回调。

参数

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 validate 回调。

参数

const struct v4l2_ctrl *ctrl

v4l2_ctrl 指针。

union v4l2_ctrl_ptr ptr

v4l2 控制值。

返回值

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