2.7. V4L2 子设备

许多驱动程序需要与子设备通信。这些设备可以执行各种任务,但最常见的是处理音频和/或视频的混合、编码或解码。对于网络摄像头,常见的子设备是传感器和摄像头控制器。

通常这些是 I2C 设备,但不一定。为了为驱动程序提供与这些子设备一致的接口,创建了 v4l2_subdev 结构体 (v4l2-subdev.h)。

每个子设备驱动程序都必须有一个 v4l2_subdev 结构体。对于简单的子设备,此结构体可以是独立的,如果需要存储更多状态信息,则可以嵌入到更大的结构体中。通常有一个低级设备结构体(例如 i2c_client),其中包含内核设置的设备数据。建议使用 v4l2_set_subdevdata() 将该指针存储在 v4l2_subdev 的私有数据中。这样可以轻松地从 v4l2_subdev 转到实际的低级总线特定设备数据。

您还需要一种从低级结构体转到 v4l2_subdev 的方法。对于常见的 i2c_client 结构体,使用 i2c_set_clientdata() 调用来存储 v4l2_subdev 指针,对于其他总线,您可能需要使用其他方法。

桥接器可能还需要存储每个子设备的私有数据,例如指向桥接器特定的每个子设备的私有数据的指针。v4l2_subdev 结构体为此目的提供了主机私有数据,可以使用 v4l2_get_subdev_hostdata()v4l2_set_subdev_hostdata() 访问。

从桥接器驱动程序的角度来看,您加载子设备模块,并以某种方式获取 v4l2_subdev 指针。对于 i2c 设备,这很容易:您调用 i2c_get_clientdata()。对于其他总线,需要执行类似的操作。存在用于 I2C 总线上的子设备的辅助函数,可以为您完成大部分棘手的工作。

每个 v4l2_subdev 包含子设备驱动程序可以实现的函数指针(或者如果不适用,则保留为 NULL)。由于子设备可以做很多不同的事情,并且您不希望最终得到一个庞大的 ops 结构体,其中只有少数 ops 被普遍实现,因此函数指针按照类别排序,每个类别都有自己的 ops 结构体。

顶层 ops 结构体包含指向类别 ops 结构体的指针,如果 subdev 驱动程序不支持该类别中的任何内容,则该指针可能为 NULL。

它看起来像这样

struct v4l2_subdev_core_ops {
        int (*log_status)(struct v4l2_subdev *sd);
        int (*init)(struct v4l2_subdev *sd, u32 val);
        ...
};

struct v4l2_subdev_tuner_ops {
        ...
};

struct v4l2_subdev_audio_ops {
        ...
};

struct v4l2_subdev_video_ops {
        ...
};

struct v4l2_subdev_pad_ops {
        ...
};

struct v4l2_subdev_ops {
        const struct v4l2_subdev_core_ops  *core;
        const struct v4l2_subdev_tuner_ops *tuner;
        const struct v4l2_subdev_audio_ops *audio;
        const struct v4l2_subdev_video_ops *video;
        const struct v4l2_subdev_pad_ops *video;
};

核心 ops 对所有 subdevs 都是通用的,其他类别根据子设备实现。例如,视频设备不太可能支持音频 ops,反之亦然。

此设置限制了函数指针的数量,同时仍然可以轻松添加新的 ops 和类别。

子设备驱动程序使用以下命令初始化 v4l2_subdev 结构体

之后,您需要使用唯一的名称初始化 sd->name 并设置模块所有者。如果您使用 i2c 辅助函数,则会自动为您完成此操作。

如果需要与媒体框架集成,则必须通过调用 media_entity_pads_init() 来初始化嵌入在 v4l2_subdev 结构体(实体字段)中的 media_entity 结构体,如果实体有 pad

struct media_pad *pads = &my_sd->pads;
int err;

err = media_entity_pads_init(&sd->entity, npads, pads);

pads 数组必须已事先初始化。无需手动设置 struct media_entity 函数和名称字段,但如果需要,则必须初始化修订字段。

当子设备设备节点(如果有)打开/关闭时,将自动获取/释放对实体的引用。

不要忘记在子设备销毁之前清理媒体实体

media_entity_cleanup(&sd->entity);

如果子设备驱动程序实现接收器 pad,则 subdev 驱动程序可以在 v4l2_subdev_pad_ops 中设置 link_validate 字段以提供自己的链接验证函数。对于管道中的每个链接,都会调用链接的接收器端的 link_validate pad 操作。在这两种情况下,驱动程序仍然负责验证子设备和视频节点之间的格式配置的正确性。

如果未设置 link_validate op,则使用默认函数 v4l2_subdev_link_validate_default()。此函数确保链接的源和接收器上的宽度、高度和媒体总线像素代码相等。除了他们自己的检查之外,Subdev 驱动程序还可以自由地使用此功能来执行上述检查。

2.7.1. Subdev 注册

目前有两种方法可以将子设备注册到 V4L2 核心。第一种(传统)可能性是由桥接器驱动程序注册子设备。当桥接器驱动程序具有有关连接到它的子设备的完整信息,并且确切知道何时注册它们时,可以执行此操作。这通常是内部子设备的情况,例如 SoC 或复杂 PCI(e) 板内的视频数据处理单元、USB 摄像头中的摄像头传感器或连接到 SoC,它们通常在其平台数据中将有关它们的信息传递给桥接器驱动程序。

但是,在某些情况下,子设备必须异步地注册到桥接器设备。这种配置的一个示例是基于设备树的系统,其中有关子设备的信息独立于桥接器设备提供给系统,例如,当子设备在 DT 中定义为 I2C 设备节点时。第二种情况中使用的 API 在下面进一步描述。

使用一种或另一种注册方法只会影响探测过程,在两种情况下,运行时桥接器-子设备交互是相同的。

2.7.1.1. 注册同步子设备

同步情况下,设备(桥接器)驱动程序需要使用 v4l2_device 注册 v4l2_subdev

如果 subdev 模块在注册之前消失,则此操作可能会失败。成功调用此函数后,subdev->dev 字段指向 v4l2_device

如果 v4l2_device 父设备具有非 NULL mdev 字段,则子设备实体将自动注册到媒体设备。

您可以使用以下命令注销子设备

之后,可以卸载 subdev 模块,并且 sd->dev == NULL

2.7.1.2. 注册异步子设备

异步情况下,可以独立于桥接器驱动程序的可用性来调用子设备探测。然后,子设备驱动程序必须验证是否满足成功探测的所有要求。这可以包括检查主时钟的可用性。如果任何条件未满足,驱动程序可能会决定返回 -EPROBE_DEFER 以请求进一步的重新探测尝试。一旦满足所有条件,应使用 v4l2_async_register_subdev() 函数注册子设备。注销使用 v4l2_async_unregister_subdev() 调用执行。以这种方式注册的子设备存储在子设备的全局列表中,准备好被桥接器驱动程序拾取。

驱动程序必须在使能够运行时 PM 之前,在使用 v4l2_async_register_subdev() 注册子设备之前完成子设备的所有初始化。这是因为子设备在注册后立即变得可访问。

2.7.1.3. 异步子设备通知器

反过来,桥接器驱动程序必须注册一个通知器对象。这是使用 v4l2_async_nf_register() 调用执行的。要注销通知器,驱动程序必须调用 v4l2_async_nf_unregister()。在释放未注册通知器的内存之前,必须通过调用 v4l2_async_nf_cleanup() 来清理它。

在注册通知器之前,桥接器驱动程序必须做两件事:首先,必须使用 v4l2_async_nf_init() 初始化通知器。其次,桥接器驱动程序可以开始形成桥接器设备运行所需的异步连接描述符列表。v4l2_async_nf_add_fwnode()v4l2_async_nf_add_fwnode_remote()v4l2_async_nf_add_i2c()

异步连接描述符描述了与外部子设备的连接,这些子设备的驱动程序尚未被探测。基于异步连接,当相关的子设备可用时,可能会创建一个媒体数据或辅助链接。可能有一个或多个到给定子设备的异步连接,但这在将连接添加到通知器时是未知的。异步连接在找到匹配的异步子设备时,逐个绑定。

2.7.1.4. 子设备的异步子设备通知器

注册异步子设备的驱动程序也可以注册异步通知器。这称为异步子设备通知器,该过程与桥接器驱动程序的过程类似,不同之处在于使用 v4l2_async_subdev_nf_init() 初始化通知器。只有在 V4L2 设备可用后,即存在通过异步子设备和通知器到非异步子设备通知器的路径时,子设备通知器才能完成。

2.7.1.5. 摄像头传感器驱动程序的异步子设备注册助手

v4l2_async_register_subdev_sensor() 是传感器驱动程序注册自己的异步连接的辅助函数,但它也注册一个通知器,并进一步注册固件中找到的镜头和闪光设备的异步连接。子设备的通知器使用 v4l2_async_unregister_subdev() 注销并与异步子设备一起清理。

2.7.1.6. 异步子设备通知器示例

这些函数分配一个异步连接描述符,该描述符是类型结构体 v4l2_async_connection 嵌入到驱动程序特定的结构体中。&struct v4l2_async_connection 应是此结构体的第一个成员

struct my_async_connection {
        struct v4l2_async_connection asc;
        ...
};

struct my_async_connection *my_asc;
struct fwnode_handle *ep;

...

my_asc = v4l2_async_nf_add_fwnode_remote(&notifier, ep,
                                         struct my_async_connection);
fwnode_handle_put(ep);

if (IS_ERR(my_asc))
        return PTR_ERR(my_asc);

2.7.1.7. 异步子设备通知器回调

然后,V4L2 核心将使用这些连接描述符将异步注册的子设备与它们匹配。如果检测到匹配,则调用 .bound() 通知器回调。在绑定所有连接后,调用 .complete() 回调。当从系统中删除连接时,调用 .unbind() 方法。所有三个回调都是可选的。

驱动程序可以在其驱动程序特定的 v4l2_async_connection 包装器中存储任何类型的自定义数据。如果在释放结构体时任何数据需要特殊处理,则驱动程序必须实现 .destroy() 通知器回调。框架将在释放 v4l2_async_connection 之前立即调用它。

2.7.2. 调用 subdev 操作

使用 v4l2_subdev 的优点是它是一个通用结构体,不包含有关底层硬件的任何知识。因此,驱动程序可能包含多个使用 I2C 总线的 subdev,但也可能包含一个通过 GPIO 引脚控制的 subdev。这种区别仅在设置设备时才相关,但一旦注册 subdev,它就完全透明。

