2.5. V4L2 设备实例¶
每个设备实例由 struct v4l2_device
表示。非常简单的设备可以直接分配此结构,但大多数情况下,您会将此结构嵌入到更大的结构中。
您必须通过调用以下函数来注册设备实例:
v4l2_device_register
(dev,v4l2_dev
)。
注册将初始化 v4l2_device
结构。如果 dev->driver_data 字段为 NULL
,它将被链接到 v4l2_dev
参数。
想要与媒体设备框架集成的驱动程序需要手动设置 dev->driver_data 以指向嵌入 struct v4l2_device
实例的驱动程序特定设备结构。这是通过在注册 V4L2 设备实例之前调用 dev_set_drvdata()
实现的。它们还必须设置 struct v4l2_device
mdev 字段以指向已正确初始化和注册的 media_device
实例。
如果 v4l2_dev
->name 为空,则它将被设置为从 dev 派生的值(驱动程序名称后跟 bus_id,更准确地说)。如果您在调用 v4l2_device_register()
之前设置它,则它将保持不变。如果 dev 为 NULL
,则您必须在调用 v4l2_device_register()
之前设置 v4l2_dev
->name。
您可以使用 v4l2_device_set_name()
根据驱动程序名称和驱动程序全局 atomic_t 实例设置名称。这将生成类似 ivtv0
、ivtv1
等名称。如果名称以数字结尾,则它将插入一个破折号:cx18-0
、cx18-1
等。此函数返回实例编号。
第一个 dev
参数通常是 struct device
指针,指向 pci_dev
、usb_interface
或 platform_device
。dev 为 NULL
的情况很少见,但在 ISA 设备或一个设备创建多个 PCI 设备时会发生这种情况,从而无法将 v4l2_dev
与特定父级关联。
您还可以提供一个 notify()
回调,子设备可以调用该回调来通知您事件。是否需要设置此回调取决于子设备。子设备支持的任何通知都必须在 include/media/subdevice.h
中的标头中定义。
V4L2 设备通过调用以下函数注销:
如果 dev->driver_data 字段指向 v4l2_dev
,它将被重置为 NULL
。注销还将自动从设备注销所有子设备。
如果您有一个热插拔设备(例如 USB 设备),则当发生断开连接时,父设备将变为无效。由于 v4l2_device
有一个指向该父设备的指针,因此也必须清除它以标记父设备已消失。为此,请调用
这不会注销子设备,因此您仍然需要调用 v4l2_device_unregister()
函数。如果您的驱动程序不是热插拔的,则无需调用 v4l2_device_disconnect()
。
有时您需要迭代特定驱动程序注册的所有设备。如果多个设备驱动程序使用相同的硬件,通常会发生这种情况。例如,ivtvfb 驱动程序是一个帧缓冲驱动程序,它使用 ivtv 硬件。例如,alsa 驱动程序也是如此。
您可以按如下方式迭代所有注册设备:
static int callback(struct device *dev, void *p)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
/* test if this device was inited */
if (v4l2_dev == NULL)
return 0;
...
return 0;
}
int iterate(void *p)
{
struct device_driver *drv;
int err;
/* Find driver 'ivtv' on the PCI bus.
pci_bus_type is a global. For USB buses use usb_bus_type. */
drv = driver_find("ivtv", &pci_bus_type);
/* iterate over all ivtv device instances */
err = driver_for_each_device(drv, NULL, p, callback);
put_driver(drv);
return err;
}
有时您需要保持设备实例的运行计数器。这通常用于将设备实例映射到模块选项数组的索引。
推荐的方法如下:
static atomic_t drv_instance = ATOMIC_INIT(0);
static int drv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
{
...
state->instance = atomic_inc_return(&drv_instance) - 1;
}
如果您有多个设备节点,则很难知道何时可以安全地为热插拔设备注销 v4l2_device
。为此,v4l2_device
具有引用计数支持。每当调用 video_register_device()
时,引用计数就会增加,每当释放该设备节点时,引用计数就会减少。当引用计数达到零时,将调用 v4l2_device
release() 回调。您可以在那里进行最终清理。
如果创建了其他设备节点(例如 ALSA),您也可以通过调用以下函数手动增加和减少引用计数:
或
由于初始引用计数为 1,因此您还需要在 disconnect()
回调(对于 USB 设备)或 remove()
回调(对于例如 PCI 设备)中调用 v4l2_device_put()
,否则引用计数将永远不会达到 0。
2.5.1. v4l2_device 函数和数据结构¶
-
struct v4l2_device¶
V4L2 设备驱动程序的主要结构
定义:
struct v4l2_device {
struct device *dev;
struct media_device *mdev;
struct list_head subdevs;
spinlock_t lock;
char name[36];
void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);
struct v4l2_ctrl_handler *ctrl_handler;
struct v4l2_prio_state prio;
struct kref ref;
void (*release)(struct v4l2_device *v4l2_dev);
};
成员
dev
指向
struct device
的指针。mdev
指向
struct media_device
的指针,可以为 NULL。subdevs
用于跟踪已注册的子设备
lock
锁定此结构;如果此结构嵌入到更大的结构中,驱动程序也可以使用它。
name
唯一的设备名称,默认情况下为驱动程序名称 + 总线 ID
notify
由某些子设备调用的通知操作。
ctrl_handler
控制处理程序。可以为
NULL
。prio
设备的优先级状态
ref
跟踪对此结构的引用。
release
当引用计数变为 0 时调用的释放函数。
描述
V4L2 设备的每个实例都应创建 v4l2_device 结构,无论是独立的还是嵌入到更大的结构中。
它允许轻松访问子设备(参见 v4l2-subdev.h)并提供基本的 V4L2 设备级支持。
注意
dev->driver_data 指向此结构。
如果没有父设备,则 dev 可能为
NULL
-
void v4l2_device_get(struct v4l2_device *v4l2_dev)¶
获取 V4L2 设备引用
参数
struct v4l2_device *v4l2_dev
指向
v4l2_device
结构的指针
描述
这是一个辅助例程,旨在增加 v4l2_dev 指向的 v4l2_device
结构的使用计数。
-
int v4l2_device_put(struct v4l2_device *v4l2_dev)¶
释放 V4L2 设备引用
参数
struct v4l2_device *v4l2_dev
指向
v4l2_device
结构的指针
描述
这是一个辅助例程,旨在减少 v4l2_dev 指向的 v4l2_device
结构的使用计数。
-
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)¶
初始化 v4l2_dev 并使 dev->driver_data 指向 v4l2_dev。
参数
struct device *dev
指向
device
结构的指针struct v4l2_device *v4l2_dev
指向
v4l2_device
结构的指针
描述
注意
在极少数情况下(ISA 设备),dev 可能为 NULL
。在这种情况下,调用者必须在调用此函数之前填充 v4l2_dev->name 字段。
-
int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, atomic_t *instance)¶
可选函数,用于初始化
v4l2_device
结构的 name 字段
参数
struct v4l2_device *v4l2_dev
指向
v4l2_device
结构的指针const char *basename
设备名称的基本名称
atomic_t *instance
指向具有设备驱动程序的实例用法的静态 atomic_t 变量的指针。
描述
v4l2_device_set_name()
使用驱动程序名称和驱动程序全局 atomic_t 实例初始化 v4l2_device
结构的 name 字段。
此函数将递增实例计数器并返回名称中使用的实例值。
首次调用此函数时,name 字段将设置为 foo0,此函数返回 0。如果名称以数字结尾(例如 cx18),则名称将设置为 cx18-0,因为 cx180 看起来会非常奇怪。
示例
static atomic_t drv_instance = ATOMIC_INIT(0);
...
instance = v4l2_device_set_name(&v4l2_dev, “foo”, &drv_instance);
-
void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)¶
将 V4L2 设备状态更改为已断开连接。
参数
struct v4l2_device *v4l2_dev
指向
struct v4l2_device
的指针
描述
应在 USB 父设备断开连接时调用。由于父设备消失,这可确保 v4l2_dev 没有无效的父指针。
注意
此函数将 v4l2_dev->dev 设置为 NULL。
-
void v4l2_device_unregister(struct v4l2_device *v4l2_dev)¶
注销所有子设备以及与 v4l2_dev 相关的任何其他资源。
参数
struct v4l2_device *v4l2_dev
指向
struct v4l2_device
的指针
-
v4l2_device_register_subdev¶
v4l2_device_register_subdev (v4l2_dev, sd)
向 v4l2 设备注册子设备。
参数
v4l2_dev
指向
v4l2_device
结构的指针sd
指向
struct v4l2_subdev
的指针
描述
注册后,子设备模块将被标记为正在使用。
如果模块不再加载任何注册尝试,则会返回错误。
-
void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)¶
从 v4l2 设备注销子设备。
-
int __v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev, bool read_only)¶
为标记有
V4L2_SUBDEV_FL_HAS_DEVNODE
标志的 v4l2 设备的所有子设备注册设备节点。
参数
struct v4l2_device *v4l2_dev
指向
struct v4l2_device
的指针bool read_only
子设备只读标志。True 以只读模式注册子设备设备节点,false 以允许完全访问子设备用户空间 API。
-
int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)¶
注册具有对子设备用户空间操作的无限制访问权限的子设备设备节点
参数
struct v4l2_device *v4l2_dev
指向
struct v4l2_device
的指针
描述
在内部调用 __v4l2_device_register_subdev_nodes()
。有关更多详细信息,请参见其文档。
-
int v4l2_device_register_ro_subdev_nodes(struct v4l2_device *v4l2_dev)¶
以只读模式注册子设备设备节点
参数
struct v4l2_device *v4l2_dev
指向
struct v4l2_device
的指针
描述
在内部调用 __v4l2_device_register_subdev_nodes()
。有关更多详细信息,请参见其文档。
-
void v4l2_subdev_notify(struct v4l2_subdev *sd, unsigned int notification, void *arg)¶
向 v4l2_device 发送通知。
参数
struct v4l2_subdev *sd
指向
struct v4l2_subdev
的指针unsigned int notification
通知类型。请注意,通知类型是驱动程序特定的。
void *arg
通知的参数。这些参数特定于每种通知类型。
-
bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)¶
测试是否支持请求。
参数
struct v4l2_device *v4l2_dev
指向
struct v4l2_device
的指针
-
v4l2_device_for_each_subdev¶
v4l2_device_for_each_subdev (sd, v4l2_dev)
辅助宏,用于迭代给定
v4l2_device
的所有子设备。
参数
sd
指针,宏将使用所有
struct v4l2_subdev
指针填充该指针,作为循环的迭代器使用。v4l2_dev
struct v4l2_device
拥有要迭代的子设备。
描述
此宏迭代 v4l2_dev 设备拥有的所有子设备。它充当 for 循环迭代器,并执行下一个语句,其中 sd 变量依次指向每个子设备。
-
__v4l2_device_call_subdevs_p¶
__v4l2_device_call_subdevs_p (v4l2_dev, sd, cond, o, f, args...)
为所有匹配条件的子设备调用指定的操作。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。sd
指针,宏将使用所有
struct v4l2_subdev
指针填充该指针,作为循环的迭代器使用。cond
要匹配的条件
o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。args...
f 的参数。
描述
忽略任何错误。
注意
在遍历子设备列表时,无法添加或删除子设备。
-
__v4l2_device_call_subdevs¶
__v4l2_device_call_subdevs (v4l2_dev, cond, o, f, args...)
为所有匹配条件的子设备调用指定的操作。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。cond
要匹配的条件
o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。args...
f 的参数。
描述
忽略任何错误。
注意
在遍历子设备列表时,无法添加或删除子设备。
-
__v4l2_device_call_subdevs_until_err_p¶
__v4l2_device_call_subdevs_until_err_p (v4l2_dev, sd, cond, o, f, args...)
为所有匹配条件的子设备调用指定的操作。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。sd
指针,宏将使用与 v4l2_dev 关联的所有
struct v4l2_subdev
子设备填充该指针。cond
要匹配的条件
o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。args...
f 的参数。
描述
如果操作为任何子设备返回除 0 或 -ENOIOCTLCMD
以外的错误,则中止并返回该错误代码,否则返回零。
注意
在遍历子设备列表时,无法添加或删除子设备。
-
__v4l2_device_call_subdevs_until_err¶
__v4l2_device_call_subdevs_until_err (v4l2_dev, cond, o, f, args...)
为所有匹配条件的子设备调用指定的操作。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。cond
要匹配的条件
o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。args...
f 的参数。
描述
如果操作为任何子设备返回除 0 或 -ENOIOCTLCMD
以外的错误,则中止并返回该错误代码,否则返回零。
注意
在遍历子设备列表时,无法添加或删除子设备。
-
v4l2_device_call_all¶
v4l2_device_call_all (v4l2_dev, grpid, o, f, args...)
为所有匹配
v4l2_subdev.grp_id
的子设备调用指定的操作,如桥接驱动程序分配的。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。grpid
struct v4l2_subdev
->grp_id 要匹配的组 ID。使用 0 匹配所有组。o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。args...
f 的参数。
描述
忽略任何错误。
注意
在遍历子设备列表时,无法添加或删除子设备。
-
v4l2_device_call_until_err¶
v4l2_device_call_until_err (v4l2_dev, grpid, o, f, args...)
为所有匹配
v4l2_subdev.grp_id
的子设备调用指定的操作,如桥接驱动程序分配的,直到发生错误。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。grpid
struct v4l2_subdev
->grp_id 要匹配的组 ID。使用 0 匹配所有组。o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。args...
f 的参数。
描述
如果操作为任何子设备返回除 0 或 -ENOIOCTLCMD
以外的错误,则中止并返回该错误代码,否则返回零。
注意
在遍历子设备列表时,无法添加或删除子设备。
-
v4l2_device_mask_call_all¶
v4l2_device_mask_call_all (v4l2_dev, grpmsk, o, f, args...)
为组 ID 匹配指定位掩码的所有子设备调用指定的操作。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。grpmsk
要对照
struct v4l2_subdev
->grp_id 组 ID 检查的位掩码。使用 0 匹配所有组。o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。args...
f 的参数。
描述
忽略任何错误。
注意
在遍历子设备列表时,无法添加或删除子设备。
-
v4l2_device_mask_call_until_err¶
v4l2_device_mask_call_until_err (v4l2_dev, grpmsk, o, f, args...)
为组 ID 匹配指定位掩码的所有子设备调用指定的操作。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。grpmsk
要对照
struct v4l2_subdev
->grp_id 组 ID 检查的位掩码。使用 0 匹配所有组。o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。args...
f 的参数。
描述
如果操作为任何子设备返回除 0 或 -ENOIOCTLCMD
以外的错误,则中止并返回该错误代码,否则返回零。
注意
在遍历子设备列表时,无法添加或删除子设备。
-
v4l2_device_has_op¶
v4l2_device_has_op (v4l2_dev, grpid, o, f)
检查是否任何匹配 grpid 的子设备具有给定的 ops。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。grpid
struct v4l2_subdev
->grp_id 要匹配的组 ID。使用 0 匹配所有组。o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。
-
v4l2_device_mask_has_op¶
v4l2_device_mask_has_op (v4l2_dev, grpmsk, o, f)
检查是否任何匹配组掩码的子设备具有给定的 ops。
参数
v4l2_dev
struct v4l2_device
拥有要迭代的子设备。grpmsk
要对照
struct v4l2_subdev
->grp_id 组 ID 检查的位掩码。使用 0 匹配所有组。o
struct v4l2_subdev_ops
中包含 f 的元素的名称。那里的每个元素都对一组操作函数进行分组。f
如果 cond 匹配,将调用的操作函数。操作函数根据
struct v4l2_subdev_ops
中的每个元素,按组定义。