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)的函数指针。由于子设备可以执行如此多的不同操作,并且您不希望最终得到一个庞大的操作结构体,其中只实现了少数几个操作,因此函数指针根据类别进行排序,并且每个类别都有自己的操作结构体。

顶层操作结构体包含指向类别操作结构体的指针,如果子设备驱动程序不支持该类别的任何内容,则这些指针可能为 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;
};

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

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

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

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

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

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

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

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

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

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

media_entity_cleanup(&sd->entity);

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

如果未设置 link_validate 操作,则会改为使用默认函数 v4l2_subdev_link_validate_default()。此函数确保链接的源和接收器上的宽度、高度和媒体总线像素代码相等。子设备驱动程序也可以自由使用此函数来执行上述检查以及他们自己的检查。

2.7.1. 子设备注册

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

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

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

2.7.1.1. 注册同步子设备

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

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

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

可以使用以下方式注销子设备:

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

2.7.1.2. 注册异步子设备

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

驱动程序必须在通过 v4l2_async_register_subdev() 注册子设备之前完成子设备的所有初始化,包括启用运行时 PM。这是因为子设备在注册后即可访问。

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. 调用子设备操作

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

注册子设备后,您可以直接调用 ops 函数:

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

但最好和更方便的是使用此宏:

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

如果 sdNULL,则宏将执行正确的 NULL 指针检查并返回 -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);

任何不支持此操作的子设备都会被跳过,并且错误结果会被忽略。如果想要检查错误,请使用此功能。

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

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

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

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

如果子设备需要将其事件通知给它的 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_device_register_subdev_nodes(),为所有标记为 V4L2_SUBDEV_FL_HAS_DEVNODE 的已注册子设备创建设备节点。当子设备注销时,这些设备节点将自动删除。

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

VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU, VIDIOC_G_CTRL, VIDIOC_S_CTRL, VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLSVIDIOC_TRY_EXT_CTRLS

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

VIDIOC_DQEVENT, VIDIOC_SUBSCRIBE_EVENTVIDIOC_UNSUBSCRIBE_EVENT

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

想要使用事件的子设备驱动程序需要在注册子设备之前设置 v4l2_subdev.flags 的 V4L2_SUBDEV_FL_HAS_EVENTS。注册后,可以像往常一样在 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_FMT, VIDIOC_SUBDEV_S_CROP, VIDIOC_SUBDEV_S_SELECTION

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

VIDIOC_SUBDEV_S_FRAME_INTERVAL, VIDIOC_SUBDEV_S_DV_TIMINGS, VIDIOC_SUBDEV_S_STD

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

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

2.10. I2C 子设备驱动程序

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

向 I2C 驱动程序添加 v4l2_subdev 支持的推荐方法是将 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_board_info 结构,该结构传递给 i2c 驱动程序并替换 irq、platform_data 和 addr 参数。

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

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() 以在注销子设备之前释放所有已分配的资源。内核会自动为每个打开的文件句柄分配和初始化一个状态,以存储尝试配置,并在关闭文件句柄时释放它。

使用 ACTIVE 和 TRY 格式 的 V4L2 子设备操作通过“state”参数接收要操作的正确状态。调用者必须通过调用 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

禁用引脚配置。假定为 ENABLE。

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 位。否则,假定为高电平有效。

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 引脚的内部信号焊盘/功能

value

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

strength

引脚驱动强度

struct v4l2_subdev_core_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

为将不同内部信号焊盘复用到 IO 引脚的芯片配置一个或多个芯片 I/O 引脚。此函数接受一个指向 ‘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

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

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 和电视的设备上,驱动程序必须显式调用 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 子设备核心操作的标志

常量

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 中的状态字段相同

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 调整为较小的值,并且不得将超过 size 原始值的数据从 data 开始写入缓冲区。

pre_streamon

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

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

post_streamoff

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

struct v4l2_subdev_vbi_ops

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

定义:

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-子设备传感器操作

定义:

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/空格作为载波突发发送。仅在 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

用于存储子设备衬垫信息。

定义:

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

衬垫编号

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

子设备路由表

定义:

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

成员

len_routes

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

num_routes

路由的数量

routes

struct v4l2_subdev_route

描述

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

struct v4l2_subdev_state

用于存储子设备状态信息。

定义:

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’ 的默认值

lock

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

sd

与状态相关的子设备

pads

struct v4l2_subdev_pad_config 数组

routing

子设备的路由表

