5.媒体控制器设备

5.1.媒体控制器

媒体控制器用户空间 API 在 媒体控制器 uAPI 手册 中进行了文档化。本文档重点介绍媒体框架的内核端实现。

5.1.1.抽象媒体设备模型

发现设备的内部拓扑结构并在运行时对其进行配置是媒体框架的目标之一。为了实现这一点,硬件设备被建模为有向图,其中图的构建块称为实体,并通过焊盘连接。

实体是基本的媒体硬件构建块。它可以对应于各种各样的逻辑块,例如物理硬件设备(例如 CMOS 传感器),逻辑硬件设备(片上系统图像处理流水线中的构建块),DMA 通道或物理连接器。

焊盘是实体可以通过其与其他实体交互的连接端点。实体产生的数据(不限于视频)从实体的输出流向一个或多个实体输入。焊盘不应与芯片边界处的物理引脚混淆。

链接是两个焊盘之间的点对点有向连接,这两个焊盘可以位于同一实体上,也可以位于不同的实体上。数据从源焊盘流向宿焊盘。

5.1.2.媒体设备

媒体设备由 struct media_device 实例表示,该实例在 include/media/media-device.h 中定义。结构的分配由媒体设备驱动程序处理,通常是将 media_device 实例嵌入到更大的驱动程序特定结构中。

驱动程序通过调用 media_device_init() 初始化媒体设备实例。初始化媒体设备实例后,通过宏 media_device_register() 调用 __media_device_register() 注册,并通过调用 media_device_unregister() 注销。初始化的媒体设备最终必须通过调用 media_device_cleanup() 清理。

请注意,不允许注销以前未注册的媒体设备实例,或清理以前未初始化的媒体设备实例。

5.1.3.实体

实体由 struct media_entity 实例表示,该实例在 include/media/media-entity.h 中定义。该结构通常嵌入到更高级别的结构中,例如 v4l2_subdevvideo_device 实例,尽管驱动程序可以直接分配实体。

驱动程序通过调用 media_entity_pads_init() 来初始化实体焊盘。

驱动程序通过调用 media_device_register_entity() 向媒体设备注册实体,并通过调用 media_device_unregister_entity() 注销实体。

5.1.4.接口

接口由 struct media_interface 实例表示,该实例在 include/media/media-entity.h 中定义。当前,仅定义了一种接口类型:设备节点。此类接口由 struct media_intf_devnode 表示。

驱动程序通过调用 media_devnode_create() 初始化并创建设备节点接口,并通过调用 media_devnode_remove() 删除它们。

5.1.5.焊盘

焊盘由 struct media_pad 实例表示,该实例在 include/media/media-entity.h 中定义。每个实体将其焊盘存储在实体驱动程序管理的焊盘数组中。驱动程序通常将该数组嵌入到驱动程序特定的结构中。

焊盘通过其实体及其在焊盘数组中的基于 0 的索引来标识。

这两个信息都存储在 struct media_pad 中,这使得 struct media_pad 指针成为存储和传递链接引用的规范方式。

焊盘具有描述焊盘功能和状态的标志。

MEDIA_PAD_FL_SINK 表示焊盘支持接收数据。MEDIA_PAD_FL_SOURCE 表示焊盘支持发送数据。

注意

每个 pad 必须设置 MEDIA_PAD_FL_SINKMEDIA_PAD_FL_SOURCE 中的一个且仅一个。

5.1.7. 图遍历

媒体框架提供了遍历媒体图、定位连接的实体和链接的 API。

要遍历属于媒体设备的所有实体,驱动程序可以使用在 include/media/media-device.h 中定义的 media_device_for_each_entity 宏。

struct media_entity *entity;

media_device_for_each_entity(entity, mdev) {
// entity will point to each entity in turn
...
}

可以使用辅助函数来查找两个给定 pad 之间的链接,或者通过启用的链接连接到另一个 pad 的 pad(media_entity_find_link()media_pad_remote_pad_first()media_entity_remote_source_pad_unique()media_pad_remote_pad_unique())。

5.1.8. 使用计数和电源处理

由于驱动程序在电源管理需求方面存在很大差异,媒体控制器不实现电源管理。但是,struct media_entity 包括一个 use_count 字段,媒体驱动程序可以使用该字段来跟踪每个实体的用户数量,以满足电源管理需求。

media_entity.use_count 字段归媒体驱动程序所有,实体驱动程序不得修改。对该字段的访问必须受到 media_device.graph_mutex 锁的保护。

5.1.10. 管道和媒体流

媒体流是从一个或多个源设备(如传感器)发出,并通过媒体实体 pad 流向最终接收器的像素或元数据流。该流可以在路由上被设备修改(例如,缩放或像素格式转换),或者可以分成多个分支,或者可以合并多个分支。

媒体管道是一组相互依赖的媒体流。这种相互依赖关系可能是由硬件(例如,如果第一个流已启用,则无法更改第二个流的配置)或由驱动程序由于软件设计引起的。最常见的是,媒体管道由单个不分支的流组成。

在开始流式传输时,驱动程序必须通知管道中的所有实体,以防止在流式传输期间通过调用 media_pipeline_start() 修改链接状态。

该函数会将管道中所有作为流一部分的 pad 标记为流式传输。

由 pipe 参数指向的 struct media_pipeline 实例将存储在管道中的每个 pad 中。驱动程序应将 struct media_pipeline 嵌入到更高级别的管道结构中,然后可以通过 struct media_pad pipe 字段访问管道。

可以嵌套调用 media_pipeline_start()。对于对该函数的所有嵌套调用,管道指针必须相同。

media_pipeline_start() 可能会返回错误。在这种情况下,它将自行清理它所做的任何更改。

停止流时,驱动程序必须使用 media_pipeline_stop() 通知实体。

如果已多次调用 media_pipeline_start(),则需要相同数量的 media_pipeline_stop() 调用才能停止流式传输。在最后一次嵌套的停止调用时,media_entity.pipe 字段将重置为 NULL

如果链接的任一端是流式传输实体,则默认情况下链接配置将失败,并返回 -EBUSY。可以在流式传输时修改的链接必须标记为 MEDIA_LNK_FL_DYNAMIC 标志。

如果需要在流式传输实体上禁用其他操作(例如,更改实体配置参数),驱动程序可以显式检查 media_entity stream_count 字段以查找实体是否正在流式传输。此操作必须在持有 media_device graph_mutex 的情况下完成。

5.1.12. 管道遍历

使用 media_pipeline_start() 构建管道后,驱动程序可以使用 :c:macro:`media_pipeline_for_each_entity` 和 :c:macro:`media_pipeline_for_each_pad` 宏遍历管道中的实体或 pad。遍历 pad 很简单

media_pipeline_pad_iter iter;
struct media_pad *pad;

media_pipeline_for_each_pad(pipe, &iter, pad) {
    /* 'pad' will point to each pad in turn */
    ...
}

要遍历实体,迭代器需要作为附加步骤进行初始化和清理

media_pipeline_entity_iter iter;
struct media_entity *entity;
int ret;

ret = media_pipeline_entity_iter_init(pipe, &iter);
if (ret)
    ...;

media_pipeline_for_each_entity(pipe, &iter, entity) {
    /* 'entity' will point to each entity in turn */
    ...
}

media_pipeline_entity_iter_cleanup(&iter);

5.1.13. 媒体控制器设备分配器 API

当媒体设备属于多个驱动程序时,共享媒体设备会使用共享的 struct device 作为查找的键进行分配。

共享媒体设备应保持注册状态,直到最后一个驱动程序取消注册它为止。此外,当所有引用都被释放时,应释放媒体设备。每个驱动程序在探测期间获取对媒体设备的引用,此时它会分配媒体设备。如果媒体设备已经分配,则 allocate API 会增加 refcount 并返回现有的媒体设备。驱动程序在调用 media_device_delete() 时,会在其断开连接例程中放回引用。

媒体设备从 kref put 处理程序中注销并清理,以确保媒体设备在最后一个驱动程序注销媒体设备之前保持注册状态。

驱动程序用法

驱动程序应使用适当的媒体核心例程来管理共享媒体设备的生命周期,处理以下两种状态:1. 分配 -> 注册 -> 删除 2. 获取已注册设备的引用 -> 删除

调用 media_device_delete() 例程以确保正确处理共享媒体设备的删除。

驱动程序探测: 调用 media_device_usb_allocate() 来分配或获取引用。如果媒体设备节点未注册,则调用 media_device_register()

驱动程序断开连接: 调用 media_device_delete() 来释放 media_device。释放由 kref put 处理程序处理。

5.1.14. API 定义

struct media_entity_notify

媒体实体通知

定义:

struct media_entity_notify {
    struct list_head list;
    void *notify_data;
    void (*notify)(struct media_entity *entity, void *notify_data);
};

成员

list

链表头

notify_data

调用回调的输入数据

notify

回调函数指针

描述