注册 subdev 后,您可以直接调用 ops 函数

err = sd->ops->core->g_std(sd, &norm);

但最好且更容易使用此宏

err = v4l2_subdev_call(sd, core, g_std, &norm);

该宏将执行正确的 NULL 指针检查,如果 sdNULL,则返回 -ENODEV,如果 sd->core 或 sd->core->g_std 是 NULL,则返回 -ENOIOCTLCMD,否则返回 sd->ops->core->g_std ops 的实际结果。

也可以调用所有或部分子设备

v4l2_device_call_all(v4l2_dev, 0, core, g_std, &norm);

任何不支持此 ops 的 subdev 都会被跳过,并且错误结果会被忽略。如果要检查错误,请使用此命令

err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_std, &norm);

除了 -ENOIOCTLCMD 之外的任何错误都将以该错误退出循环。如果没有发生错误(除了 -ENOIOCTLCMD),则返回 0。

两次调用的第二个参数是一个组 ID。如果为 0,则调用所有 subdev。如果为非零值,则仅调用那些组 ID 与该值匹配的 subdev。在桥接器驱动程序注册 subdev 之前,它可以将 sd->grp_id 设置为它想要的任何值(默认为 0)。此值归桥接器驱动程序所有,子设备驱动程序永远不会修改或使用它。

组 ID 使桥接器驱动程序可以更好地控制如何调用回调。例如,一个板上可能有多个音频芯片,每个芯片都能够改变音量。但是,通常在用户想要更改音量时,只会实际使用一个。您可以将该 subdev 的组 ID 设置为例如 AUDIO_CONTROLLER,并在调用 v4l2_device_call_all() 时将其指定为组 ID 值。这确保它只会转到需要的 subdev。

如果子设备需要将其 v4l2_device 父设备通知事件,则它可以调用 v4l2_subdev_notify(sd, notification, arg)。此宏检查是否定义了 notify() 回调,如果未定义,则返回 -ENODEV。否则,将返回 notify() 调用的结果。

2.8. V4L2 子设备用户空间 API

传统上,桥接器驱动程序向用户空间公开一个或多个视频节点,并通过 v4l2_subdev_ops 操作来控制子设备,以响应视频节点操作。这向应用程序隐藏了底层硬件的复杂性。对于复杂的设备,可能需要比视频节点提供的更精细的设备控制。在这些情况下,实现 媒体控制器 API 的桥接器驱动程序可以选择直接从用户空间访问子设备操作。

可以在 /dev 中创建名为 v4l-subdevX 的设备节点以直接访问子设备。如果子设备支持直接用户空间配置,则必须在注册之前设置 V4L2_SUBDEV_FL_HAS_DEVNODE 标志。

注册子设备后,v4l2_device 驱动程序可以为所有标记有 V4L2_SUBDEV_FL_HAS_DEVNODE 的已注册子设备创建设备节点,方法是调用 v4l2_device_register_subdev_nodes()。当注销子设备时,这些设备节点将被自动删除。

设备节点处理 V4L2 API 的子集。

VIDIOC_QUERYCTRLVIDIOC_QUERYMENUVIDIOC_G_CTRLVIDIOC_S_CTRLVIDIOC_G_EXT_CTRLSVIDIOC_S_EXT_CTRLSVIDIOC_TRY_EXT_CTRLS

控件 ioctl 与 V4L2 中定义的相同。它们的行为相同,唯一的例外是它们仅处理在子设备中实现的控件。根据驱动程序,也可以通过一个(或多个)V4L2 设备节点访问这些控件。

VIDIOC_DQEVENTVIDIOC_SUBSCRIBE_EVENTVIDIOC_UNSUBSCRIBE_EVENT

事件 ioctl 与 V4L2 中定义的相同。它们的行为相同,唯一的例外是它们仅处理由子设备生成的事件。根据驱动程序,也可以通过一个(或多个)V4L2 设备节点报告这些事件。

想要使用事件的子设备驱动程序需要在注册子设备之前设置 V4L2_SUBDEV_FL_HAS_EVENTS v4l2_subdev.flags。注册后,事件可以像往常一样在 v4l2_subdev.devnode 设备节点上排队。

为了正确支持事件,还实现了 poll() 文件操作。

私有 ioctl

上面列表中未包含的所有 ioctl 都通过 core::ioctl 操作直接传递给子设备驱动程序。

2.9. 只读子设备用户空间 API

桥接驱动程序通过直接调用由 v4l2_subdev_ops 结构实现的内核 API 来控制其连接的子设备,通常不希望用户空间能够通过子设备设备节点更改相同的参数,因此通常不注册任何内容。

有时通过只读 API 向用户空间报告当前子设备配置很有用,该 API 不允许应用程序更改设备参数,但允许与子设备设备节点交互以检查它们。

例如,为了实现基于计算摄影的相机,用户空间需要了解每个支持的输出分辨率的详细相机传感器配置(在跳过、合并、裁剪和缩放方面)。为了支持此类用例,桥接驱动程序可以通过只读 API 将子设备操作公开给用户空间。

要为所有注册了 V4L2_SUBDEV_FL_HAS_DEVNODE 的子设备创建只读设备节点,v4l2_device 驱动程序应调用 v4l2_device_register_ro_subdev_nodes()

对于使用 v4l2_device_register_ro_subdev_nodes() 注册的子设备设备节点,用户空间应用程序对以下 ioctl 的访问受到限制。

VIDIOC_SUBDEV_S_FMTVIDIOC_SUBDEV_S_CROPVIDIOC_SUBDEV_S_SELECTION

这些 ioctl 仅允许在只读子设备设备节点上用于 V4L2_SUBDEV_FORMAT_TRY 格式和选择矩形。

VIDIOC_SUBDEV_S_FRAME_INTERVALVIDIOC_SUBDEV_S_DV_TIMINGSVIDIOC_SUBDEV_S_STD

这些 ioctl 不允许在只读子设备节点上使用。

如果 ioctl 不允许,或者要修改的格式设置为 V4L2_SUBDEV_FORMAT_ACTIVE,则核心将返回一个负错误代码,并且 errno 变量设置为 -EPERM

2.10. I2C 子设备驱动程序

由于这些驱动程序非常常见,因此可以使用特殊的辅助函数来简化这些驱动程序的使用 (v4l2-common.h)。

v4l2_subdev 支持添加到 I2C 驱动程序的推荐方法是将 v4l2_subdev 结构嵌入到为每个 I2C 设备实例创建的状态结构中。非常简单的设备没有状态结构,在这种情况下,您可以直接创建一个 v4l2_subdev

典型的状态结构如下所示(其中 “chipname” 替换为芯片的名称)

struct chipname_state {
        struct v4l2_subdev sd;
        ...  /* additional state fields */
};

按如下方式初始化 v4l2_subdev 结构

v4l2_i2c_subdev_init(&state->sd, client, subdev_ops);

此函数将填写 v4l2_subdev 的所有字段,确保 v4l2_subdev 和 i2c_client 都相互指向。

您还应该添加一个辅助内联函数,以从 v4l2_subdev 指针转到 chipname_state 结构

static inline struct chipname_state *to_state(struct v4l2_subdev *sd)
{
        return container_of(sd, struct chipname_state, sd);
}

使用此函数从 v4l2_subdev 结构转到 i2c_client 结构

struct i2c_client *client = v4l2_get_subdevdata(sd);

使用此函数从 i2c_client 转到 v4l2_subdev 结构

struct v4l2_subdev *sd = i2c_get_clientdata(client);

确保在调用 remove() 回调时调用 v4l2_device_unregister_subdev()(sd)。这将从桥接驱动程序中注销子设备。即使从未注册子设备,也可以安全地调用此函数。

您需要这样做,因为当桥接驱动程序销毁 i2c 适配器时,会调用该适配器上的 i2c 设备的 remove() 回调。之后,相应的 v4l2_subdev 结构将无效,因此必须首先注销它们。从 remove() 回调调用 v4l2_device_unregister_subdev()(sd) 可确保始终正确地完成此操作。

桥接驱动程序还有一些可以使用的辅助函数

struct v4l2_subdev *sd = v4l2_i2c_new_subdev(v4l2_dev, adapter,
                                "module_foo", "chipid", 0x36, NULL);

这将加载给定的模块(如果没有模块需要加载,则可以为 NULL),并使用给定的 i2c_adapter 和芯片/地址参数调用 i2c_new_client_device()。如果一切顺利,它将向 v4l2_device 注册子设备。

您还可以使用 v4l2_i2c_new_subdev() 的最后一个参数来传递它应该探测的可能的 I2C 地址数组。仅当上一个参数为 0 时才使用这些探测地址。非零参数意味着您知道确切的 i2c 地址,因此在这种情况下不会进行探测。

如果出现问题,这两个函数都返回 NULL

请注意,您传递给 v4l2_i2c_new_subdev() 的 chipid 通常与模块名称相同。它允许您指定芯片变体,例如 “saa7114” 或 “saa7115”。但总的来说,i2c 驱动程序会自动检测到这一点。chipid 的使用需要在以后更仔细地研究。它在 i2c 驱动程序之间有所不同,因此可能会造成混淆。要查看支持哪些芯片变体,您可以查看 i2c 驱动程序代码中的 i2c_device_id 表。这列出了所有可能性。

还有一个辅助函数

v4l2_i2c_new_subdev_board() 使用传递给 i2c 驱动程序的 i2c_board_info 结构,并替换 irq、platform_data 和 addr 参数。

如果子设备支持 s_config core ops,则在设置子设备后使用 irq 和 platform_data 参数调用该 op。

v4l2_i2c_new_subdev() 函数将调用 v4l2_i2c_new_subdev_board(),在内部使用 client_typeaddr 填充 i2c_board_info 结构。

2.11. 集中管理的子设备活动状态

传统上,V4L2 子设备驱动程序维护活动设备配置的内部状态。这通常实现为例如 struct v4l2_mbus_framefmt 数组,每个 pad 一个条目,对于裁剪和合成矩形也是如此。

除了活动配置之外,每个子设备文件句柄都有一个由 V4L2 核心管理的 struct v4l2_subdev_state,其中包含尝试配置。

为了简化子设备驱动程序,V4L2 子设备 API 现在可以选择性地支持由 v4l2_subdev_state 表示的集中管理的活动配置。一个状态实例(包含活动设备配置)作为 v4l2_subdev 结构的一部分存储在子设备本身中,而核心将一个尝试状态与每个打开的文件句柄相关联,以存储与该文件句柄相关的尝试配置。