stream_configs

流配置(仅适用于 V4L2_SUBDEV_FL_STREAMS)

描述

只有当主参数的 ‘which’ 字段设置为 V4L2_SUBDEV_FORMAT_TRY 时,此结构才需要传递给 pad op。对于 V4L2_SUBDEV_FORMAT_ACTIVE,传递 NULL 是安全的。

struct v4l2_subdev_pad_ops

v4l2-子设备 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 数组可能会被子设备驱动程序调整以适应设备的功能。

get_mbus_config

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

set_routing

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

enable_streams

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

仅支持单个流而不设置 V4L2_SUBDEV_CAP_STREAMS 子设备功能标志的驱动程序可以忽略掩码参数。

disable_streams

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

仅支持单个流而不设置 V4L2_SUBDEV_CAP_STREAMS 子设备功能标志的驱动程序可以忽略掩码参数。

struct v4l2_subdev_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_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 子设备内部操作

定义:

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

将子设备状态初始化为默认值

registered

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

unregistered

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

open

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

close

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

release

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

描述

注意

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

struct v4l2_subdev_platform_data

稳压器配置结构

定义:

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

成员

regulators

用于打开/关闭子设备的可选稳压器

num_regulators

稳压器的数量

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

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

v4l2_dev

指向结构体 v4l2_device 的指针

ops

指向结构体 v4l2_subdev_ops 的指针

internal_ops

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

ctrl_handler

此子设备的控制句柄。可以为 NULL。

name

子设备的名称。请注意,名称必须唯一。

grp_id

可用于对相似的子设备进行分组。该值是驱动程序特定的。

dev_priv

指向私有数据的指针

host_priv

指向子设备所连接的设备的私有数据的指针。

devnode

子设备设备节点

dev

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

fwnode

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

async_list

将此子设备链接到全局 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() 为子设备隐式注册的子设备通知器。

asc_list

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

pdata

子设备平台数据的公共部分

state_lock

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

privacy_led

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

active_state

子设备的活动状态(对于在内部跟踪状态的子设备为 NULL)。通过调用 v4l2_subdev_init_finalize() 初始化。

enabled_pads

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

s_stream_enabled

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

描述

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

此结构应由 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

参数

ent

指向 struct media_entity 的指针。

vdev_to_v4l2_subdev

vdev_to_v4l2_subdev (vdev)

从嵌入其中的 struct video_device 返回 struct v4l2_subdev

参数

vdev

指向 struct video_device 的指针

struct v4l2_subdev_fh

用于存储每个文件句柄的子设备信息

定义:

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

参数

fh

指向 struct v4l2_fh 的指针

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

设置 V4L2 设备私有设备数据

参数

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

void *p

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

void *v4l2_get_subdevdata(const struct v4l2_subdev *sd)

获取 V4L2 设备私有设备数据

参数

const struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

描述

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

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

设置 V4L2 设备私有主机数据

参数

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指针

void *p

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

void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)

获取 V4L2 设备私有数据

参数

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)

从子设备 fwnode 端点获取 pad 编号,假设端口与 pad 之间是 1:1 映射

参数

struct media_entity *entity

指向子设备实体的指针

struct fwnode_endpoint *endpoint

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

描述

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

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

验证媒体链接

参数

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 的指针

描述

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

验证媒体链接

参数

struct media_link *link

指向 struct media_link 的指针

描述

此函数调用子设备的 link_validate 操作来验证媒体链接是否对流传输有效。它还在内部调用 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 实现

参数

struct media_entity *entity

指向 struct media_entity 的指针

unsigned int pad0

第一个 pad 的 pad 编号

unsigned int pad1

第二个 pad 的 pad 编号

描述

此函数是针对实现多路复用流 API 的子设备(由 V4L2_SUBDEV_FL_STREAMS 子设备标志指示)的 media_entity_operations.has_pad_interdep 操作的实现。

如果 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

参数

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

参数

struct v4l2_subdev_state *state

要释放的 v4l2_subdev_state。

描述

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

v4l2_subdev_init_finalize

v4l2_subdev_init_finalize (sd)

完成子设备的初始化

参数

sd

子设备

描述

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

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

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

void v4l2_subdev_cleanup(struct v4l2_subdev *sd)

释放子设备分配的资源

参数

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, ...)

获取指向流格式的指针

参数

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, ...)

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

参数

state

子设备状态

pad

pad ID

...

流 ID(可选参数)

描述

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

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