当新实体在媒体设备上注册时,驱动程序可以注册一个回调来执行操作。此处理程序旨在创建现有实体之间的链接,而不应创建实体并注册它们。

struct media_device_ops

媒体设备操作

定义:

struct media_device_ops {
    int (*link_notify)(struct media_link *link, u32 flags, unsigned int notification);
    struct media_request *(*req_alloc)(struct media_device *mdev);
    void (*req_free)(struct media_request *req);
    int (*req_validate)(struct media_request *req);
    void (*req_queue)(struct media_request *req);
};

成员

link_notify

链接状态更改通知回调。此回调在持有 graph_mutex 的情况下被调用。

req_alloc

分配一个请求。如果您需要分配一个大于 struct media_request 的结构,则设置此项。req_allocreq_free 必须同时设置或同时为 NULL。

req_free

释放一个请求。如果也设置了 req_alloc,则设置此项,否则保留为 NULL。

req_validate

验证请求,但暂时不排队。调用此操作时,持有 req_queue_mutex 锁。

req_queue

将已验证的请求排队,不能失败。如果在排队此请求时发生错误,则应在驱动程序内部将其标记为错误,并且任何相关的缓冲区最终都必须以状态 VB2_BUF_STATE_ERROR 返回到 vb2。调用此操作时,持有 req_queue_mutex 锁。重要的是,在对所有其他对象类型进行排队之后,最后对 vb2 缓冲区对象进行排队:对缓冲区进行排队会启动请求处理,因此与请求(以及缓冲区)相关的所有其他对象必须可供驱动程序使用。一旦对缓冲区进行排队,驱动程序就可以在 req_queue 退出之前完成或删除请求中的对象。

struct media_device

媒体设备

定义:

struct media_device {
    struct device *dev;
    struct media_devnode *devnode;
    char model[32];
    char driver_name[32];
    char serial[40];
    char bus_info[32];
    u32 hw_revision;
    u64 topology_version;
    u32 id;
    struct ida entity_internal_idx;
    int entity_internal_idx_max;
    struct list_head entities;
    struct list_head interfaces;
    struct list_head pads;
    struct list_head links;
    struct list_head entity_notify;
    struct mutex graph_mutex;
    struct media_graph pm_count_walk;
    void *source_priv;
    int (*enable_source)(struct media_entity *entity, struct media_pipeline *pipe);
    void (*disable_source)(struct media_entity *entity);
    const struct media_device_ops *ops;
    struct mutex req_queue_mutex;
    atomic_t request_id;
};

成员

dev

父设备

devnode

媒体设备节点

model

设备型号名称

driver_name

可选的设备驱动程序名称。如果未设置,则对 MEDIA_IOC_DEVICE_INFO 的调用将返回 dev->driver->name。例如,USB 驱动程序需要此项,否则它们都将显示为驱动程序名称为“usb”。

serial

设备序列号(可选)

bus_info

唯一且稳定的设备位置标识符

hw_revision

硬件设备修订版本

topology_version

用于存储图形拓扑版本的单调计数器。每次拓扑更改时都应递增。

id

上次注册的图形对象上使用的唯一 ID

entity_internal_idx

图形遍历算法使用的唯一内部实体 ID

entity_internal_idx_max

已分配的内部实体索引

entities

已注册实体列表

interfaces

已注册接口列表

pads

已注册焊盘列表

links

已注册链接列表

entity_notify

已注册的 entity_notify 回调列表

graph_mutex

保护对 struct media_device 数据的访问

pm_count_walk

用于电源状态遍历的图形遍历。使用 graph_mutex 串行访问。

source_priv

用于启用/禁用源处理程序的驱动程序私有数据

enable_source

启用源处理程序函数指针

disable_source

禁用源处理程序函数指针

ops

操作处理程序回调

req_queue_mutex

针对停止或开始流的其他操作,序列化 MEDIA_REQUEST_IOC_QUEUE ioctl。

request_id

用于生成唯一请求 ID

描述

此结构表示抽象的高级媒体设备。它允许轻松访问实体并提供基本的媒体设备级别支持。该结构可以直接分配或嵌入到更大的结构中。

dev 是一个物理设备。必须在注册媒体设备之前设置它。

model 是通过 sysfs 导出的描述性模型名称。它不必是唯一的。

enable_source 是一个处理程序,用于查找接收器实体的源实体,并在源实体空闲时激活它们之间的链接。驱动程序应在访问源之前调用此处理程序。

disable_source 是一个处理程序,用于查找接收器实体的源实体,并停用它们之间的链接。驱动程序应调用此处理程序以释放源。

用例:查找连接到解码器实体的调谐器实体,并检查它是否可用,并从 enable_source 激活它们之间的链接,并从 disable_source 停用它们之间的链接。

注意

media_device 注册时,或者当桥接驱动程序在探测期间找到 media_device 时,桥接驱动程序应实现并设置该处理程序。桥接驱动程序使用运行 enable_sourcedisable_source 处理程序所需的信息设置 source_priv。调用者应持有 graph_mutex 来访问和调用 enable_sourcedisable_source 处理程序。

void media_device_init(struct media_device *mdev)

初始化媒体设备元素

参数

struct media_device *mdev

指向结构 media_device 的指针

描述

此函数在注册媒体设备之前初始化它。媒体设备初始化和注册分为两个函数,以避免竞争条件,并在媒体图完成之前使媒体设备可供用户空间使用。

因此,驱动程序需要先初始化媒体设备,在媒体设备中注册任何实体,创建焊盘到焊盘的链接,然后最后通过调用 media_device_register() 作为最后一步来注册媒体设备。

调用者负责在注册之前初始化媒体设备。必须设置以下字段

  • dev 必须指向父设备

  • model 必须填充设备型号名称

如果 bus_info 字段以“0”开头,则 media_device_init() 为 PCI 和平台设备设置 bus_info 字段。

void media_device_cleanup(struct media_device *mdev)

清理媒体设备元素

参数

struct media_device *mdev

指向结构 media_device 的指针

描述

此函数将销毁在 media_device_init() 中初始化的 graph_mutex。

int __media_device_register(struct media_device *mdev, struct module *owner)

注册媒体设备元素

参数

struct media_device *mdev

指向结构 media_device 的指针

struct module *owner

应填充 THIS_MODULE

描述

用户应改为调用 media_device_register() 宏。

调用者负责在注册前初始化 media_device 结构体。 media_device 的以下字段必须设置:

  • media_device.model 必须使用以 NULL 结尾的 UTF-8 字符串填充设备型号名称。设备/型号修订版本不得存储在此字段中。

以下字段是可选的:

  • media_device.serial 是一个唯一的序列号,存储为以 NULL 结尾的 ASCII 字符串。该字段足够大,可以存储文本形式的 GUID。如果硬件不提供唯一的序列号,则此字段必须留空。

  • media_device.bus_info 表示设备在系统中的位置,以 NULL 结尾的 ASCII 字符串表示。对于 PCI/PCIe 设备, media_device.bus_info 必须设置为 “PCI:”(或 “PCIe:”)后跟 pci_name() 的值。对于 USB 设备,必须使用 usb_make_path() 函数。此字段供应用程序用来区分不提供序列号的相同设备。

  • media_device.hw_revision 是驱动程序特定格式的硬件设备修订版本。如果可能,修订版本应使用 KERNEL_VERSION() 宏格式化。

注意

  1. 成功注册后,将创建一个名为 media[0-9]+ 的字符设备。设备的主次设备号是动态的。型号名称作为 sysfs 属性导出。

  2. 注销尚未注册的媒体设备是不安全的。

返回值:

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

media_device_register

media_device_register (mdev)

注册媒体设备元素

参数

mdev

指向结构 media_device 的指针

描述

此宏调用 __media_device_register(),将 THIS_MODULE 作为 __media_device_register() 的第二个参数(owner)传递。

void media_device_unregister(struct media_device *mdev)

注销一个媒体设备元素

参数

struct media_device *mdev

指向结构 media_device 的指针

描述

在未注册(但已初始化)的媒体设备上调用此函数是安全的。

int media_device_register_entity(struct media_device *mdev, struct media_entity *entity)

在先前注册的媒体设备内注册一个媒体实体。

参数

struct media_device *mdev

指向结构 media_device 的指针

struct media_entity *entity

指向要注册的 media_entity 结构体的指针

描述

实体由唯一的正整数 ID 标识。媒体控制器框架将自动生成此类 ID。不能保证 ID 是连续的,并且 ID 号在较新的内核版本上可能会更改。因此,驱动程序和用户空间都不应硬编码 ID 号来引用实体,而应在需要时使用框架来查找 ID。

在调用 media_device_register_entity() 之前,应初始化 media_entity 的名称、类型和标志字段。嵌入到更高层标准结构中的实体可以由更高层框架设置其中的一些字段。

如果设备有焊盘,则应在此函数之前调用 media_entity_pads_init() 。否则,在调用此函数之前,应将 media_entity.padmedia_entity.num_pads 置零。