子设备驱动程序可以选择使用状态来管理其活动配置,方法是在注册子设备之前调用 v4l2_subdev_init_finalize() 初始化子设备状态。它们还必须调用 v4l2_subdev_cleanup() 以释放所有已分配的资源,然后才能注销子设备。核心自动为每个打开的文件句柄分配和初始化一个状态,以存储尝试配置,并在关闭文件句柄时释放它。

V4L2 子设备操作使用 ACTIVE 和 TRY 格式,通过 “状态” 参数接收要操作的正确状态。状态必须由调用者通过调用 v4l2_subdev_lock_state()v4l2_subdev_unlock_state() 来锁定和解锁。调用者可以通过调用 v4l2_subdev_call_state_active() 宏来执行此操作。

不接收状态参数的操作隐式地对子设备活动状态进行操作,驱动程序可以通过调用 v4l2_subdev_lock_and_get_active_state() 来独占访问该状态。子设备活动状态也必须通过调用 v4l2_subdev_unlock_state() 来释放。

驱动程序绝不能手动访问存储在 v4l2_subdev 或文件句柄中的状态,而不使用指定的辅助函数。

虽然 V4L2 核心将正确的尝试或活动状态传递给子设备操作,但许多现有设备驱动程序在调用 v4l2_subdev_call() 的操作时传递 NULL 状态。这种遗留结构导致子设备驱动程序出现问题,这些驱动程序让 V4L2 核心管理活动状态,因为它们期望接收适当的状态作为参数。为了帮助将子设备驱动程序转换为托管活动状态,而无需同时转换所有调用者,v4l2_subdev_call() 中添加了一个额外的包装器层,它通过使用 v4l2_subdev_lock_and_get_active_state() 获取和锁定被调用者的活动状态来处理 NULL 情况,并在调用后解锁状态。

整个子设备状态实际上分为三个部分:v4l2_subdev_state、子设备控件和子设备驱动程序的内部状态。将来,这些部分应该合并为一个状态。目前,我们需要一种方法来处理这些部分的锁定。这可以通过共享锁来完成。v4l2_ctrl_handler 已经通过其 “lock” 指针支持这一点,并且相同的模型也用于状态。驱动程序可以在调用 v4l2_subdev_init_finalize() 之前执行以下操作

sd->ctrl_handler->lock = &priv->mutex;
sd->state_lock = &priv->mutex;

这在控件和状态之间共享驱动程序的私有互斥锁。

2.12. 流、多路复用媒体 pad 和内部路由

子设备驱动程序可以通过设置 V4L2_SUBDEV_FL_STREAMS 子设备标志并实现对集中管理的子设备活动状态、路由和基于流的配置的支持来实现对多路复用流的支持。

2.13. V4L2 子设备函数和数据结构

struct v4l2_decode_vbi_line

用于 decode_vbi_line

定义:

struct v4l2_decode_vbi_line {
    u32 is_second_field;
    u8 *p;
    u32 line;
    u32 type;
};

成员

is_second_field

对于第一个(奇数)场,设置为 0;对于第二个(偶数)场,设置为 1。

p

指向解码器中切片的 VBI 数据的指针。退出时,指向有效负载的开始。

line

切片的 VBI 数据的行号 (1-23)

type

VBI 服务类型 (V4L2_SLICED_*)。如果未找到服务,则为 0

enum v4l2_subdev_io_pin_bits

子设备外部 IO 引脚配置位

常量

V4L2_SUBDEV_IO_PIN_DISABLE

禁用引脚配置。假定启用。

V4L2_SUBDEV_IO_PIN_OUTPUT

如果引脚是输出,则设置它。

V4L2_SUBDEV_IO_PIN_INPUT

如果引脚是输入,则设置它。

V4L2_SUBDEV_IO_PIN_SET_VALUE

通过 struct v4l2_subdev_io_pin_config->value 设置输出值。

V4L2_SUBDEV_IO_PIN_ACTIVE_LOW

引脚活动为位 0。否则,假定为 ACTIVE HIGH。

struct v4l2_subdev_io_pin_config

子设备外部 IO 引脚配置

定义:

struct v4l2_subdev_io_pin_config {
    u32 flags;
    u8 pin;
    u8 function;
    u8 value;
    u8 strength;
};

成员

flags

此引脚配置的标志位掩码,其位由 enum v4l2_subdev_io_pin_bits 定义。

pin

要配置的芯片外部 IO 引脚

function

要路由到 IO 引脚的内部信号 pad/函数

value

引脚的初始值 - 例如 GPIO 输出值

strength

引脚驱动强度

struct v4l2_subdev_core_ops

为子设备定义核心 ops 回调

定义:

struct v4l2_subdev_core_ops {
    int (*log_status)(struct v4l2_subdev *sd);
    int (*s_io_pin_config)(struct v4l2_subdev *sd, size_t n, struct v4l2_subdev_io_pin_config *pincfg);
    int (*init)(struct v4l2_subdev *sd, u32 val);
    int (*load_fw)(struct v4l2_subdev *sd);
    int (*reset)(struct v4l2_subdev *sd, u32 val);
    int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
    long (*command)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
    long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
#ifdef CONFIG_COMPAT;
    long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg);
#endif;
#ifdef CONFIG_VIDEO_ADV_DEBUG;
    int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
    int (*s_register)(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg);
#endif;
    int (*s_power)(struct v4l2_subdev *sd, int on);
    int (*interrupt_service_routine)(struct v4l2_subdev *sd, u32 status, bool *handled);
    int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub);
    int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub);
};

成员

log_status

用于 VIDIOC_LOG_STATUS() ioctl 处理程序代码的回调。

s_io_pin_config

为芯片配置一个或多个芯片 I/O 引脚,这些芯片将不同的内部信号 pad 多路复用到 IO 引脚。此函数采用指向 “n” 个引脚配置条目数组的指针,每个引脚配置一个条目。此函数可以在子设备初始化之外的其他时间调用。

init

将传感器寄存器初始化为某种合理的默认值。不要用于新的驱动程序,应在现有驱动程序中删除。

load_fw

加载固件。

reset

通用重置命令。该参数选择要重置的子系统。传递 0 将始终重置整个芯片。没有在 linux-media 邮件列表中首先讨论这一点,不要用于新的驱动程序。通常没有理由重置设备。

s_gpio

设置 GPIO 引脚。现在很简单,如果需要,可能需要用方向参数进行扩展。

command

由内核驱动程序调用,以便调用子设备驱动程序内部的具有单独回调的函数驱动程序。

ioctl

在 V4L2 核心的 ioctl() 系统调用处理程序的末尾调用。用于提供对驱动程序上使用的私有 ioctl 的支持。

compat_ioctl32

当 32 位应用程序使用 64 位内核时调用,以便修复从/到用户空间传递的数据。

g_register

用于 VIDIOC_DBG_G_REGISTER() ioctl 处理程序代码的回调。

s_register

用于 VIDIOC_DBG_S_REGISTER() ioctl 处理程序代码的回调。

s_power

将子设备置于省电模式(on == 0)或正常操作模式(on == 1)。已弃用。请参阅 编写相机传感器驱动程序。pre_streamon 和 post_streamoff 回调可以用于例如在调用 s_stream 之前将总线设置为 LP-11 模式。

interrupt_service_routine

当由于此子设备而引发中断状态时,由桥接芯片的中断服务处理程序调用,以便此子设备可以处理详细信息。它可能会安排稍后执行的工作。它不得睡眠。从 IRQ 上下文中调用

subscribe_event

驱动程序使用它来请求控件框架,以便在控件值更改时收到警告。

unsubscribe_event

从控件框架中删除事件订阅。

struct v4l2_subdev_tuner_ops

在无线电模式下打开 v4l 设备时使用的回调。

定义:

struct v4l2_subdev_tuner_ops {
    int (*standby)(struct v4l2_subdev *sd);
    int (*s_radio)(struct v4l2_subdev *sd);
    int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq);
    int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq);
    int (*enum_freq_bands)(struct v4l2_subdev *sd, struct v4l2_frequency_band *band);
    int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
    int (*s_tuner)(struct v4l2_subdev *sd, const struct v4l2_tuner *vt);
    int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm);
    int (*s_modulator)(struct v4l2_subdev *sd, const struct v4l2_modulator *vm);
    int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type);
    int (*s_config)(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *config);
};

成员

standby

将调谐器置于待机模式。下次使用它时,它将自动唤醒。

s_radio

将调谐器切换到无线电模式的回调。驱动程序应在无线电模式下操作调谐器 ops 时显式调用它,然后才能处理它。用于同时具有 AM/FM 无线电接收器和 TV 的设备。

s_frequency

用于 VIDIOC_S_FREQUENCY() ioctl 处理程序代码的回调。

g_frequency

用于 VIDIOC_G_FREQUENCY() ioctl 处理程序代码的回调。必须填写 freq->type。通常由 video_ioctl2() 或桥接驱动程序完成。

enum_freq_bands

用于 VIDIOC_ENUM_FREQ_BANDS() ioctl 处理程序代码的回调。

g_tuner

用于 VIDIOC_G_TUNER() ioctl 处理程序代码的回调。

s_tuner

用于 VIDIOC_S_TUNER() ioctl 处理程序代码的回调。必须填写 vt->type。通常由 video_ioctl2 或桥接驱动程序完成。

g_modulator

用于 VIDIOC_G_MODULATOR() ioctl 处理程序代码的回调。

s_modulator

用于 VIDIOC_S_MODULATOR() ioctl 处理程序代码的回调。

s_type_addr

设置调谐器类型及其 I2C 地址。

s_config

设置 tda9887 特定内容,如 port1、port2 和 qss

描述

注意

在同时具有 AM/FM 和 TV 的设备上,由驱动程序显式调用 s_radio,以便在处理其他需要它的 struct v4l2_subdev_tuner_ops 之前将调谐器切换到无线电模式。此类用法的示例是

static void s_frequency(void *priv, const struct v4l2_frequency *f)
{
      ...
      if (f.type == V4L2_TUNER_RADIO)
              v4l2_device_call_all(v4l2_dev, 0, tuner, s_radio);
      ...
      v4l2_device_call_all(v4l2_dev, 0, tuner, s_frequency);
}
struct v4l2_subdev_audio_ops

用于音频相关设置的回调

定义:

struct v4l2_subdev_audio_ops {
    int (*s_clock_freq)(struct v4l2_subdev *sd, u32 freq);
    int (*s_i2s_clock_freq)(struct v4l2_subdev *sd, u32 freq);
    int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
    int (*s_stream)(struct v4l2_subdev *sd, int enable);
};

成员

s_clock_freq

设置音频时钟输出的频率(以 Hz 为单位)。用于将音频处理器与视频解码器连接起来,确保音频和视频保持同步。频率的常用值为 48000、44100 或 32000 Hz。如果不支持该频率,则返回 -EINVAL。

s_i2s_clock_freq

以 bps 为单位设置 I2S 速度。这用于提供一种标准方法来选择某些板设计中用于驱动数字音频流的 I2S 时钟。频率的常用值为 1024000 和 2048000。如果不支持该频率,则返回 -EINVAL

s_routing

用于定义音频芯片的输入和/或输出引脚,以及任何其他配置数据。切勿尝试在此级别使用用户级别的输入 ID(例如复合、S-Video、调谐器)。i2c 设备不应该知道输入引脚是否连接到复合连接器,因为在另一个板或平台上,它可能连接到完全不同的东西。调用驱动程序负责将用户级别的输入映射到 i2c 设备上的正确引脚。

s_stream

用于通知音频代码流将开始或已停止。

struct v4l2_mbus_frame_desc_entry_csi2

定义:

struct v4l2_mbus_frame_desc_entry_csi2 {
    u8 vc;
    u8 dt;
};

成员

vc

CSI-2 虚拟通道

dt

CSI-2 数据类型 ID

enum v4l2_mbus_frame_desc_flags

媒体总线帧描述标志

常量

V4L2_MBUS_FRAME_DESC_FL_LEN_MAX

指示 struct v4l2_mbus_frame_desc_entry->length 字段指定最大数据长度。

V4L2_MBUS_FRAME_DESC_FL_BLOB

指示格式没有行偏移量,即接收器应使用 1D DMA。

struct v4l2_mbus_frame_desc_entry

媒体总线帧描述结构

定义:

struct v4l2_mbus_frame_desc_entry {
    enum v4l2_mbus_frame_desc_flags flags;
    u32 stream;
    u32 pixelcode;
    u32 length;
    union {
        struct v4l2_mbus_frame_desc_entry_csi2 csi2;
    } bus;
};

成员

flags

位掩码标志,由 enum v4l2_mbus_frame_desc_flags 定义。

stream

路由配置中的流

pixelcode

媒体总线像素代码,如果未设置 flags FRAME_DESC_FL_BLOB,则有效。

length

每帧的八位字节数,如果设置了 flags V4L2_MBUS_FRAME_DESC_FL_LEN_MAX,则有效。

bus

总线特定帧描述符参数

bus.csi2

CSI-2 特定总线配置

enum v4l2_mbus_frame_desc_type

媒体总线帧描述类型

常量

V4L2_MBUS_FRAME_DESC_TYPE_UNDEFINED

未定义的帧描述类型。驱动程序不应使用此类型,它用于向后兼容。

V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL

并行媒体总线。

V4L2_MBUS_FRAME_DESC_TYPE_CSI2

CSI-2 媒体总线。帧描述参数必须在 struct v4l2_mbus_frame_desc_entry->csi2 中设置。

struct v4l2_mbus_frame_desc

媒体总线数据帧描述

定义:

struct v4l2_mbus_frame_desc {
    enum v4l2_mbus_frame_desc_type type;
    struct v4l2_mbus_frame_desc_entry entry[V4L2_FRAME_DESC_ENTRY_MAX];
    unsigned short num_entries;
};

成员

type

总线类型 (enum v4l2_mbus_frame_desc_type)

entry

帧描述符数组

num_entries

entry 数组中的条目数

enum v4l2_subdev_pre_streamon_flags

用于 pre_streamon 子设备核心 op 的标志

常量

V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP

在调用 s_stream() 之前,将发射器设置为 LP-11 或 LP-111 模式。

struct v4l2_subdev_video_ops

在视频模式下打开 v4l 设备时使用的回调。

定义:

struct v4l2_subdev_video_ops {
    int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
    int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags);
    int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm);
    int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm);
    int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
    int (*g_std_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
    int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
    int (*g_tvnorms)(struct v4l2_subdev *sd, v4l2_std_id *std);
    int (*g_tvnorms_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
    int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
    int (*s_stream)(struct v4l2_subdev *sd, int enable);
    int (*g_pixelaspect)(struct v4l2_subdev *sd, struct v4l2_fract *aspect);
    int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf, unsigned int *size);
    int (*pre_streamon)(struct v4l2_subdev *sd, u32 flags);
    int (*post_streamoff)(struct v4l2_subdev *sd);
};

成员

s_routing

请参阅 audio_ops 中的 s_routing,除了此版本适用于视频设备。

s_crystal_freq

以 Hz 为单位设置用于生成时钟的晶体频率。一个额外的标志字段允许设备进行特定的配置,例如时钟分频器等。如果未使用,则将标志设置为 0。如果不支持该频率,则返回 -EINVAL。

g_std

用于 VIDIOC_G_STD() ioctl 处理程序代码的回调。

s_std

用于 VIDIOC_S_STD() ioctl 处理程序代码的回调。

s_std_output

为视频输出设备设置 v4l2_std_id。视频输入设备会忽略此设置。

g_std_output

获取视频输出设备当前的制式标准。视频输入设备会忽略此设置。

querystd

用于 VIDIOC_QUERYSTD() ioctl 处理程序代码的回调。

g_tvnorms

获取视频采集设备支持的所有制式的 v4l2_std_id。视频输出设备会忽略此设置。

g_tvnorms_output

获取视频输出设备支持的所有制式的 v4l2_std_id。视频采集设备会忽略此设置。

g_input_status

获取输入状态。与 struct v4l2_input 中的 status 字段相同。

s_stream

启动(enabled == 1)或停止(enabled == 0)子设备上的流传输。停止失败将移除流传输启动时获取的任何资源,但驱动程序仍会返回错误代码。调用者应跟踪子设备状态,不应启动或停止已启动或停止的子设备。另请参见 v4l2-subdev.c 中的 call_s_stream 包装器。

此回调已弃用。新的驱动程序应改为实现 v4l2_subdev_pad_ops.enable_streamsv4l2_subdev_pad_ops.disable_streams 操作,并为 v4l2_subdev_video_ops.s_stream 操作使用 v4l2_subdev_s_stream_helper 以支持旧版用户。

驱动程序也不应直接调用 .s_stream() 子设备操作,而应使用 v4l2_subdev_enable_streams()v4l2_subdev_disable_streams() 辅助函数。

g_pixelaspect

返回像素宽高比的回调。

s_rx_buffer

为子设备设置主机分配的内存缓冲区。子设备可以将 size 调整为较低的值,并且从 data 开始,写入缓冲区的数据不得超过 size 的原始值。

pre_streamon

可以在实际开始流传输之前调用,以帮助初始化总线。当前的用法是在流传输之前将 CSI-2 发射器设置为 LP-11 或 LP-111 模式。请参见 enum v4l2_subdev_pre_streamon_flags

如果 pre_streamon 无法执行标志参数指示的操作,则应返回错误。特别是,-EACCES 表示不支持该操作。对于每次成功调用 pre_streamon,调用者都应调用 post_streamoff。

post_streamoff

在停止流传输后调用,但仅当之前调用过 pre_streamon 时才调用。

struct v4l2_subdev_vbi_ops

通过 vbi 设备节点以视频模式打开 v4l 设备时使用的回调。

定义:

struct v4l2_subdev_vbi_ops {
    int (*decode_vbi_line)(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi_line);
    int (*s_vbi_data)(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *vbi_data);
    int (*g_vbi_data)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *vbi_data);
    int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap);
    int (*s_raw_fmt)(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt);
    int (*g_sliced_fmt)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
    int (*s_sliced_fmt)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
};

成员

decode_vbi_line

支持分片 VBI 的视频解码器需要实现此 ioctl。struct v4l2_decode_vbi_line 的字段 p 设置为解码器生成的 VBI 数据的开始位置。然后,驱动程序解析分片 VBI 数据并相应地设置结构中的其他字段。指针 p 更新为指向有效负载的开始位置,可以逐字复制到 struct v4l2_sliced_vbi_data 的 data 字段中。如果没有找到有效的 VBI 数据,则在返回时将 type 字段设置为 0。

s_vbi_data

用于在视频信号上生成 VBI 信号。struct v4l2_sliced_vbi_data 填充了应该输出的数据包。请注意,如果将 line 字段设置为 0,则会禁用该 VBI 信号。如果没有找到有效的 VBI 数据,则在返回时将 type 字段设置为 0。

g_vbi_data

用于从读取回寄存器获取分片 VBI 数据包。并非所有视频解码器都支持此功能。如果由于读取回寄存器包含无效或错误数据而没有可用数据,则返回 -EIO。请注意,您必须填写“id”成员和“field”成员(以确定应获取来自第一个还是第二个字段的 CC 数据)。

g_sliced_vbi_cap

用于 VIDIOC_G_SLICED_VBI_CAP() ioctl 处理程序代码的回调。

s_raw_fmt

为原始 VBI 设置视频编码器/解码器。

g_sliced_fmt

检索当前的分片 VBI 设置。

s_sliced_fmt

设置分片 VBI 设置。

struct v4l2_subdev_sensor_ops

v4l2-subdev 传感器操作

定义:

struct v4l2_subdev_sensor_ops {
    int (*g_skip_top_lines)(struct v4l2_subdev *sd, u32 *lines);
    int (*g_skip_frames)(struct v4l2_subdev *sd, u32 *frames);
};

成员

g_skip_top_lines

要跳过的图像顶部行数。某些传感器需要此设置,这些传感器总是会损坏输出图像的几个顶部行,或者在这些行中发送其元数据。

g_skip_frames

流开始时要跳过的帧数。对于一些有缺陷的传感器,在打开时会生成错误的帧,因此需要此设置。

enum v4l2_subdev_ir_mode

描述了支持的 IR 类型

常量

V4L2_SUBDEV_IR_MODE_PULSE_WIDTH

IR 使用 struct ir_raw_event 记录

struct v4l2_subdev_ir_parameters

用于 IR TX 或 TX 的参数

定义:

struct v4l2_subdev_ir_parameters {
    unsigned int bytes_per_data_element;
    enum v4l2_subdev_ir_mode mode;
    bool enable;
    bool interrupt_enable;
    bool shutdown;
    bool modulation;
    u32 max_pulse_width;
    unsigned int carrier_freq;
    unsigned int duty_cycle;
    bool invert_level;
    bool invert_carrier_sense;
    u32 noise_filter_min_width;
    unsigned int carrier_range_lower;
    unsigned int carrier_range_upper;
    u32 resolution;
};

成员

bytes_per_data_element

读取或写入调用中每个数据元素占用的字节数。

mode

enum v4l2_subdev_ir_mode 定义的 IR 模式。

enable

如果为 true,则设备处于活动状态

interrupt_enable

如果为 true,则启用 IR 中断

shutdown

如果为 true:将硬件设置为低/无功耗模式;false:正常模式

modulation

如果为 true,则使用载波;如果为 false,则使用基带

max_pulse_width

最大脉冲宽度,以纳秒为单位,仅对基带信号有效

carrier_freq

载波频率,以赫兹为单位,仅对调制信号有效

duty_cycle

占空比百分比,仅对调制信号有效

invert_level

反转信号电平

invert_carrier_sense

将 0/space 作为载波突发发送。仅在 TX 中使用。

noise_filter_min_width

有效脉冲的最小时间,以纳秒为单位。仅用于 RX。

carrier_range_lower

较低的载波范围,以赫兹为单位,仅对调制信号有效。仅用于 RX。

carrier_range_upper

较高的载波范围,以赫兹为单位,仅对调制信号有效。仅用于 RX。

resolution

接收分辨率,以纳秒为单位。仅用于 RX。

struct v4l2_subdev_ir_ops

用于 IR 子设备的操作

定义:

struct v4l2_subdev_ir_ops {
    int (*rx_read)(struct v4l2_subdev *sd, u8 *buf, size_t count, ssize_t *num);
    int (*rx_g_parameters)(struct v4l2_subdev *sd, struct v4l2_subdev_ir_parameters *params);
    int (*rx_s_parameters)(struct v4l2_subdev *sd, struct v4l2_subdev_ir_parameters *params);
    int (*tx_write)(struct v4l2_subdev *sd, u8 *buf, size_t count, ssize_t *num);
    int (*tx_g_parameters)(struct v4l2_subdev *sd, struct v4l2_subdev_ir_parameters *params);
    int (*tx_s_parameters)(struct v4l2_subdev *sd, struct v4l2_subdev_ir_parameters *params);
};

成员

rx_read

读取接收到的代码或脉冲宽度数据。语义与非阻塞 read() 调用类似。

rx_g_parameters

获取 IR 接收器的当前操作参数和状态。

rx_s_parameters

设置 IR 接收器的当前操作参数和状态。建议首先调用 [rt]x_g_parameters 来填写当前状态,然后只更改需要更改的字段。返回时,将返回实际的设备操作参数和状态。请注意,硬件限制可能会阻止实际设置与请求的设置匹配 - 例如,当请求 36,000 Hz 时,实际载波设置为 35,904 Hz。例外情况是 shutdown 参数为 true。将返回上次使用的操作参数,但硬件的实际状态可能不同,以最大限度地减少功耗和处理(当 shutdown 为 true 时)。

tx_write

写入代码或脉冲宽度数据以进行传输。语义与非阻塞 write() 调用类似。

tx_g_parameters

获取 IR 发射器的当前操作参数和状态。

tx_s_parameters

设置 IR 发射器的当前操作参数和状态。建议首先调用 [rt]x_g_parameters 来填写当前状态,然后只更改需要更改的字段。返回时,将返回实际的设备操作参数和状态。请注意,硬件限制可能会阻止实际设置与请求的设置匹配 - 例如,当请求 36,000 Hz 时,实际载波设置为 35,904 Hz。例外情况是 shutdown 参数为 true。将返回上次使用的操作参数,但硬件的实际状态可能不同,以最大限度地减少功耗和处理(当 shutdown 为 true 时)。

struct v4l2_subdev_pad_config

用于存储 subdev pad 信息。

定义:

struct v4l2_subdev_pad_config {
    struct v4l2_mbus_framefmt format;
    struct v4l2_rect crop;
    struct v4l2_rect compose;
    struct v4l2_fract interval;
};

成员

format

struct v4l2_mbus_framefmt

crop

用于裁剪的 struct v4l2_rect

compose

用于合成的 struct v4l2_rect

interval

帧间隔

struct v4l2_subdev_stream_config

用于存储流配置。

定义:

struct v4l2_subdev_stream_config {
    u32 pad;
    u32 stream;
    bool enabled;
    struct v4l2_mbus_framefmt fmt;
    struct v4l2_rect crop;
    struct v4l2_rect compose;
    struct v4l2_fract interval;
};

成员

pad

pad 编号

stream

stream number

enabled

是否已使用 v4l2_subdev_enable_streams() 启用流

fmt

struct v4l2_mbus_framefmt

crop

用于裁剪的 struct v4l2_rect

compose

用于合成的 struct v4l2_rect

interval

帧间隔

描述

此结构存储流的配置。

struct v4l2_subdev_stream_configs

流配置的集合。

定义:

struct v4l2_subdev_stream_configs {
    u32 num_configs;
    struct v4l2_subdev_stream_config *configs;
};

成员

num_configs

config 中的条目数。

configs

struct v4l2_subdev_stream_configs 的数组。

struct v4l2_subdev_krouting

subdev 路由表

定义:

struct v4l2_subdev_krouting {
    unsigned int len_routes;
    unsigned int num_routes;
    struct v4l2_subdev_route *routes;
};

成员

len_routes

routes 数组的长度,以路由为单位

num_routes

路由数

routes

struct v4l2_subdev_route

描述

此结构包含子设备的路由表。

struct v4l2_subdev_state

用于存储 subdev 状态信息。

定义:

struct v4l2_subdev_state {
    struct mutex _lock;
    struct mutex *lock;
    struct v4l2_subdev *sd;
    struct v4l2_subdev_pad_config *pads;
    struct v4l2_subdev_krouting routing;
    struct v4l2_subdev_stream_configs stream_configs;
};

成员

_lock

“锁”的默认值

lock

状态的互斥锁。可以由用户替换。

sd

状态相关的子设备

pads

struct v4l2_subdev_pad_config 数组

routing

子设备的路由表

stream_configs

流配置(仅适用于 V4L2_SUBDEV_FL_STREAMS)

描述

只有在主参数的“which”字段设置为 V4L2_SUBDEV_FORMAT_TRY 时,才需要将此结构传递给 pad 操作。对于 V4L2_SUBDEV_FORMAT_ACTIVE,传递 NULL 是安全的。

struct v4l2_subdev_pad_ops

v4l2-subdev pad 级别操作

定义:

struct v4l2_subdev_pad_ops {
    int (*enum_mbus_code)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_mbus_code_enum *code);
    int (*enum_frame_size)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_frame_size_enum *fse);
    int (*enum_frame_interval)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_frame_interval_enum *fie);
    int (*get_fmt)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_format *format);
    int (*set_fmt)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_format *format);
    int (*get_selection)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_selection *sel);
    int (*set_selection)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_selection *sel);
    int (*get_frame_interval)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_frame_interval *interval);
    int (*set_frame_interval)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, struct v4l2_subdev_frame_interval *interval);
    int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
    int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
    int (*s_dv_timings)(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings);
    int (*g_dv_timings)(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings);
    int (*query_dv_timings)(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings);
    int (*dv_timings_cap)(struct v4l2_subdev *sd, struct v4l2_dv_timings_cap *cap);
    int (*enum_dv_timings)(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *timings);
#ifdef CONFIG_MEDIA_CONTROLLER;
    int (*link_validate)(struct v4l2_subdev *sd, struct media_link *link,struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt);
#endif ;
    int (*get_frame_desc)(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_frame_desc *fd);
    int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_frame_desc *fd);
    int (*get_mbus_config)(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_config *config);
    int (*set_routing)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state,enum v4l2_subdev_format_whence which, struct v4l2_subdev_krouting *route);
    int (*enable_streams)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, u32 pad, u64 streams_mask);
    int (*disable_streams)(struct v4l2_subdev *sd,struct v4l2_subdev_state *state, u32 pad, u64 streams_mask);
};

成员

enum_mbus_code

用于 VIDIOC_SUBDEV_ENUM_MBUS_CODE() ioctl 处理程序代码的回调。

enum_frame_size

用于 VIDIOC_SUBDEV_ENUM_FRAME_SIZE() ioctl 处理程序代码的回调。

enum_frame_interval

用于 VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL() ioctl 处理程序代码的回调。

get_fmt

用于 VIDIOC_SUBDEV_G_FMT() ioctl 处理程序代码的回调。

set_fmt

用于 VIDIOC_SUBDEV_S_FMT() ioctl 处理程序代码的回调。

get_selection

用于 VIDIOC_SUBDEV_G_SELECTION() ioctl 处理程序代码的回调。

set_selection

用于 VIDIOC_SUBDEV_S_SELECTION() ioctl 处理程序代码的回调。

get_frame_interval

用于 VIDIOC_SUBDEV_G_FRAME_INTERVAL() ioctl 处理程序代码的回调。

set_frame_interval

用于 VIDIOC_SUBDEV_S_FRAME_INTERVAL() ioctl 处理程序代码的回调。

get_edid

用于 VIDIOC_SUBDEV_G_EDID() ioctl 处理程序代码的回调。

set_edid

用于 VIDIOC_SUBDEV_S_EDID() ioctl 处理程序代码的回调。

s_dv_timings

在子设备中设置自定义 dv 时序。当子设备能够在硬件中设置详细的时序信息以生成/检测视频信号时,将使用此功能。

g_dv_timings

在子设备中获取自定义 dv 时序。

query_dv_timings

用于 VIDIOC_QUERY_DV_TIMINGS() ioctl 处理程序代码的回调。

dv_timings_cap

用于 VIDIOC_SUBDEV_DV_TIMINGS_CAP() ioctl 处理程序代码的回调。

enum_dv_timings

用于 VIDIOC_SUBDEV_ENUM_DV_TIMINGS() ioctl 处理程序代码的回调。

link_validate

由媒体控制器代码使用,以检查属于管道的链接是否可用于流传输。

get_frame_desc

获取当前的低级别媒体总线帧参数。

set_frame_desc

设置低级别媒体总线帧参数,fd 数组可以由 subdev 驱动程序调整到设备功能。

get_mbus_config