v4l2_subdev_state_get_compose

v4l2_subdev_state_get_compose (state, pad, ...)

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

参数

state

子设备状态

pad

pad ID

...

流 ID(可选参数)

描述

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

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

v4l2_subdev_state_get_interval

v4l2_subdev_state_get_interval (state, pad, ...)

获取指向流帧间隔的指针

参数

state

子设备状态

pad

pad ID

...

流 ID(可选参数)

描述

此函数返回子设备状态中给定 pad + stream 的帧间隔指针。

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

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

根据状态填充 format

参数

struct v4l2_subdev *sd

子设备

struct v4l2_subdev_state *state

子设备状态

struct v4l2_subdev_format *format

指向 struct v4l2_subdev_format 的指针

描述

根据 format 结构中的信息填充 format->format 字段。

如果子设备驱动程序在其 get_fmt 操作中不需要执行任何特殊操作,则支持活动状态的子设备驱动程序可以使用此函数来实现 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)

根据状态填充帧间隔

参数

struct v4l2_subdev *sd

子设备

struct v4l2_subdev_state *state

子设备状态

struct v4l2_subdev_frame_interval *fi

指向 struct v4l2_subdev_frame_interval 的指针

描述

根据 fi 结构中的信息填充 fi->interval 字段。

如果子设备驱动程序在其 get_frame_interval 操作中不需要执行任何特殊操作,则支持活动状态的子设备驱动程序可以使用此函数来实现 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)

将给定的路由设置到子设备状态

参数

struct v4l2_subdev *sd

子设备

struct v4l2_subdev_state *state

子设备状态

const struct v4l2_subdev_krouting *routing

将复制到子设备状态的路由

描述

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

这可以在子设备驱动程序的 set_routing 操作中验证路由后使用。

for_each_active_route

for_each_active_route (routing, route)

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

参数

routing

路由表

路由

路由迭代器

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)

将给定的路由和格式设置到子设备状态

参数

struct v4l2_subdev *sd

子设备

struct v4l2_subdev_state *state

子设备状态

const struct v4l2_subdev_krouting *routing

将复制到子设备状态的路由

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)

查找相反的 stream

参数

const struct v4l2_subdev_krouting *routing

用于查找相反侧的路由

u32 pad

pad ID

u32 stream

stream id

u32 *other_pad

用于返回相反 pad 的指针

u32 *other_stream

用于返回相反 stream 的指针

描述

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

如果调用者不需要该值,则 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)

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

参数

struct v4l2_subdev_state *state

子设备状态

u32 pad

pad ID

u32 stream

stream id

描述

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

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

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

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

参数

const struct v4l2_subdev_state *state

子设备状态

u32 pad0

第一个 pad

u32 pad1

第二个 pad

u64 *streams

第一个 pad 上的 stream 位掩码

描述

子设备的接收端端口上的数据流会根据子设备状态路由表中的定义路由到发送端端口。路由的接收端和发送端的数据流编号不一定匹配。此函数使用 state 中的路由表,将 pad0 上的数据流编号(以位掩码 streams 表示)转换为 pad1 上对应的流编号。它返回 pad1 上的数据流掩码,并使用路由表中找到的数据流更新 streams

pad0pad1 必须分别为接收端和发送端端口,顺序不限。

返回值

pad1 上路由到 pad0streams 的数据流的位掩码。

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

来自接收端端口的所有流必须路由到单个发送端端口

V4L2_SUBDEV_ROUTING_NO_SOURCE_STREAM_MIX

发送端端口上的所有流必须来自单个接收端端口

V4L2_SUBDEV_ROUTING_NO_SINK_MULTIPLEXING

接收端端口不应包含多路复用的流

V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING

发送端端口不应包含多路复用的流

V4L2_SUBDEV_ROUTING_ONLY_1_TO_1

只允许非重叠的一对一数据流路由( V4L2_SUBDEV_ROUTING_NO_1_TO_NV4L2_SUBDEV_ROUTING_NO_N_TO_1 的组合)

V4L2_SUBDEV_ROUTING_NO_STREAM_MIX

来自接收端端口的所有流必须路由到单个发送端端口,并且该发送端端口不得从任何其他接收端端口获取路由( V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIXV4L2_SUBDEV_ROUTING_NO_SOURCE_STREAM_MIX 的组合)

V4L2_SUBDEV_ROUTING_NO_MULTIPLEXING

发送端或接收端都不允许有多路复用的流。

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

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