实体具有描述实体功能和状态的标志。

MEDIA_ENT_FL_DEFAULT

指示给定类型的默认实体。这可以用来报告默认的音频和视频设备或默认的相机传感器。

注意

驱动程序应在调用此函数之前设置实体功能。请注意,驱动程序不应使用值 MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWNMEDIA_ENT_F_UNKNOWN

void media_device_unregister_entity(struct media_entity *entity)

注销一个媒体实体。

参数

struct media_entity *entity

指向要注销的 media_entity 结构体的指针

描述

当调用此函数时,与实体关联的所有链接和所有 PAD 都会自动从 media_device 中注销。

注销一个实体不会更改其他实体的 ID,并且先前使用的 ID 永远不会被重用于新注册的实体。

当注销媒体设备时,其所有实体都会自动注销。然后不需要手动注销实体。

注意

如果需要,驱动程序必须显式释放 media_entity 实例本身。

void media_device_register_entity_notify(struct media_device *mdev, struct media_entity_notify *nptr)

注册一个 media_entity_notify 回调

参数

struct media_device *mdev

媒体设备

struct media_entity_notify *nptr

media_entity_notify

描述

注意

当注册新实体时,会调用所有已注册的 media_entity_notify 回调。

void media_device_unregister_entity_notify(struct media_device *mdev, struct media_entity_notify *nptr)

注销一个媒体实体通知回调

参数

struct media_device *mdev

媒体设备

struct media_entity_notify *nptr

media_entity_notify

void media_device_pci_init(struct media_device *mdev, struct pci_dev *pci_dev, const char *name)

从 PCI 设备创建并初始化一个 media_device 结构体。

参数

struct media_device *mdev

指向结构 media_device 的指针

struct pci_dev *pci_dev

指向 struct pci_dev 的指针

const char *name

媒体设备名称。如果 NULL,该例程将使用 pci_name() 宏给出的 pci 设备的默认名称。

void __media_device_usb_init(struct media_device *mdev, struct usb_device *udev, const char *board_name, const char *driver_name)

从 PCI 设备创建并初始化一个 media_device 结构体。

参数

struct media_device *mdev

指向结构 media_device 的指针

struct usb_device *udev

指向 struct usb_device 的指针

const char *board_name

媒体设备名称。如果为 NULL,该例程将使用 USB 产品名称(如果可用)。

const char *driver_name

驱动程序的名称。如果为 NULL,该例程将使用 udev->dev->driver->name 给出的名称,这通常是错误的做法。

描述

注意

最好调用 media_device_usb_init(),因为这样的宏会用 KBUILD_MODNAME 填充 driver_name。

media_device_usb_init

media_device_usb_init (mdev, udev, name)

从 PCI 设备创建并初始化一个 media_device 结构体。

参数

mdev

指向结构 media_device 的指针

udev

指向 struct usb_device 的指针

name

媒体设备名称。如果为 NULL,该例程将使用 USB 产品名称(如果可用)。

描述

此宏调用 media_device_usb_init(),并将 media_device_usb_init()driver_name 参数填充为 KBUILD_MODNAME

void media_set_bus_info(char *bus_info, size_t bus_info_size, struct device *dev)

设置 bus_info 字段

参数

char *bus_info

写入总线信息的位置(字符数组)

size_t bus_info_size

bus_info 的长度

struct device *dev

相关的 struct device

描述

根据 dev 设置总线信息。当前针对 PCI 和平台设备执行此操作。必须保证 dev 不为 NULL 才能执行此操作。

此函数不应从驱动程序中调用。

struct media_file_operations

媒体设备文件操作

定义:

struct media_file_operations {
    struct module *owner;
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    __poll_t (*poll) (struct file *, struct poll_table_struct *);
    long (*ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*open) (struct file *);
    int (*release) (struct file *);
};

成员

owner

应填充 THIS_MODULE

read

指向实现 read() 系统调用的函数的指针

write

指向实现 write() 系统调用的函数的指针

poll

指向实现 poll() 系统调用的函数的指针

ioctl

指向实现 ioctl() 系统调用的函数的指针

compat_ioctl

指向在编译为 64 位的内核上处理 32 位用户空间对 ioctl() 系统调用的函数的指针。

open

指向实现 open() 系统调用的函数的指针

release

指向释放 open 函数分配的资源的函数的指针。

struct media_devnode

媒体设备节点

定义:

struct media_devnode {
    struct media_device *media_dev;
    const struct media_file_operations *fops;
    struct device dev;
    struct cdev cdev;
    struct device *parent;
    int minor;
    unsigned long flags;
    void (*release)(struct media_devnode *devnode);
};

成员

media_dev

指向结构 media_device 的指针

fops

指向具有媒体设备操作的 media_file_operations 结构的指针

dev

指向包含媒体控制器设备的 device 结构的指针

cdev

struct cdev 指针字符设备

parent

父设备

minor

设备节点次要编号

flags

标志,MEDIA_FLAG_* 常量的组合

release

在 media-device.c 的 media_devnode_release() 例程末尾调用的释放回调。

描述

此结构表示与媒体相关的设备节点。

parent 是一个物理设备。它必须由核心或设备驱动程序在注册节点之前设置。

int media_devnode_register(struct media_device *mdev, struct media_devnode *devnode, struct module *owner)

注册媒体设备节点

参数

struct media_device *mdev

我们想要注册设备节点的 struct media_device

struct media_devnode *devnode

我们想要注册的媒体设备节点结构

struct module *owner

应填充 THIS_MODULE

描述

注册代码分配次要编号并在内核中注册新的设备节点。如果找不到可用的次要编号,或者设备节点的注册失败,则会返回错误。

成功时返回零。

请注意,如果 media_devnode_register 调用失败,则不会调用 media_devnode 结构的 release() 回调,因此调用者负责释放任何数据。

void media_devnode_unregister_prepare(struct media_devnode *devnode)

清除媒体设备节点注册位

参数

struct media_devnode *devnode

要准备取消注册的设备节点

描述

这会清除传递的设备注册位。以后的 open 调用将会遇到错误。应在 media_devnode_unregister() 之前调用,以避免取消注册和设备文件 open 调用之间的竞争。

如果设备节点从未注册或已经取消注册,则可以安全地调用此函数。

void media_devnode_unregister(struct media_devnode *devnode)

取消注册媒体设备节点

参数

struct media_devnode *devnode

要取消注册的设备节点

描述

这将取消注册传递的设备。以后的 open 调用将会遇到错误。

应在 media_devnode_unregister_prepare() 之后调用

struct media_devnode *media_devnode_data(struct file *filp)

返回指向 media_devnode 的指针

参数

struct file *filp

指向结构体 file 的指针

int media_devnode_is_registered(struct media_devnode *devnode)

如果 media_devnode 已注册,则返回 true;否则返回 false。

参数

struct media_devnode *devnode

指向结构体 media_devnode 的指针。

注意

如果 mdev 为 NULL,则也返回 false。

enum media_gobj_type

图对象的类型

常量

MEDIA_GRAPH_ENTITY

标识一个媒体实体

MEDIA_GRAPH_PAD

标识一个媒体端口

MEDIA_GRAPH_LINK

标识一个媒体链接

MEDIA_GRAPH_INTF_DEVNODE

通过设备节点标识一个媒体内核 API 接口

struct media_gobj

定义一个图对象。

定义:

struct media_gobj {
    struct media_device     *mdev;
    u32 id;
    struct list_head        list;
};

成员

mdev

指向拥有该对象的结构体 media_device 的指针

id

非零的对象 ID 标识符。该 ID 在 media_device 内部应该是唯一的,因为它由 MEDIA_BITS_PER_TYPE 用于存储类型加上 MEDIA_BITS_PER_ID 用于存储 ID 组成

list

存储在每个类型 mdev 对象列表中的列表条目

描述

媒体图上的所有对象都应该嵌入此结构体

struct media_entity_enum

媒体实体的枚举。

定义:

struct media_entity_enum {
    unsigned long *bmap;
    int idx_max;
};

成员

bmap

位图,其中每个位表示一个实体,位于 struct media_entity->internal_idx。

idx_max

bmap 中的位数

struct media_graph

媒体图遍历状态

定义:

struct media_graph {
    struct {
        struct media_entity *entity;
        struct list_head *link;
    } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
    struct media_entity_enum ent_enum;
    int top;
};

成员

stack

图遍历栈;该栈包含有关要遍历的媒体实体的路径以及它们所到达的链接的信息。

stack.entity

指向图中的 struct media_entity 的指针。

stack.link

指向 struct list_head 的指针。

ent_enum

已访问的实体

top

栈顶

struct media_pipeline

媒体管道相关信息

定义:

struct media_pipeline {
    bool allocated;
    struct media_device *mdev;
    struct list_head pads;
    int start_count;
};

成员

allocated

由框架分配和释放的媒体管道

mdev

管道所属的媒体设备

pads