获取远程子设备的媒体总线配置。媒体总线配置通常在子设备探测时从固件接口检索,立即应用于硬件,并最终由驱动程序调整。远程子设备(通常是视频接收器)应使用此操作来查询发送端总线配置,以便相应地调整自己的总线配置。调用者应确保他们从远程端获取尽可能最新的配置,可能会尽可能接近流传输时间调用此操作。如果已调用的 pad 索引无效或发生不可恢复的故障,则该操作将失败。在调用操作之前,已将 config 参数 memset 为 0。

set_routing

启用或禁用子设备路由表中描述的数据连接路由。实现此操作的 Subdevs 必须设置 V4L2_SUBDEV_FL_STREAMS 标志。

enable_streams

在给定的源 pad 上启用 streams_mask 中定义的流。实现此操作的 Subdevs 必须使用 subdev 核心提供的活动状态管理(通过在初始化时调用 v4l2_subdev_init_finalize() 启用)。不要直接调用,请改用 v4l2_subdev_enable_streams()

如果驱动程序仅支持单个流而不设置 V4L2_SUBDEV_CAP_STREAMS 子设备功能标志,则可以忽略 mask 参数。

disable_streams

在给定的源 pad 上禁用 streams_mask 中定义的流。实现此操作的 Subdevs 必须使用 subdev 核心提供的活动状态管理(通过在初始化时调用 v4l2_subdev_init_finalize() 启用)。不要直接调用,请改用 v4l2_subdev_disable_streams()

如果驱动程序仅支持单个流而不设置 V4L2_SUBDEV_CAP_STREAMS 子设备功能标志,则可以忽略 mask 参数。

struct v4l2_subdev_ops

Subdev 操作

定义:

struct v4l2_subdev_ops {
    const struct v4l2_subdev_core_ops       *core;
    const struct v4l2_subdev_tuner_ops      *tuner;
    const struct v4l2_subdev_audio_ops      *audio;
    const struct v4l2_subdev_video_ops      *video;
    const struct v4l2_subdev_vbi_ops        *vbi;
    const struct v4l2_subdev_ir_ops         *ir;
    const struct v4l2_subdev_sensor_ops     *sensor;
    const struct v4l2_subdev_pad_ops        *pad;
};

成员

core

指向 struct v4l2_subdev_core_ops 的指针。可以为 NULL

tuner

指向 struct v4l2_subdev_tuner_ops 的指针。可以为 NULL

audio

指向 struct v4l2_subdev_audio_ops 的指针。可以为 NULL

video

指向 struct v4l2_subdev_video_ops 的指针。可以为 NULL

vbi

指向 struct v4l2_subdev_vbi_ops 的指针。可以为 NULL

ir

指向 struct v4l2_subdev_ir_ops 的指针。可以为 NULL

sensor

指向 struct v4l2_subdev_sensor_ops 的指针。可以为 NULL

pad

指向 struct v4l2_subdev_pad_ops 的指针。可以为 NULL

struct v4l2_subdev_internal_ops

V4L2 subdev 内部操作

定义:

struct v4l2_subdev_internal_ops {
    int (*init_state)(struct v4l2_subdev *sd, struct v4l2_subdev_state *state);
    int (*registered)(struct v4l2_subdev *sd);
    void (*unregistered)(struct v4l2_subdev *sd);
    int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
    int (*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
    void (*release)(struct v4l2_subdev *sd);
};

成员

init_state

将 subdev 状态初始化为默认值

registered

在此 subdev 注册时调用。调用时,v4l2_dev 字段设置为正确的 v4l2_device。

unregistered

在此 subdev 注销时调用。调用时,v4l2_dev 字段仍设置为正确的 v4l2_device。

open

当应用程序打开 subdev 设备节点时调用。

close

当 subdev 设备节点关闭时调用。请注意,可能在 unregistered 之后调用 close

release

当 subdev 设备的最后一个用户消失时调用。这发生在 unregistered 回调之后,并且当 v4l-subdevX 设备节点的最后一个打开的文件句柄关闭时。如果没有为此子设备创建设备节点,则在 unregistered 回调之后立即调用 release 回调。release 回调通常用于释放包含 v4l2_subdev 结构的内存。对于设置 V4L2_SUBDEV_FL_HAS_DEVNODE 标志的任何子设备,几乎肯定需要此回调。

描述

注意

永远不要从驱动程序中调用此函数,只有 v4l2 框架可以调用这些操作。

struct v4l2_subdev_platform_data

regulators 配置结构

定义:

struct v4l2_subdev_platform_data {
    struct regulator_bulk_data *regulators;
    int num_regulators;
    void *host_priv;
};

成员

regulators

用于打开/关闭 subdevice 的可选 regulators

num_regulators

Regululators 的数量

host_priv

每个子设备的数据,特定于某个视频主机设备

struct v4l2_subdev

描述 V4L2 子设备

定义:

struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER);
    struct media_entity entity;
#endif;
    struct list_head list;
    struct module *owner;
    bool owner_v4l2_dev;
    u32 flags;
    struct v4l2_device *v4l2_dev;
    const struct v4l2_subdev_ops *ops;
    const struct v4l2_subdev_internal_ops *internal_ops;
    struct v4l2_ctrl_handler *ctrl_handler;
    char name[52];
    u32 grp_id;
    void *dev_priv;
    void *host_priv;
    struct video_device *devnode;
    struct device *dev;
    struct fwnode_handle *fwnode;
    struct list_head async_list;
    struct list_head async_subdev_endpoint_list;
    struct v4l2_async_notifier *subdev_notifier;
    struct list_head asc_list;
    struct v4l2_subdev_platform_data *pdata;
    struct mutex *state_lock;
    struct led_classdev *privacy_led;
    struct v4l2_subdev_state *active_state;
    u64 enabled_pads;
    bool s_stream_enabled;
};

成员

entity

指向 struct media_entity 的指针

list

子设备列表

owner

所有者与驱动程序的 struct device 所有者相同。

owner_v4l2_dev

如果 sd->ownerv4l2_dev->dev 所有者的所有者匹配,则为 true。由 v4l2_device_register_subdev() 初始化。

flags

subdev 标志。可以是:V4L2_SUBDEV_FL_IS_I2C - 如果此 subdev 是 i2c 设备,则设置此标志;V4L2_SUBDEV_FL_IS_SPI - 如果此 subdev 是 spi 设备,则设置此标志;V4L2_SUBDEV_FL_HAS_DEVNODE - 如果此 subdev 需要设备节点,则设置此标志;V4L2_SUBDEV_FL_HAS_EVENTS - 如果此 subdev 生成事件,则设置此标志。

v4l2_dev

指向 struct v4l2_device 的指针

ops

指向 struct v4l2_subdev_ops 的指针

internal_ops

指向 struct v4l2_subdev_internal_ops 的指针。永远不要从驱动程序中调用这些内部操作!

ctrl_handler

此 subdev 的控制处理程序。可以为 NULL。

name

Sub-device 的名称。请注意,名称必须是唯一的。

grp_id

可用于对类似的 subdevs 进行分组。值是特定于驱动程序的

dev_priv

指向私有数据的指针

host_priv

指向设备附加的 subdev 使用的私有数据的指针。

devnode

subdev 设备节点

dev

指向物理设备的指针(如果有)

fwnode

subdev 的 fwnode_handle,通常与 dev->of_node->fwnode 或 dev->fwnode 相同(以非 NULL 者为准)。

async_list

将此 subdev 链接到全局 subdev_list 或 notifier->done_list 列表。

async_subdev_endpoint_list

struct v4l2_async_subdev_endpoint 的 async_subdev_endpoint_entry 中的列表条目。

subdev_notifier

使用 v4l2_async_register_subdev_sensor() 为 sub- device 隐式注册的子设备通知程序。

asc_list

异步连接列表,struct v4l2_async_connection.subdev_entry。

pdata

subdevice 平台数据的公共部分

state_lock

指向用于所有 subdev 状态的锁的指针,由驱动程序设置。这是可选的。如果为 NULL,则每个状态实例将获得自己的锁。

privacy_led

指向传感器隐私 LED 的 LED classdev 的可选指针。

active_state

subdev 的活动状态(对于内部跟踪状态的 subdevs,为 NULL)。通过调用 v4l2_subdev_init_finalize() 初始化。

enabled_pads

v4l2_subdev_enable_streams()v4l2_subdev_disable_streams() 辅助函数(用于回退情况)使用的已启用 pads 的位掩码。

s_stream_enabled

跟踪是否已使用 s_stream 启用流传输。这仅用于 call_s_stream() 内部使用。

描述

subdev 驱动程序的每个实例都应创建此结构,无论是独立的还是嵌入在更大的结构中。

此结构应由 v4l2_subdev_init() 或其变体之一初始化:v4l2_spi_subdev_init()v4l2_i2c_subdev_init()

media_entity_to_v4l2_subdev

media_entity_to_v4l2_subdev (ent)

从嵌入的 struct media_entity 返回 struct v4l2_subdev

Parameters

ent

指向 struct media_entity 的指针。

vdev_to_v4l2_subdev

vdev_to_v4l2_subdev (vdev)

从嵌入它的 struct video_device 返回 struct v4l2_subdev

Parameters

vdev

指向 struct video_device 的指针

struct v4l2_subdev_fh

用于存储每个文件句柄的 subdev 信息

定义:

struct v4l2_subdev_fh {
    struct v4l2_fh vfh;
    struct module *owner;
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API);
    struct v4l2_subdev_state *state;
    u64 client_caps;
#endif;
};

成员

vfh

指向 struct v4l2_fh 的指针

owner

指向此文件句柄所有者的模块指针

state

指向 struct v4l2_subdev_state 的指针

client_caps

V4L2_SUBDEV_CLIENT_CAP_* 的位掩码

to_v4l2_subdev_fh

to_v4l2_subdev_fh (fh)

从嵌入它的 struct v4l2_fh 返回 struct v4l2_subdev_fh

Parameters

fh

指向 struct v4l2_fh 的指针

void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)

设置 V4L2 dev 私有设备数据

Parameters

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

void *p

指向要存储的私有设备数据的指针。

void *v4l2_get_subdevdata(const struct v4l2_subdev *sd)

获取 V4L2 dev 私有设备数据

Parameters

const struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

描述

返回指向要存储的私有设备数据的指针。

void v4l2_set_subdev_hostdata(struct v4l2_subdev *sd, void *p)

设置 V4L2 dev 私有主机数据

Parameters

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

void *p

指向要存储的私有数据的指针。

void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)

获取 V4L2 dev 私有数据

Parameters

const struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

描述

返回指向要存储的私有主机数据的指针。

int v4l2_subdev_get_fwnode_pad_1_to_1(struct media_entity *entity, struct fwnode_endpoint *endpoint)

从 subdev fwnode 端点获取 pad 编号,假设 1:1 端口:pad

Parameters

struct media_entity *entity

指向 subdev 实体的指针

struct fwnode_endpoint *endpoint

指向已解析的 fwnode 端点的指针

描述

对于将端口号和 pad 索引 1:1 映射的子设备,此函数可以用作 .get_fwnode_pad 操作。 如果端点由子设备拥有,则该函数返回端点端口号。

成功时返回端点端口号,否则返回负错误代码。

验证媒体链接

Parameters

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

struct media_link *link

指向 struct media_link 的指针

struct v4l2_subdev_format *source_fmt

指向 struct v4l2_subdev_format 的指针

struct v4l2_subdev_format *sink_fmt

指向 struct v4l2_subdev_format 的指针

描述

此函数确保链接的源和目标上的宽度、高度和媒体总线像素代码相等。

验证媒体链接

Parameters

struct media_link *link

指向 struct media_link 的指针

描述

此函数调用 subdev 的 link_validate ops 来验证媒体链接是否对流式传输有效。 它还在内部调用 v4l2_subdev_link_validate_default() 以确保链接的源和目标上的宽度、高度和媒体总线像素代码相等。

该函数可用作 v4l2_subdev 实例的直接 media_entity_ops.link_validate 实现。 它支持子设备之间的所有链接,以及子设备和视频设备之间的链接,前提是视频设备也实现了它们的 media_entity_ops.link_validate 操作。

bool v4l2_subdev_has_pad_interdep(struct media_entity *entity, unsigned int pad0, unsigned int pad1)

子设备的 MC has_pad_interdep 实现

Parameters

struct media_entity *entity

指向 struct media_entity 的指针

unsigned int pad0

第一个 pad 的 pad 编号

unsigned int pad1

第二个 pad 的 pad 编号

描述

此函数是 media_entity_operations.has_pad_interdep 操作的实现,适用于实现多路复用流 API 的子设备(如 V4L2_SUBDEV_FL_STREAMS 子设备标志所示)。

如果 pad0 和 pad1 之间存在活动路由,则它认为两个 pad 是相互依赖的。

struct v4l2_subdev_state *__v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name, struct lock_class_key *key)

分配 v4l2_subdev_state

Parameters

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针,为其分配状态。

const char *lock_name

状态锁的名称

struct lock_class_key *key

锁的 lock_class_key

描述

当不再需要状态时,必须调用 __v4l2_subdev_state_free()

不要由驱动程序直接调用。

void __v4l2_subdev_state_free(struct v4l2_subdev_state *state)

释放 v4l2_subdev_state

Parameters

struct v4l2_subdev_state *state

要释放的 v4l2_subdev_state。

描述

不要由驱动程序直接调用。

v4l2_subdev_init_finalize

v4l2_subdev_init_finalize (sd)

完成子设备的初始化

Parameters

sd

子设备

描述

此函数完成子设备的初始化,包括为子设备分配活动状态。

在使用集中式活动状态的子设备驱动程序初始化 subdev struct 并调用 media_entity_pads_init() 之后,但在注册 subdev 之前,必须调用此函数。

在删除子设备时,用户必须调用 v4l2_subdev_cleanup()

void v4l2_subdev_cleanup(struct v4l2_subdev *sd)

释放子设备分配的资源

Parameters

struct v4l2_subdev *sd

子设备

描述

清除 V4L2 异步子设备。 如果资源已使用 v4l2_async_subdev_endpoint_add()v4l2_subdev_init_finalize() 与之关联,则必须在释放子设备时调用此函数。

v4l2_subdev_state_get_format

v4l2_subdev_state_get_format (state, pad, ...)

获取指向流格式的指针

Parameters

state

子设备状态

pad

pad id

...

流 id(可选参数)

描述

这会为子设备状态中给定的 pad + 流返回指向 struct v4l2_mbus_framefmt 的指针。

对于不知道流的驱动程序,会返回相应 pad 的格式。 如果 pad 不存在,则返回 NULL。

v4l2_subdev_state_get_crop

v4l2_subdev_state_get_crop (state, pad, ...)

获取指向流裁剪矩形的指针

Parameters

state

子设备状态

pad

pad id

...

流 id(可选参数)

描述

这会为子设备状态中给定的 pad + 流返回指向裁剪矩形的指针。

对于不知道流的驱动程序,会返回相应 pad 的裁剪矩形。 如果 pad 不存在,则返回 NULL。

v4l2_subdev_state_get_compose

v4l2_subdev_state_get_compose (state, pad, ...)

获取指向流合成矩形的指针

Parameters

state

子设备状态

pad

pad id

...

流 id(可选参数)

描述

这会为子设备状态中给定的 pad + 流返回指向合成矩形的指针。

对于不知道流的驱动程序,会返回相应 pad 的合成矩形。 如果 pad 不存在,则返回 NULL。

v4l2_subdev_state_get_interval

v4l2_subdev_state_get_interval (state, pad, ...)

获取指向流帧间隔的指针

Parameters

state

子设备状态

pad

pad id

...

流 id(可选参数)

描述

这会为子设备状态中给定的 pad + 流返回指向帧间隔的指针。

对于不知道流的驱动程序,会返回相应 pad 的帧间隔。 如果 pad 不存在,则返回 NULL。

int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *format)

基于状态填充格式

Parameters

struct v4l2_subdev *sd

子设备

struct v4l2_subdev_state *state

子设备状态

struct v4l2_subdev_format *format

指向 struct v4l2_subdev_format 的指针

描述

基于 format 结构中的信息填充 format->format 字段。

如果 subdev 驱动程序不需要在其 get_fmt op 中执行任何特殊操作,则支持活动状态的 subdev 驱动程序可以使用此函数来实现 v4l2_subdev_pad_ops.get_fmt。

成功时返回 0,否则返回错误值。

int v4l2_subdev_get_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_frame_interval *fi)

基于状态填充帧间隔

Parameters

struct v4l2_subdev *sd

子设备

struct v4l2_subdev_state *state

子设备状态

struct v4l2_subdev_frame_interval *fi

指向 struct v4l2_subdev_frame_interval 的指针

描述

基于 fi 结构中的信息填充 fi->interval 字段。

如果 subdev 驱动程序不需要在其 get_frame_interval op 中执行任何特殊操作,则支持活动状态的 subdev 驱动程序可以使用此函数来实现 v4l2_subdev_pad_ops.get_frame_interval。

成功时返回 0,否则返回错误值。

int v4l2_subdev_set_routing(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, const struct v4l2_subdev_krouting *routing)

将给定路由设置为 subdev 状态

Parameters

struct v4l2_subdev *sd

子设备

struct v4l2_subdev_state *state

子设备状态

const struct v4l2_subdev_krouting *routing

将复制到 subdev 状态的路由

描述

这将从状态中释放旧路由表(如果存在),为给定路由分配足够的空间,并复制路由。

这可以从 subdev 驱动程序的 set_routing op 中使用,在验证路由之后。

for_each_active_route

for_each_active_route (routing, route)

迭代路由表的所有活动路由

Parameters

routing

路由表

route

路由迭代器

int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, const struct v4l2_subdev_krouting *routing, const struct v4l2_mbus_framefmt *fmt)

将给定的路由和格式设置为 subdev 状态

Parameters

struct v4l2_subdev *sd

子设备

struct v4l2_subdev_state *state

子设备状态

const struct v4l2_subdev_krouting *routing

将复制到 subdev 状态的路由

const struct v4l2_mbus_framefmt *fmt

用于初始化所有流的格式

描述

这与 v4l2_subdev_set_routing 相同,但还会使用给定的格式初始化所有流。

int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing, u32 pad, u32 stream, u32 *other_pad, u32 *other_stream)

查找相反的流

Parameters

const struct v4l2_subdev_krouting *routing

用于查找另一侧的路由

u32 pad

pad id

u32 stream

流 id

u32 *other_pad

用于返回相反 pad 的指针

u32 *other_stream

用于返回相反流的指针

描述

此函数使用路由表查找与给定 pad + 流相反的 pad + 流。

如果调用方不需要该值,则 other_pad 和/或 other_stream 可以为 NULL。

成功时返回 0,如果未找到匹配的路由,则返回 -EINVAL。

struct v4l2_mbus_framefmt *v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state, u32 pad, u32 stream)

获取指向相反流格式的指针

Parameters

struct v4l2_subdev_state *state

子设备状态

u32 pad

pad id

u32 stream

流 id

描述

这会为子设备状态中与给定 pad + 流相反的 pad + 流返回指向 struct v4l2_mbus_framefmt 的指针。

如果状态不包含给定的 pad + 流,则返回 NULL。

u64 v4l2_subdev_state_xlate_streams(const struct v4l2_subdev_state *state, u32 pad0, u32 pad1, u64 *streams)

将流从一个 pad 转换为另一个 pad

Parameters

const struct v4l2_subdev_state *state

子设备状态

u32 pad0

第一个 pad

u32 pad1

第二个 pad

u64 *streams

第一个 pad 上的流位掩码

描述

subdev 的 sink pad 上的流根据 subdev 状态路由表中的表达式路由到源 pad。 流编号在路由的 sink 和源侧不一定匹配。 此函数使用 state 中的路由表将 pad0 上的流(表示为 streams 中的位掩码)转换为 pad1 上的相应流。 它返回 pad1 上的流掩码,并使用在路由表中找到的流更新 streams

pad0pad1 必须是 sink 和源,顺序不限。

返回

路由到 pad0 上的 streamspad1 的流的位掩码。

enum v4l2_subdev_routing_restriction

子设备内部路由限制

常量

V4L2_SUBDEV_ROUTING_NO_1_TO_N

输入流不应路由到多个输出流(流重复)

V4L2_SUBDEV_ROUTING_NO_N_TO_1

多个输入流不应路由到同一个输出流(流合并)

V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX

来自 sink pad 的所有流必须路由到单个源 pad

V4L2_SUBDEV_ROUTING_NO_SOURCE_STREAM_MIX

源 pad 上的所有流必须源自单个 sink pad

V4L2_SUBDEV_ROUTING_NO_SINK_MULTIPLEXING

sink pad 不应包含多路复用流

V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING

源 pad 不应包含多路复用流

V4L2_SUBDEV_ROUTING_ONLY_1_TO_1