参数

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)

启用端口上的数据流

参数

struct v4l2_subdev *sd

子设备

u32 pad

端口

u64 streams_mask

要启用的数据流的位掩码

描述

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

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

每个数据流启用仅适用于实现 .enable_streams() 和 .disable_streams() 操作的子设备。对于其他子设备,此函数通过调用 .s_stream() 操作来实现尽力而为的兼容性,但仅限于具有单个发送端端口的子设备。

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

返回值

  • 0:成功

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

  • -EINVAL:端口索引无效,或者不对应于发送端端口

  • -EOPNOTSUPP:由于子设备有多个发送端端口,无法回退到旧版 .s_stream() 操作

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

禁用端口上的数据流

参数

struct v4l2_subdev *sd

子设备

u32 pad

端口

u64 streams_mask

要禁用的数据流的位掩码

描述

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

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

每个数据流禁用仅适用于实现 .enable_streams() 和 .disable_streams() 操作的子设备。对于其他子设备,此函数通过调用 .s_stream() 操作来实现尽力而为的兼容性,但仅限于具有单个发送端端口的子设备。

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

返回值

  • 0:成功

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

  • -EINVAL:端口索引无效,或者不对应于发送端端口

  • -EOPNOTSUPP:由于子设备有多个发送端端口,无法回退到旧版 .s_stream() 操作

int v4l2_subdev_s_stream_helper(struct v4l2_subdev *sd, int enable)

使用 enable_streams 和 disable_streams 实现子设备 s_stream 操作的辅助函数

参数

struct v4l2_subdev *sd

子设备

int enable

启用或禁用数据流

描述

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

此辅助函数只能由具有单个发送端端口的子设备使用。

返回值

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

void v4l2_subdev_lock_state(struct v4l2_subdev_state *state)

锁定子设备状态

参数

struct v4l2_subdev_state *state

子设备状态

描述

锁定给定的子设备状态。

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

void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state)

解锁子设备状态

参数

struct v4l2_subdev_state *state

子设备状态

描述

解锁给定的子设备状态。

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

锁定两个子设备状态

参数

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)

解锁两个子设备状态

参数

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)

检查活动子设备状态是否已解锁并返回它

参数

struct v4l2_subdev *sd

子设备

描述

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

例如,当获取活动状态仅用于将其传递给其他函数,而不访问状态字段时,可以使用此函数。

struct v4l2_subdev_state *v4l2_subdev_get_locked_active_state(struct v4l2_subdev *sd)

检查活动子设备状态是否已锁定并返回它

参数

struct v4l2_subdev *sd

子设备

描述

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

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

struct v4l2_subdev_state *v4l2_subdev_lock_and_get_active_state(struct v4l2_subdev *sd)

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

参数

struct v4l2_subdev *sd

子设备

描述

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

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

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

初始化子设备结构体

参数

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 的一个操作。

参数

sd

指向 struct v4l2_subdev 的指针

o

位于 struct v4l2_subdev_ops 中包含 f 的元素的名称。那里的每个元素都分组了一组回调函数。

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 的一个操作,该操作将状态作为参数,并将子设备的活动状态传递给它。

参数

sd

指向 struct v4l2_subdev 的指针

o

位于 struct v4l2_subdev_ops 中包含 f 的元素的名称。那里的每个元素都分组了一组回调函数。

f

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

args...

f 的参数。

描述

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

v4l2_subdev_call_state_try

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

调用 v4l2_subdev 的一个操作,该操作将状态作为参数,并将新分配的试用状态传递给子设备。

参数

sd

指向 struct v4l2_subdev 的指针

o

位于 struct v4l2_subdev_ops 中包含 f 的元素的名称。那里的每个元素都分组了一组回调函数。

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)

检查子设备是否定义了某个操作。

参数

sd

指向 struct v4l2_subdev 的指针

o

struct v4l2_subdev_ops 中回调函数的分组,f 是其中的一部分。

f

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

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

为子设备传递事件通知

参数

struct v4l2_subdev *sd

要传递事件的子设备

const struct v4l2_event *ev

要传递的事件

描述

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

bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd)

返回子设备是否正在流式传输

参数

struct v4l2_subdev *sd

子设备

描述

v4l2_subdev_is_streaming() 判断子设备当前是否正在流式传输。此处的“流式传输”是指是否已成功调用 .s_stream() 或 .enable_streams(),并且流式传输尚未被禁用。

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