media_pipeline_pad 的列表

start_count

媒体管道启动-停止计数

struct media_pipeline_pad

媒体管道的一部分端口

定义:

struct media_pipeline_pad {
    struct list_head list;
    struct media_pipeline *pipe;
    struct media_pad *pad;
};

成员

list

媒体端口列表中的条目

pipe

端口所属的媒体管道

pad

媒体端口

描述

此结构体将端口与媒体管道关联起来。 media_pipeline_pad 的实例由 media_pipeline_start() 在构建管道时创建,并存储在 media_pad.pads 列表中。media_pipeline_stop() 从列表中删除条目并将其删除。

struct media_pipeline_pad_iter

media_pipeline_for_each_pad 的迭代器

定义:

struct media_pipeline_pad_iter {
    struct list_head *cursor;
};

成员

cursor

当前元素

struct media_pipeline_entity_iter

media_pipeline_for_each_entity 的迭代器

定义:

struct media_pipeline_entity_iter {
    struct media_entity_enum ent_enum;
    struct list_head *cursor;
};

成员

ent_enum

实体枚举跟踪器

cursor

当前元素

媒体图的一部分链接对象。

定义:

struct media_link {
    struct media_gobj graph_obj;
    struct list_head list;
    union {
        struct media_gobj *gobj0;
        struct media_pad *source;
        struct media_interface *intf;
    };
    union {
        struct media_gobj *gobj1;
        struct media_pad *sink;
        struct media_entity *entity;
    };
    struct media_link *reverse;
    unsigned long flags;
    bool is_backlink;
};

成员

graph_obj

包含媒体对象公共数据的嵌入式结构体

list

与拥有该链接的实体或接口关联的链表。

{unnamed_union}

匿名

gobj0

联合体的一部分。用于获取链接的第一个图对象的指针。

source

联合体的一部分。仅当第一个对象 (gobj0) 是端口时使用。在这种情况下,它表示源端口。

intf

联合体的一部分。仅当第一个对象 (gobj0) 是接口时使用。

{unnamed_union}

匿名

gobj1

联合体的一部分。用于获取链接的第二个图对象的指针。

sink

联合体的一部分。仅当第二个对象 (gobj1) 是端口时使用。在这种情况下,它表示接收器端口。

entity

联合体的一部分。仅当第二个对象 (gobj1) 是实体时使用。

reverse

指向端口到端口链接的反向链接的指针。

flags

链接标志,如 uapi/media.h 中定义 (MEDIA_LNK_FL_*)

is_backlink

指示链接是否为反向链接。

enum media_pad_signal_type

媒体端口内的信号类型

常量

PAD_SIGNAL_DEFAULT

默认信号。当所有输入或所有输出都由端口号唯一标识时使用此信号。

PAD_SIGNAL_ANALOG

端口包含模拟信号。它可以是射频、中频、基带信号或子载波。调谐器输入、中频锁相环解调器、复合信号和 S-Video 信号应使用它。

PAD_SIGNAL_DV

包含数字视频信号,它可以是从模拟电视视频源采样的比特流。在这种情况下,它通常包含 VBI 数据。

PAD_SIGNAL_AUDIO

包含来自音频子载波的中频模拟信号或音频比特流。中频信号由调谐器提供,并由音频 AM/FM 解码器使用。比特流音频由音频解码器提供。

struct media_pad

一个媒体端口图对象。

定义:

struct media_pad {
    struct media_gobj graph_obj;
    struct media_entity *entity;
    u16 index;
    u16 num_links;
    enum media_pad_signal_type sig_type;
    unsigned long flags;
    struct media_pipeline *pipe;
};

成员

graph_obj

包含媒体对象公共数据的嵌入式结构体

entity

此端口所属的实体

index

实体端口数组中的端口索引,从 0 到 n 编号

num_links

连接到此端口的链接数

sig_type

媒体端口内的信号类型

flags