仅允许非重叠的 1 对 1 流路由(V4L2_SUBDEV_ROUTING_NO_1_TO_NV4L2_SUBDEV_ROUTING_NO_N_TO_1 的组合)

V4L2_SUBDEV_ROUTING_NO_STREAM_MIX

来自 sink pad 的所有流必须路由到单个源 pad,并且该源 pad 不应从任何其他 sink pad 获取路由(V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIXV4L2_SUBDEV_ROUTING_NO_SOURCE_STREAM_MIX 的组合)

V4L2_SUBDEV_ROUTING_NO_MULTIPLEXING

在源端或 sink 端都不允许使用多路复用流。

int v4l2_subdev_routing_validate(struct v4l2_subdev *sd, const struct v4l2_subdev_krouting *routing, enum v4l2_subdev_routing_restriction disallow)

验证路由是否符合驱动程序约束

Parameters

struct v4l2_subdev *sd

子设备

const struct v4l2_subdev_krouting *routing

要验证的路由

enum v4l2_subdev_routing_restriction disallow

路由限制

描述

这会验证给定的路由是否符合 disallow 约束。

成功时返回 0,否则返回错误值。

int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad, u64 streams_mask)

在 pad 上启用流

Parameters

struct v4l2_subdev *sd

子设备

u32 pad

pad

u64 streams_mask

要启用的流的位掩码

描述

此函数在子设备的源 pad 上启用流。 pad 由其索引标识,而流由 streams_mask 位掩码标识。 这允许一次在 pad 上启用多个流。

不允许启用已启用的流。 如果 streams_mask 包含已启用的流,则此函数将返回 -EALREADY,而不执行任何操作。

每个流启用仅适用于实现 .enable_streams() 和 .disable_streams() 操作的子设备。 对于其他子设备,此函数通过调用 .s_stream() 操作来实现最大程度的兼容性,该操作仅限于具有单个源 pad 的子设备。

不知道流的驱动程序应将 streams_mask 设置为 BIT_ULL(0)。

返回

  • 0:成功

  • -EALREADY:streams_mask 中的一个流已启用

  • -EINVAL: pad 索引无效,或者不对应于源 pad

  • -EOPNOTSUPP: 无法回退到旧的 .s_stream() 操作,因为 subdev 有多个源 pad

int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad, u64 streams_mask)

禁用 pad 上的流

Parameters

struct v4l2_subdev *sd

子设备

u32 pad

pad

u64 streams_mask

要禁用的流的位掩码

描述

此函数禁用子设备的源 pad 上的流。 pad 由其索引标识,而流由 streams_mask 位掩码标识。这允许一次禁用 pad 上的多个流。

不允许禁用未启用的流。如果 streams_mask 包含禁用的流,则此函数返回 -EALREADY 而不执行任何操作。

每个流的禁用仅适用于实现 .enable_streams() 和 .disable_streams() 操作的 subdev。对于其他 subdev,此函数通过调用 .s_stream() 操作来实现尽力而为的兼容性,仅限于具有单个源 pad 的 subdev。

不知道流的驱动程序应将 streams_mask 设置为 BIT_ULL(0)。

返回

  • 0:成功

  • -EALREADY: streams_mask 中的一个流未启用

  • -EINVAL: pad 索引无效,或者不对应于源 pad

  • -EOPNOTSUPP: 无法回退到旧的 .s_stream() 操作,因为 subdev 有多个源 pad

int v4l2_subdev_s_stream_helper(struct v4l2_subdev *sd, int enable)

使用 enable_streams 和 disable_streams 实现 subdev s_stream 操作的辅助函数

Parameters

struct v4l2_subdev *sd

子设备

int enable

启用或禁用流式传输

描述

实现流感知的 v4l2_subdev_pad_ops.enable_streamsv4l2_subdev_pad_ops.disable_streams 操作的子设备驱动程序可以使用此辅助函数来实现旧的 v4l2_subdev_video_ops.s_stream 操作。

此辅助函数只能由具有单个源 pad 的 subdev 使用。

返回

成功时为 0,否则为负错误代码。

void v4l2_subdev_lock_state(struct v4l2_subdev_state *state)

锁定 subdev 状态

Parameters

struct v4l2_subdev_state *state

子设备状态

描述

锁定给定的 subdev 状态。

使用后必须使用 v4l2_subdev_unlock_state() 解锁该状态。

void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state)

解锁 subdev 状态

Parameters

struct v4l2_subdev_state *state

子设备状态

描述

解锁给定的 subdev 状态。

void v4l2_subdev_lock_states(struct v4l2_subdev_state *state1, struct v4l2_subdev_state *state2)

锁定两个子设备状态

Parameters

struct v4l2_subdev_state *state1

一个子设备状态

struct v4l2_subdev_state *state2

另一个子设备状态

描述

锁定两个子设备的状态。

使用后必须使用 v4l2_subdev_unlock_states() 解锁这些状态。

这不同于对两个状态都调用 v4l2_subdev_lock_state(),这样如果状态共享同一个锁,则锁只会被获取一次(因此不会发生死锁)。调用者负责确保锁将始终以相同的顺序获取。

void v4l2_subdev_unlock_states(struct v4l2_subdev_state *state1, struct v4l2_subdev_state *state2)

解锁两个子设备状态

Parameters

struct v4l2_subdev_state *state1

一个子设备状态

struct v4l2_subdev_state *state2

另一个子设备状态

描述

解锁两个子设备的状态。

这不同于对两个状态都调用 v4l2_subdev_unlock_state(),这样如果状态共享同一个锁,则锁只会被释放一次。

struct v4l2_subdev_state *v4l2_subdev_get_unlocked_active_state(struct v4l2_subdev *sd)

检查活动 subdev 状态是否已解锁并返回它

Parameters

struct v4l2_subdev *sd

子设备

描述

返回子设备的活动状态,如果 subdev 不支持活动状态,则返回 NULL。如果状态不为 NULL,则调用 lockdep_assert_not_held() 以在状态被锁定时发出警告。

此函数用于例如当获取活动状态仅用于向前传递而无需访问状态字段时。

struct v4l2_subdev_state *v4l2_subdev_get_locked_active_state(struct v4l2_subdev *sd)

检查活动 subdev 状态是否已锁定并返回它

Parameters

struct v4l2_subdev *sd

子设备

描述

返回子设备的活动状态,如果 subdev 不支持活动状态,则返回 NULL。如果状态不为 NULL,则调用 lockdep_assert_held() 以在状态未锁定时发出警告。

当调用者知道活动状态已被锁定时,应使用此函数。

struct v4l2_subdev_state *v4l2_subdev_lock_and_get_active_state(struct v4l2_subdev *sd)

锁定并返回子设备的活动 subdev 状态

Parameters

struct v4l2_subdev *sd

子设备

描述

返回子设备的锁定的活动状态,如果 subdev 不支持活动状态,则返回 NULL。

使用后必须使用 v4l2_subdev_unlock_state() 解锁该状态。

void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)

初始化子设备结构

Parameters

struct v4l2_subdev *sd

指向要初始化的 struct v4l2_subdev 的指针

const struct v4l2_subdev_ops *ops

指向 struct v4l2_subdev_ops 的指针。

v4l2_subdev_call

v4l2_subdev_call (sd, o, f, args...)

调用 v4l2_subdev 的操作。

Parameters

sd

指向 struct v4l2_subdev 的指针

o

包含 fstruct v4l2_subdev_ops 中元素的名称。那里的每个元素都对一组回调函数进行分组。

f

要调用的回调函数。回调函数根据 struct v4l2_subdev_ops 中每个元素进行分组。

args...

f 的参数。

例子

err = v4l2_subdev_call(sd, video, s_std, norm);

v4l2_subdev_call_state_active

v4l2_subdev_call_state_active (sd, o, f, args...)

调用 v4l2_subdev 的一个操作,该操作将状态作为参数,并将 subdev 的活动状态传递给它。

Parameters

sd

指向 struct v4l2_subdev 的指针

o

包含 fstruct v4l2_subdev_ops 中元素的名称。那里的每个元素都对一组回调函数进行分组。

f

要调用的回调函数。回调函数根据 struct v4l2_subdev_ops 中每个元素进行分组。

args...

f 的参数。

描述

这类似于 v4l2_subdev_call(),只是此版本只能用于将 subdev 状态作为参数的操作。该宏将在调用 op 之前获取活动状态并将其锁定,并在调用之后将其解锁。

v4l2_subdev_call_state_try

v4l2_subdev_call_state_try (sd, o, f, args...)

调用 v4l2_subdev 的一个操作,该操作将状态作为参数,并将 subdev 的新分配的 try 状态传递给它。

Parameters

sd

指向 struct v4l2_subdev 的指针

o

包含 fstruct v4l2_subdev_ops 中元素的名称。那里的每个元素都对一组回调函数进行分组。

f

要调用的回调函数。回调函数根据 struct v4l2_subdev_ops 中每个元素进行分组。

args...

f 的参数。

描述

这类似于 v4l2_subdev_call_state_active(),只是由于此版本分配了一个新状态,因此它仅适用于 V4L2_SUBDEV_FORMAT_TRY 用例。

注意

只有旧的非 MC 驱动程序可能需要此宏。

v4l2_subdev_has_op

v4l2_subdev_has_op (sd, o, f)

检查 subdev 是否定义了某个操作。

Parameters

sd

指向 struct v4l2_subdev 的指针

o

回调函数 f 所属的 struct v4l2_subdev_ops 中的回调函数组。

f

要检查其存在的回调函数。

void v4l2_subdev_notify_event(struct v4l2_subdev *sd, const struct v4l2_event *ev)

传递子设备的事件通知

Parameters

struct v4l2_subdev *sd

要为其传递事件的 subdev

const struct v4l2_event *ev

要传递的事件

描述

将指定的事件传递给所有订阅了 v42l subdev 事件队列的用户空间事件侦听器,以及使用通知回调的桥接驱动程序。通知回调的通知类型将是 V4L2_DEVICE_NOTIFY_EVENT

bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd)

返回 subdev 是否正在流式传输

Parameters

struct v4l2_subdev *sd

子设备

描述

v4l2_subdev_is_streaming() 告诉 subdev 当前是否正在流式传输。“流式传输”在此处表示是否已成功调用 .s_stream() 或 .enable_streams(),并且尚未禁用流式传输。

如果 subdev 实现了 .enable_streams(),则必须在保持活动状态锁定的情况下调用此函数。