端口标志,如 include/uapi/linux/media.h 中定义(查找 MEDIA_PAD_FL_*

pipe

此端口所属的管道。使用 media_entity_pipeline() 来访问此字段。

struct media_entity_operations

媒体实体操作

定义:

struct media_entity_operations {
    int (*get_fwnode_pad)(struct media_entity *entity, struct fwnode_endpoint *endpoint);
    int (*link_setup)(struct media_entity *entity,const struct media_pad *local, const struct media_pad *remote, u32 flags);
    int (*link_validate)(struct media_link *link);
    bool (*has_pad_interdep)(struct media_entity *entity, unsigned int pad0, unsigned int pad1);
};

成员

get_fwnode_pad

根据 fwnode 端点返回端口号,如果出错则返回负值。此操作可用于将 fwnode 映射到媒体端口号。可选。

link_setup

通知实体链接更改。该操作可能会返回错误,在这种情况下,链接设置将被取消。可选。

link_validate

从实体角度返回链接是否有效。media_pipeline_start() 函数通过调用此操作来验证所有链接。可选。

has_pad_interdep

返回实体的两个端口是否相互依赖。如果两个端口相互依赖,则它们是同一管道的一部分,并且启用其中一个端口意味着另一个端口将变为“锁定”状态,并且不允许配置更改。保证 pad0 和 pad1 不会同时是接收器或源。永远不要直接调用 .has_pad_interdep() 操作,始终使用 media_entity_has_pad_interdep()。可选:如果未实现该操作,则所有端口都将被视为相互依赖。

描述

注意

这些回调函数在持有结构体 media_device.graph_mutex 互斥锁的情况下调用。

enum media_entity_type

媒体实体类型

常量

MEDIA_ENTITY_TYPE_BASE

实体未嵌入到另一个子系统结构体中。

MEDIA_ENTITY_TYPE_VIDEO_DEVICE

实体嵌入到 struct video_device 实例中。

MEDIA_ENTITY_TYPE_V4L2_SUBDEV

该实体嵌入在 struct v4l2_subdev 实例中。

描述

媒体实体对象通常不是直接实例化的,而是媒体实体结构由其他特定于子系统的结构继承(通过嵌入)。媒体实体类型标识实现媒体实体实例的子类结构的类型。

这允许媒体实体的运行时类型识别和安全转换为正确的对象类型。例如,嵌入在 v4l2_subdev 结构实例中的媒体实体结构实例将具有类型 MEDIA_ENTITY_TYPE_V4L2_SUBDEV,并且可以使用 container_of() 宏安全地转换为 v4l2_subdev 结构。

struct media_entity

一个媒体实体图对象。

定义:

struct media_entity {
    struct media_gobj graph_obj;
    const char *name;
    enum media_entity_type obj_type;
    u32 function;
    unsigned long flags;
    u16 num_pads;
    u16 num_links;
    u16 num_backlinks;
    int internal_idx;
    struct media_pad *pads;
    struct list_head links;
    const struct media_entity_operations *ops;
    int use_count;
    union {
        struct {
            u32 major;
            u32 minor;
        } dev;
    } info;
};

成员

graph_obj

包含媒体对象通用数据的嵌入式结构。

name

实体名称。

obj_type

实现 media_entity 的对象类型。

function

实体主函数,如 include/uapi/linux/media.h 中定义(搜索 MEDIA_ENT_F_*

flags

实体标志,如 include/uapi/linux/media.h 中定义(搜索 MEDIA_ENT_FL_*

num_pads

接收器和源焊盘的数量。

num_links

链接总数,包括前向和后向,启用和禁用。

num_backlinks

后向链接的数量

internal_idx

一个唯一的内部实体特定编号。如果实体注销或再次注册,则会重复使用这些编号。

pads

焊盘数组,其大小由 num_pads 定义。

links

数据链接列表。

ops

实体操作。

use_count

实体的使用计数。

info

与 devnode 信息的联合。仅为了向后兼容性而保留。

info.dev

包含设备主次信息。

info.dev.major

设备节点主编号,如果设备是 devnode。

info.dev.minor

设备节点次编号,如果设备是 devnode。

描述

注意

use_count 引用计数永远不能为负数,但有意为有符号整数:可以使用简单的 WARN_ON(<0) 检查来检测会使其为负数的引用计数错误。

media_entity_for_each_pad

media_entity_for_each_pad (entity, iter)

迭代实体中的所有焊盘

参数

entity

焊盘所属的实体

iter

迭代器焊盘

描述

迭代媒体实体中的所有焊盘。

struct media_interface

一个媒体接口图对象。

定义:

struct media_interface {
    struct media_gobj               graph_obj;
    struct list_head                links;
    u32 type;
    u32 flags;
};

成员

graph_obj

嵌入式图对象

links

指向图实体的链接列表

type

接口类型,如 include/uapi/linux/media.h 中定义(搜索 MEDIA_INTF_T_*

flags

接口标志,如 include/uapi/linux/media.h 中定义(搜索 MEDIA_INTF_FL_*

描述

注意

目前,没有为 media_interface 定义任何标志。

struct media_intf_devnode

通过设备节点的媒体接口。

定义:

struct media_intf_devnode {
    struct media_interface          intf;
    u32 major;
    u32 minor;
};

成员

intf

嵌入式接口对象

major

设备节点的主编号

minor

设备节点的次编号

u32 media_entity_id(struct media_entity *entity)

返回媒体实体图对象 ID

参数

struct media_entity *entity

指向 media_entity 的指针

enum media_gobj_type media_type(struct media_gobj *gobj)

返回媒体对象类型

参数

struct media_gobj *gobj

指向 media_gobj 图结构的指针

u32 media_id(struct media_gobj *gobj)

返回媒体对象 ID

参数

struct media_gobj *gobj

指向 media_gobj 图结构的指针

u32 media_gobj_gen_id(enum media_gobj_type type, u64 local_id)

在对象 ID 上封装类型和 ID

参数

enum media_gobj_type type

在枚举 media_gobj_type 中定义的对象类型。

u64 local_id

来自结构体 media_device.id 的下一个 ID。

bool is_media_entity_v4l2_video_device(struct media_entity *entity)

检查实体是否为 video_device

参数

struct media_entity *entity

指向实体的指针

返回值:

如果实体是 video_device 对象的实例,并且可以使用 container_of() 宏安全地转换为 struct video_device,则返回 true,否则返回 false

bool is_media_entity_v4l2_subdev(struct media_entity *entity)

检查实体是否为 v4l2_subdev

参数

struct media_entity *entity

指向实体的指针

返回值:

如果实体是 v4l2_subdev 对象的实例,并且可以使用 container_of() 宏安全地转换为结构体 v4l2_subdev,则返回 true,否则返回 false

int media_entity_enum_init(struct media_entity_enum *ent_enum, struct media_device *mdev)

初始化实体枚举

参数

struct media_entity_enum *ent_enum

要初始化的实体枚举

struct media_device *mdev

相关的媒体设备

返回值:

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

void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)

释放实体枚举的资源

参数

struct media_entity_enum *ent_enum

要释放的实体枚举

void media_entity_enum_zero(struct media_entity_enum *ent_enum)

清除整个枚举

参数

struct media_entity_enum *ent_enum

要清除的实体枚举

void media_entity_enum_set(struct media_entity_enum *ent_enum, struct media_entity *entity)

标记枚举中的单个实体

参数

struct media_entity_enum *ent_enum

实体枚举

struct media_entity *entity

要标记的实体

void media_entity_enum_clear(struct media_entity_enum *ent_enum, struct media_entity *entity)

取消标记枚举中的单个实体

参数

struct media_entity_enum *ent_enum

实体枚举

struct media_entity *entity

要取消标记的实体

bool media_entity_enum_test(struct media_entity_enum *ent_enum, struct media_entity *entity)

测试是否已标记实体

参数

struct media_entity_enum *ent_enum

实体枚举

struct media_entity *entity

要测试的实体

描述

如果实体被标记,则返回 true

bool media_entity_enum_test_and_set(struct media_entity_enum *ent_enum, struct media_entity *entity)

测试是否已标记实体,并标记它

参数

struct media_entity_enum *ent_enum

实体枚举

struct media_entity *entity

要测试的实体

描述

如果实体被标记,则返回 true,并在执行此操作之前标记它。

bool media_entity_enum_empty(struct media_entity_enum *ent_enum)

测试整个枚举是否为空

参数

struct media_entity_enum *ent_enum

实体枚举

返回值:

如果实体为空,则返回 true

bool media_entity_enum_intersects(struct media_entity_enum *ent_enum1, struct media_entity_enum *ent_enum2)

测试两个枚举是否相交

参数

struct media_entity_enum *ent_enum1

第一个实体枚举

struct media_entity_enum *ent_enum2

第二个实体枚举

返回值:

如果实体枚举 ent_enum1ent_enum2 相交,则返回 true,否则返回 false

gobj_to_entity

gobj_to_entity (gobj)

从其中包含的 gobj 返回 media_entity 结构体指针。

参数

gobj

指向 media_gobj 图结构的指针

gobj_to_pad

gobj_to_pad (gobj)

从其中包含的 gobj 返回 media_pad 结构体指针。

参数

gobj

指向 media_gobj 图结构的指针

gobj_to_link (gobj)

从其中包含的 gobj 返回 media_link 结构体指针。

参数

gobj

指向 media_gobj 图结构的指针

gobj_to_intf

gobj_to_intf (gobj)

从其中包含的 gobj 返回 media_interface 结构体指针。

参数

gobj

指向 media_gobj 图结构的指针

intf_to_devnode

intf_to_devnode (intf)

从其中包含的 intf 返回 struct media_intf_devnode 指针。

参数

intf

指向 media_intf_devnode 结构体的指针

void media_gobj_create(struct media_device *mdev, enum media_gobj_type type, struct media_gobj *gobj)

初始化图对象

参数

struct media_device *mdev

指向包含该对象的 media_device 的指针

enum media_gobj_type type

对象的类型

struct media_gobj *gobj

指向 media_gobj 图结构的指针

描述

此例程初始化媒体图对象内部嵌入的 media_gobj 结构体。如果使用 media_*_create 函数调用,则会自动调用此例程。但是,如果该对象(实体、链接、pad、接口)嵌入在其他对象上,则应在媒体控制器上注册该对象之前调用此函数。

void media_gobj_destroy(struct media_gobj *gobj)

停止在媒体设备上使用图对象

参数

struct media_gobj *gobj

指向 media_gobj 图结构的指针

描述

诸如 media_device_unregister() 等删除/销毁媒体图对象的所有例程都应调用此函数。

int media_entity_pads_init(struct media_entity *entity, u16 num_pads, struct media_pad *pads)

初始化实体pad

参数

struct media_entity *entity

pad所属的实体

u16 num_pads

sink 和 source pad 的总数

struct media_pad *pads

num_pads 个 pad 的数组。

描述

pads 数组由实体驱动程序管理,并传递给 media_entity_pads_init(),该函数的指针将存储在 media_entity 结构中。

如果不需要 pad,驱动程序可以直接将 media_entity->num_pads 填充为 0,将 media_entity->pads 填充为 NULL,或者调用此函数来完成相同的操作。

由于 pad 的数量是预先知道的,因此 pads 数组不是动态分配的,而是由实体驱动程序管理的。大多数驱动程序会将 pads 数组嵌入到驱动程序特定的结构中,从而避免动态分配。

驱动程序必须在调用 media_entity_pads_init() 之前设置 pads 数组中每个 pad 的方向。该函数将初始化其他 pad 字段。

void media_entity_cleanup(struct media_entity *entity)

释放与实体关联的资源

参数

struct media_entity *entity

pad所属的实体

描述

此函数必须在取消注册实体后的清理阶段调用(目前,它不执行任何操作)。

在内存已清零但尚未通过 media_entity_pad_init() 初始化的 media_entity 上调用 media_entity_cleanup() 是有效的,并且是空操作。

int media_get_pad_index(struct media_entity *entity, u32 pad_type, enum media_pad_signal_type sig_type)

从实体中检索 pad 索引

参数

struct media_entity *entity

pad所属的实体

u32 pad_type

pad 的类型,MEDIA_PAD_FL_* pad 类型之一

enum media_pad_signal_type sig_type

要搜索的 pad 的信号类型

描述

此辅助函数查找实体内部满足 is_sinksig_type 条件的第一个 pad 索引。

成功时,返回 pad 编号。如果未找到 pad 或 media 实体是指向 NULL 的指针,则返回 -EINVAL。

返回值:

创建两个实体之间的链接。

参数

struct media_entity *source

指向源 pad 的 media_entity 的指针。

u16 source_pad

pads 数组中源 pad 的编号

struct media_entity *sink

指向接收器 pad 的 media_entity 的指针。

u16 sink_pad

pads 数组中接收器 pad 的编号。

u32 flags

链接标志,如 include/uapi/linux/media.h 中定义 (搜索 MEDIA_LNK_FL_*)

描述

flags 的有效值

MEDIA_LNK_FL_ENABLED

指示链接已启用,可用于传输媒体数据。当两个或多个链接指向同一接收器 pad 时,一次只能启用其中一个链接。

MEDIA_LNK_FL_IMMUTABLE

指示链接的启用状态无法在运行时修改。如果设置了 MEDIA_LNK_FL_IMMUTABLE,则还必须设置 MEDIA_LNK_FL_ENABLED,因为不可变链接始终处于启用状态。

注意

在调用此函数之前,应先为两端调用 media_entity_pads_init()media_device_register_entity()

创建两个实体之间的链接。

参数

const struct media_device *mdev

指向包含该对象的 media_device 的指针

const u32 source_function

源实体的功能。仅当 source 为 NULL 时使用。

struct media_entity *source

指向源 pad 的 media_entity 的指针。如果为 NULL,则将使用所有与 sink_function 匹配的实体。

const u16 source_pad

pads 数组中源 pad 的编号

const u32 sink_function

接收器实体的功能。仅当 sink 为 NULL 时使用。

struct media_entity *sink

指向接收器 pad 的 media_entity 的指针。如果为 NULL,则将使用所有与 sink_function 匹配的实体。

const u16 sink_pad

pads 数组中接收器 pad 的编号。

u32 flags

链接标志,如 include/uapi/linux/media.h 中定义。

const bool allow_both_undefined

如果 true,则 sourcesink 都可以为 NULL。在这种情况下,它将在所有与 source_function 匹配的实体与所有与 sink_function 匹配的实体之间创建一个交叉开关。如果 false,如果 sourcesink 都为 NULL,它将返回 0 且不会创建任何链接。

描述

flags 的有效值

MEDIA_LNK_FL_ENABLED 标志指示链接已启用,可用于传输媒体数据。

如果创建了多个链接并且此标志作为参数传递,则只有第一个创建的链接才具有此标志。

MEDIA_LNK_FL_IMMUTABLE 标志指示链接的启用状态无法在运行时修改。

如果设置了 MEDIA_LNK_FL_IMMUTABLE,则还必须设置 MEDIA_LNK_FL_ENABLED,因为不可变链接始终处于启用状态。

某些设备通常会有多个相同类型的源或接收实体,需要将它们连接起来。虽然 media_create_pad_link() 逐个创建链接,但此函数旨在允许 1:n、n:1 甚至交叉开关 (n:n) 链接。

注意

在调用此函数之前,应先为要链接的实体调用 media_entity_pads_init()media_device_register_entity()

删除与实体关联的所有链接

参数

struct media_entity *entity

指向 media_entity 的指针

描述

注意

当通过 media_device_register_entity() 注销实体时,会自动调用此函数。

在不加锁的情况下配置媒体链接

参数

struct media_link *link

正在配置的链接

u32 flags

链接配置标志

描述

链接设置的大部分工作由通过链接连接的两个实体处理。此函数通知两个实体链接配置的更改。

如果链接是不可变的,或者当前配置和新配置相同,则立即返回。

用户应持有 link->source->parent->mutex。否则,应使用 media_entity_setup_link()

在运行时更改链接标志属性

参数

struct media_link *link

指向 media_link 的指针

u32 flags

请求的新链接标志

描述

唯一可配置的属性是 MEDIA_LNK_FL_ENABLED 链接标志,用于启用/禁用链接。使用 MEDIA_LNK_FL_IMMUTABLE 链接标志标记的链接不能启用或禁用。

当启用或禁用链接时,媒体框架会按顺序为链接源和接收端的两个实体调用 link_setup 操作。如果第二个 link_setup 调用失败,则会在第一个实体上进行另一个 link_setup 调用,以恢复原始链接标志。

可以通过将 media_device.link_notify 指针设置为回调函数来通知媒体设备驱动程序有关链接设置操作。如果提供了通知回调,则会在启用链接之前和禁用链接之后调用该回调。

如果实体的任何链接是非不可变的,则实体驱动程序必须实现 link_setup 操作。该操作必须配置硬件或存储配置信息以供以后应用。

链接配置不得对其他链接产生任何副作用。如果接收端 pad 上的已启用链接阻止在同一 pad 上启用另一个链接,则 link_setup 操作必须返回 -EBUSY,并且不能隐式禁用第一个已启用的链接。

注意

链接标志的有效值与 media_create_pad_link() 中描述的 pad 到 pad 链接相同,或者与 media_create_intf_link() 中描述的接口到实体链接相同。

查找两个 pad 之间的链接

参数

struct media_pad *source

源 pad

struct media_pad *sink

接收 pad

返回值:

返回指向两个实体之间链接的指针。如果不存在这样的链接,则返回 NULL

struct media_pad *media_pad_remote_pad_first(const struct media_pad *pad)

查找链接远端上的第一个 pad

参数

const struct media_pad *pad

链接本地端的 pad

描述

通过迭代所有源于或终止于该 pad 的链接来搜索连接到给定 pad 的远程 pad,直到找到已启用的链接。

返回值:

返回指向第一个找到的已启用链接的远程端 pad 的指针,如果未找到已启用的链接,则返回 NULL

struct media_pad *media_pad_remote_pad_unique(const struct media_pad *pad)

查找连接到 pad 的远程 pad

参数

const struct media_pad *pad

pad

描述

搜索并通过已启用的链接返回连接到 pad 的远程 pad。如果找到多个(或没有)远程 pad,则会返回错误。

唯一性约束使得此辅助函数适用于在给定 pad 上一次支持单个活动源的实体。

  • -ENOTUNIQ - 启用了多个链接

  • -ENOLINK - 未找到连接的 pad

返回值:

指向远程 pad 的指针,或者如果发生错误,则指向以下错误指针之一

struct media_pad *media_entity_remote_pad_unique(const struct media_entity *entity, unsigned int type)

查找连接到实体的远程 pad

参数

const struct media_entity *entity

实体

unsigned int type

要查找的 pad 类型(MEDIA_PAD_FL_SINK 或 MEDIA_PAD_FL_SOURCE)

描述

搜索并通过已启用的链接返回连接到 entitytype 类型的远程 pad。如果多个(或没有)远程 pad 符合这些条件,则会返回错误。

唯一性约束使得此辅助函数适用于一次支持单个活动源或接收端的实体。

  • -ENOTUNIQ - 启用了多个链接

  • -ENOLINK - 未找到连接的 pad

返回值:

指向远程 pad 的指针,或者如果发生错误,则指向以下错误指针之一

struct media_pad *media_entity_remote_source_pad_unique(const struct media_entity *entity)

查找连接到实体的远程源衬垫

参数

const struct media_entity *entity

实体

描述

搜索并通过启用的链接返回连接到 entity 的远程源衬垫。 如果多个(或没有)远程衬垫符合这些条件,则返回错误。

唯一性约束使此辅助函数适用于一次仅支持单个活动源的实体。

  • -ENOTUNIQ - 启用了多个链接

  • -ENOLINK - 未找到连接的 pad

返回值:

指向远程 pad 的指针,或者如果发生错误,则指向以下错误指针之一

bool media_pad_is_streaming(const struct media_pad *pad)

测试衬垫是否是流式管道的一部分

参数

const struct media_pad *pad

pad

返回值:

如果衬垫是使用 media_pipeline_start() 函数启动的管道的一部分,则为 True,否则为 false。

bool media_entity_is_streaming(const struct media_entity *entity)

测试实体是否是流式管道的一部分

参数

const struct media_entity *entity

实体

返回值:

如果实体是使用 media_pipeline_start() 函数启动的管道的一部分,则为 True,否则为 false。

struct media_pipeline *media_entity_pipeline(struct media_entity *entity)

获取实体所属的媒体管道

参数

struct media_entity *entity

实体

描述

已弃用:请改用 media_pad_pipeline()

当使用 media_pipeline_start() 构建管道时,此函数返回与实体关联的媒体管道。 该指针在调用 media_pipeline_stop() 之前保持有效。

通常,当携带多个流(在不同的衬垫上,或使用复用流在同一衬垫上)时,实体可以是多个管道的一部分。 此函数仅用于不支持多个管道的实体。

返回值:

实体所属的 media_pipeline,如果实体不属于任何管道,则为 NULL。

struct media_pipeline *media_pad_pipeline(struct media_pad *pad)

获取衬垫所属的媒体管道

参数

struct media_pad *pad

pad

描述

当使用 media_pipeline_start() 构建管道时,此函数返回与衬垫关联的媒体管道。 该指针在调用 media_pipeline_stop() 之前保持有效。

返回值:

衬垫所属的 media_pipeline,如果衬垫不属于任何管道,则为 NULL。

int media_entity_get_fwnode_pad(struct media_entity *entity, const struct fwnode_handle *fwnode, unsigned long direction_flags)

从 fwnode 获取衬垫编号

参数

struct media_entity *entity

实体

const struct fwnode_handle *fwnode

指向应该用于查找衬垫的 fwnode_handle 的指针

unsigned long direction_flags

衬垫的预期方向,如 include/uapi/linux/media.h 中所定义(搜索 MEDIA_PAD_FL_*

描述

此函数可用于从 fwnode 解析媒体衬垫编号。 这对于使用更复杂的媒体衬垫映射的设备很有用。

如果实体未实现 get_fwnode_pad() 操作,则此函数将在实体中搜索第一个与 direction_flags 匹配的衬垫。

返回值:

成功时返回衬垫编号,否则返回负错误代码。

int media_graph_walk_init(struct media_graph *graph, struct media_device *mdev)

分配图遍历使用的资源。

参数

struct media_graph *graph

将用于遍历图的媒体图结构

struct media_device *mdev

指向包含该对象的 media_device 的指针

描述

此函数已弃用,请改用 media_pipeline_for_each_pad()

在图遍历期间,调用者需要在释放图状态之前保持 media_device graph_mutex。

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

void media_graph_walk_cleanup(struct media_graph *graph)

释放图遍历使用的资源。

参数

struct media_graph *graph

将用于遍历图的媒体图结构

描述

此函数已弃用,请改用 media_pipeline_for_each_pad()

void media_graph_walk_start(struct media_graph *graph, struct media_entity *entity)

在给定实体处开始遍历媒体图

参数

struct media_graph *graph

将用于遍历图的媒体图结构

struct media_entity *entity

起始实体

描述

此函数已弃用,请改用 media_pipeline_for_each_pad()

在使用此函数之前,必须使用 media_graph_walk_init() 来分配用于遍历图的资源。此函数初始化图遍历结构,以从给定实体开始遍历实体图。遍历结构在图遍历期间不得由调用者修改。图遍历完成后,必须使用 media_graph_walk_cleanup() 释放资源。

struct media_entity *media_graph_walk_next(struct media_graph *graph)

获取图中下一个实体

参数

struct media_graph *graph

媒体图结构

描述

此函数已弃用,请改用 media_pipeline_for_each_pad()

对给定的媒体实体图执行深度优先遍历。

图结构必须事先通过调用 media_graph_walk_start() 进行初始化。

返回值:

返回图中的下一个实体,如果整个图都已遍历,则返回 NULL

int media_pipeline_start(struct media_pad *origin, struct media_pipeline *pipe)

将管道标记为正在流式传输

参数

struct media_pad *origin

起始 pad

struct media_pipeline *pipe

要分配给管道中所有 pad 的媒体管道。

描述

将通过启用的链接直接或间接连接到 pad **origin** 的所有 pad 标记为正在流式传输。给定的管道对象被分配给管道中的每个 pad,并存储在 media_pad 的 pipe 字段中。

可以嵌套调用此函数,在这种情况下,需要相同数量的 media_pipeline_stop() 调用来停止流式传输。对于所有嵌套的 media_pipeline_start() 调用,管道指针必须相同。

int __media_pipeline_start(struct media_pad *origin, struct media_pipeline *pipe)

将管道标记为正在流式传输

参数

struct media_pad *origin

起始 pad

struct media_pipeline *pipe

要分配给管道中所有 pad 的媒体管道。

描述

..note:: 这是 media_pipeline_start() 的非锁定版本

void media_pipeline_stop(struct media_pad *pad)

将管道标记为未在流式传输

参数

struct media_pad *pad

起始 pad

描述

将通过启用的链接直接或间接连接到给定 pad 的所有 pad 标记为未在流式传输。 media_pad 的 pipe 字段将重置为 NULL

如果多次调用了 media_pipeline_start(),则需要相同数量的对此函数的调用才能将管道标记为未在流式传输。

void __media_pipeline_stop(struct media_pad *pad)

将管道标记为未在流式传输

参数

struct media_pad *pad

起始 pad

描述

注意

这是 media_pipeline_stop() 的非锁定版本

media_pipeline_for_each_pad

media_pipeline_for_each_pad (pipe, iter, pad)

迭代媒体管道中的所有 pad

参数

pipe

管道

iter

迭代器 (struct media_pipeline_pad_iter)

pad

迭代器焊盘

描述

迭代媒体管道中的所有 pad。这仅在管道已通过 media_pipeline_start() 构建,并在通过 media_pipeline_stop() 销毁之前有效。

int media_pipeline_entity_iter_init(struct media_pipeline *pipe, struct media_pipeline_entity_iter *iter)

初始化管道实体迭代器

参数

struct media_pipeline *pipe

管道

struct media_pipeline_entity_iter *iter

迭代器

描述

必须调用此函数来初始化迭代器,然后才能在 media_pipeline_for_each_entity() 循环中使用。迭代器必须在循环之后通过调用 media_pipeline_entity_iter_cleanup 来销毁(包括从循环中断的代码路径)。

同一个迭代器可以在多个连续循环中使用,而无需销毁和重新初始化。

返回值:

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

void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter)

销毁管道实体迭代器

参数

struct media_pipeline_entity_iter *iter

迭代器

描述

必须调用此函数来销毁使用 media_pipeline_entity_iter_init() 初始化的迭代器。

media_pipeline_for_each_entity

media_pipeline_for_each_entity (pipe, iter, entity)

迭代媒体管道中的所有实体

参数

pipe

管道

iter

迭代器 (struct media_pipeline_entity_iter)

entity

迭代器实体

描述

迭代媒体管道中的所有实体。这仅在管道已通过 media_pipeline_start() 构建,并在通过 media_pipeline_stop() 销毁之前有效。迭代器必须在迭代之前使用 media_pipeline_entity_iter_init() 初始化,并在之后使用 media_pipeline_entity_iter_cleanup() 销毁(包括从循环中断的代码路径)。

int media_pipeline_alloc_start(struct media_pad *pad)

将管道标记为正在流式传输

参数

struct media_pad *pad

起始 pad

描述

media_pipeline_alloc_start() 类似于 media_pipeline_start(),但它不是在给定的管道上工作,而是在 pad 已经是管道的一部分时使用现有管道,否则会分配一个新的管道。

media_pipeline_alloc_start() 的调用必须与 media_pipeline_stop() 匹配。

struct media_intf_devnode *media_devnode_create(struct media_device *mdev, u32 type, u32 flags, u32 major, u32 minor)

创建并初始化一个设备节点接口

参数

struct media_device *mdev

指向结构 media_device 的指针

u32 type

接口的类型,由 include/uapi/linux/media.h 提供(查找 MEDIA_INTF_T_* 宏)。

u32 flags

接口标志,定义在 include/uapi/linux/media.h 中(查找 MEDIA_INTF_FL_*)。

u32 major

设备节点主设备号。

u32 minor

设备节点次设备号。

返回值:

如果成功,则返回指向新分配的

media_intf_devnode 指针。

描述

注意

目前,没有为 media_interface 定义任何标志。

void media_devnode_remove(struct media_intf_devnode *devnode)

移除一个设备节点接口

参数

struct media_intf_devnode *devnode

指向要释放的 media_intf_devnode 的指针。

描述

当设备节点接口被移除时,所有指向它的链接都会被自动移除。

创建一个实体和一个接口之间的链接

参数

struct media_entity *entity

指向 media_entity 的指针

struct media_interface *intf

指向 media_interface 的指针

u32 flags

链接标志,如 include/uapi/linux/media.h 中定义 (搜索 MEDIA_LNK_FL_*)

描述

flags 的有效值

MEDIA_LNK_FL_ENABLED

表示接口已连接到实体硬件。这是接口的默认值。如果硬件由于正在使用其他控制硬件的接口而处于繁忙状态,则可能会禁用接口。

一个典型的例子是混合电视设备,它在给定时间只能处理一种类型的流。因此,当数字电视正在流式传输时,V4L2 接口将不会启用,因为该设备也无法流式传输模拟电视或无线电。

注意

在调用此函数之前,应为接口调用 media_devnode_create(),并且应为将作为链接一部分的接口调用 media_device_register_entity()

移除单个接口链接

参数

struct media_link *link

指向 media_link 的指针。

描述

注意

这是 media_remove_intf_link() 的一个未锁定的版本

移除单个接口链接

参数

struct media_link *link

指向 media_link 的指针。

描述

注意

优先使用此函数,而不是 __media_remove_intf_link()

移除与接口关联的所有链接

参数

struct media_interface *intf

指向 media_interface 的指针

描述

注意

这是 media_remove_intf_links() 的一个未锁定的版本。

移除与接口关联的所有链接

参数

struct media_interface *intf

指向 media_interface 的指针

描述

注意

  1. 当通过 media_device_register_entity() 取消注册实体时,以及通过 media_devnode_remove() 取消注册设备节点时,将自动调用此函数。

  2. 优先使用此函数,而不是 __media_remove_intf_links()

media_entity_call

media_entity_call (entity, operation, args...)

在实体上调用 struct media_entity_operations 操作

参数

entity

将在其上调用 operation 的实体

操作

操作的类型。应该是一个结构体 media_entity_operations 的成员名称。

args...

可变参数

描述

这个辅助函数将检查 operation 是否为 NULL。如果是这种情况,它将发出对 operation(entity, args) 的调用。

media_entity 的两个实例之间创建一个辅助链接

参数

struct media_entity *primary

指向主 media_entity 的指针

struct media_entity *ancillary

指向辅助 media_entity 的指针

描述

在两个实体之间创建一个辅助链接,表明它们代表形成一个逻辑单元的两个连接的硬件。一个典型的例子是连接到其支持的传感器的相机镜头控制器。

该函数为新链接设置 MEDIA_LNK_FL_ENABLED 和 MEDIA_LNK_FL_IMMUTABLE。

遍历一个 media_entity 的链接

参数

struct media_entity *entity

指向 media_entity 的指针

struct media_link *link

指向 media_link 的指针,用于保存遍历的值

unsigned long link_type

MEDIA_LNK_FL_LINK_TYPE 标志之一

描述

返回与特定链接类型匹配的实体的下一个链接。这允许遍历实体的链接,同时保证所有返回的链接都属于给定类型。

for_each_media_entity_data_link (entity, link)

遍历实体的数据链接

参数

entity

指向 media_entity 的指针

链接

指向 media_link 的指针,用于保存遍历的值

描述

遍历一个 media_entity 的数据链接

enum media_request_state

媒体请求状态

常量

MEDIA_REQUEST_STATE_IDLE

空闲

MEDIA_REQUEST_STATE_VALIDATING

正在验证请求,不允许状态更改

MEDIA_REQUEST_STATE_QUEUED

已排队

MEDIA_REQUEST_STATE_COMPLETE

已完成,请求已完成

MEDIA_REQUEST_STATE_CLEANING

正在清理,请求正在重新初始化

MEDIA_REQUEST_STATE_UPDATING

正在更新请求,即正在添加、修改或删除请求对象

NR_OF_MEDIA_REQUEST_STATE

媒体请求状态的数量,内部用于完整性检查

struct media_request

媒体设备请求

定义:

struct media_request {
    struct media_device *mdev;
    struct kref kref;
    char debug_str[TASK_COMM_LEN + 11];
    enum media_request_state state;
    unsigned int updating_count;
    unsigned int access_count;
    struct list_head objects;
    unsigned int num_incomplete_objects;
    wait_queue_head_t poll_wait;
    spinlock_t lock;
};

成员

mdev

此请求所属的媒体设备

kref

引用计数

debug_str

调试消息的前缀(进程名称:fd)

state

请求的状态

updating_count

正在进行的请求更新的数量计数

access_count

正在进行的请求访问的数量计数

objects

struct media_request_object 请求对象列表

num_incomplete_objects

请求中未完成对象的数量

poll_wait

轮询的等待队列

lock

串行化对此结构的访问

int media_request_lock_for_access(struct media_request *req)

锁定请求以访问其对象

参数

struct media_request *req

媒体请求

描述

在访问已完成的请求之前使用。在访问期间必须持有对请求的引用。这通常通过文件句柄自动进行。完成后使用 media_request_unlock_for_access

void media_request_unlock_for_access(struct media_request *req)

解锁之前为访问而锁定的请求

参数

struct media_request *req

媒体请求

描述

解锁先前使用 media_request_lock_for_access 锁定的请求。

int media_request_lock_for_update(struct media_request *req)

锁定请求以更新其对象

参数

struct media_request *req

媒体请求

描述

在更新请求之前使用,即在其添加、修改或删除请求对象。在更新期间必须持有对请求的引用。这通常通过文件句柄自动进行。完成后使用 media_request_unlock_for_update

void media_request_unlock_for_update(struct media_request *req)

解锁之前为更新而锁定的请求

参数

struct media_request *req

媒体请求

描述

解锁先前使用 media_request_lock_for_update 锁定的请求。

void media_request_get(struct media_request *req)

获取媒体请求

参数

struct media_request *req

媒体请求

描述

获取媒体请求。

void media_request_put(struct media_request *req)

释放媒体请求

参数

struct media_request *req

媒体请求

描述

释放媒体请求。当引用计数达到 0 时,媒体请求将被释放。

struct media_request *media_request_get_by_fd(struct media_device *mdev, int request_fd)

通过 fd 获取媒体请求

参数

struct media_device *mdev

此请求所属的媒体设备

int request_fd

请求的文件描述符

描述

获取由媒体设备拥有的 request_fd 表示的请求。

如果此驱动程序不支持请求,则返回 -EBADR 错误指针。如果未找到请求,则返回 -EINVAL。如果找到请求,则返回指向请求的指针:调用者在使用完请求后必须调用 media_request_put

int media_request_alloc(struct media_device *mdev, int *alloc_fd)

分配媒体请求

参数

struct media_device *mdev

此请求所属的媒体设备

int *alloc_fd

将请求的文件描述符存储在此 int 中

描述

分配媒体请求并将 fd 放入 alloc_fd 中。

struct media_request_object_ops

媒体请求对象操作

定义:

struct media_request_object_ops {
    int (*prepare)(struct media_request_object *object);
    void (*unprepare)(struct media_request_object *object);
    void (*queue)(struct media_request_object *object);
    void (*unbind)(struct media_request_object *object);
    void (*release)(struct media_request_object *object);
};

成员

prepare

验证并准备请求对象,可选。

unprepare

取消准备请求对象,可选。

queue

将请求对象排队,可选。

unbind

取消绑定请求对象,可选。

release

释放请求对象,必需。

struct media_request_object

属于媒体请求的不透明对象

定义:

struct media_request_object {
    const struct media_request_object_ops *ops;
    void *priv;
    struct media_request *req;
    struct list_head list;
    struct kref kref;
    bool completed;
};

成员

ops

对象的操作

priv

对象的私有指针

req

此对象所属的请求(可以为 NULL)

list

struct media_request 的对象列表条目

kref

对象的引用计数,在释放 req->lock 之前获取

completed

如果为 true,则此对象已完成。

描述

与请求相关的对象。此结构始终嵌入在另一个包含此请求对象实际数据的结构中。

void media_request_object_get(struct media_request_object *obj)

获取媒体请求对象

参数

struct media_request_object *obj

对象

描述

获取媒体请求对象。

void media_request_object_put(struct media_request_object *obj)

释放媒体请求对象

参数

struct media_request_object *obj

对象

描述

释放一个媒体请求对象。一旦所有引用都消失,该对象的内存将被释放。

struct media_request_object *media_request_object_find(struct media_request *req, const struct media_request_object_ops *ops, void *priv)

在请求中查找对象

参数

struct media_request *req

媒体请求

const struct media_request_object_ops *ops

查找具有此 ops 值的对象

void *priv

查找具有此 priv 值的对象

描述

opspriv 都必须是非 NULL 值。

返回对象指针,如果未找到则返回 NULL。调用者在使用完对象后必须调用 media_request_object_put()

由于此函数需要遍历对象列表,它会获取 req->lock 自旋锁以确保安全。

void media_request_object_init(struct media_request_object *obj)

初始化一个媒体请求对象

参数

struct media_request_object *obj

对象

描述

初始化一个媒体请求对象。一旦对象没有引用(此函数将引用初始化为 1),将使用 ops 的释放回调来释放该对象。

int media_request_object_bind(struct media_request *req, const struct media_request_object_ops *ops, void *priv, bool is_buffer, struct media_request_object *obj)

将媒体请求对象绑定到请求

参数

struct media_request *req

媒体请求

const struct media_request_object_ops *ops

此对象的对象操作

void *priv

与此对象关联的特定于驱动程序的 priv 指针

bool is_buffer

如果对象是缓冲区对象,则设置为 true。

struct media_request_object *obj

对象

描述

将此对象绑定到请求,并设置该对象的 ops 和 priv 值,以便稍后可以使用 media_request_object_find() 找到它。

每个绑定的对象都必须在某个时间点被内核解除绑定或完成,否则请求永远不会完成。当请求被释放时,所有已完成的对象都将被请求核心代码解除绑定。

缓冲区对象将被添加到请求的对象列表的末尾,非缓冲区对象将被添加到列表的前面。这确保了所有缓冲区对象都在列表的末尾,并且它们所依赖的所有非缓冲区对象都首先被处理。

void media_request_object_unbind(struct media_request_object *obj)

解除绑定一个媒体请求对象

参数

struct media_request_object *obj

对象

描述

从请求中解除绑定媒体请求对象。

void media_request_object_complete(struct media_request_object *obj)

将媒体请求对象标记为已完成

参数

struct media_request_object *obj

对象

描述

将媒体请求对象标记为已完成。只有绑定的对象才能被完成。

struct media_device *media_device_usb_allocate(struct usb_device *udev, const char *module_name, struct module *owner)

分配并返回结构体 media 设备

参数

struct usb_device *udev

结构体 usb_device 指针

const char *module_name

应该填充 KBUILD_MODNAME

struct module *owner

驱动程序的结构体模块指针 THIS_MODULE。 对于内置驱动程序,THIS_MODULE 为空。即使 THIS_MODULE 为空也是安全的。

描述

当多个驱动程序共享 usb_device 和媒体设备时,应调用此接口来分配媒体设备。此接口分配 media_device 结构,并调用 media_device_usb_init() 来初始化它。

void media_device_delete(struct media_device *mdev, const char *module_name, struct module *owner)

释放媒体设备。调用 kref_put()。

参数

struct media_device *mdev

结构体 media_device 指针

const char *module_name

应该填充 KBUILD_MODNAME

struct module *owner

驱动程序的结构体模块指针 THIS_MODULE。 对于内置驱动程序,THIS_MODULE 为空。即使 THIS_MODULE 为空也是安全的。

描述

应该调用此接口来释放媒体设备实例的 kref。