这个文本文件讲述V4L2的框架所提供嘚各种结构以及它们之间的关系.
由于硬件的复杂性v412驱动往往是非常复杂的: 大多数设备有多个IC在/dev目录下有多个设备节点, 并也创建non-V4L2的设备,如DVBALSA,FBI2C和input(IR)设备。
特别是v412驱动支持很多的音频/视频、多路复用/编码/解码芯片使得它比大多数模块更加复杂的。通常这些芯片通过┅个或多个I2C总线被连接到主桥驱动器总线但也可以使用其他总线。这种设备被称为“子设备”
很长一段时间这个框架被限制在video_device结构,鼡来创建v4l设备节点和视频缓冲区处理的video_buf(请注意本文档不讨论video_buf框架)。
这意味着所有驱动程序必须设置设备实例的并连接本身的子设備。这部分是相当复杂很多驱动程序很难这样正确处理。
由于缺乏一个框架使很多共同的代码不可重构因此,这个框架设置所有驱动箌需要的基本结构单元与此相同的框架更容重构被所有驱动共享的相同代码。
driver-global atomic_t实例设置名称这将产生类似于ivtv0,ivtv1等的名字如果名字最後一个数字,然后将它插入一个破折号:cx18-0cx18-1等,这个函数返回的实例数量。
第一个参数‘dev’通常是一个pci_dev\ usb接口或者platform_device的struct device指针dev很少为NULL,但它是ISA设備或一个设备创建的多个PCI设备时这种情况有可能发生。这可能和v4l2_dev的特殊父设备有关系
您也可以提供一个notify()回调子设备,可以通过调鼡子设备通知事件给你取决于你是否需要设置子设备。一个子设备支持的任何通知必须在头文件中定义include/media/<subdevice>.h.
如果你有一个可热插拔设备(如USB設备)然后发生断开连接的时候父设备将变为无效。由于v4l2_device有指向父设备的指针它被清除时,要标记父设备消失要做到这一点调用:
許多驱动程序需要与子设备进行通信。这些设备可以完成所有这类任务
最常用子设备有处理音频 和/或 视频混流、编码或解码器、摄像头传感器和摄像头控制器
通常情况下,它们都是I2C器件但也不全是。为了给这些子设备提供一致的接口v4l2_subdev结构(V4L2 subdev.h)被创创建。
每个子设备驱動程序必须有一个v4l2_subdev结构这个结构可单独作为简单的设备存在或者如果需要存储更多的状态信息时它可能被嵌入在一个更大的结构体中。┅般有一个低级别设备结构(如i2c_client)其中包含通过内核设置的设备数据。建议通过v4l2_set_subdevdata()函数存储这种指针到v4l2_subdev的私有数据这样就会使从v4l2_subdev中佷容易的获取实际的低级总线的特殊设备数据。
还需要一种方法从低级结构体中获取v4l2_subdev对于普通的i2c_client结构体,i2c_set_client()调用时可以保存一个v4l2_subdev指针对于其他的总线可以用相应的方法。
从桥驱动角度来说加载子设备模块和某种方式下v4l2_subdev指针的成员,对于i2c设备来说很容易:可以调用i2c_get_clientdata()函數对于其他总线来说也要用相似的方法。在i2c总线上子设备的协助功能可以让工作更有效
这种设置限制的函数指针的数目,同时还使其噫于添加新操作函数和类别
子设备驱动初始化的v4l2_subdev结构使用:
之后,您需要初始化一个独一无二的名称subdev->name和设置模块所有者这样做是为了洳果你使用的I2C协助功能。
pads数组必须此前已初始化不需要手动设置结构media_entity类型和name字段,但如果需要修改字段必须初始化。
它也可以通过下邊的函数调用全部或部分子设备:
不支持这个OPS的任何子设备跳过并且错误的结构将被忽略如果你想检查是否有错误,使用这个:
任何不昰-ENOIOCTLCMD 的错误将退出循环如果没有错误发生,将返回0.
这两个调用的第二个参数是一组ID如果为0,然后所有subdevs被调用如果不为零,但那么只有那些其组ID匹配值将被调用桥驱动注册一个subdev之前它可以设置sd-> grp_id的值(默认值是0)。这个值被桥驱动器和子设备驱动拥有程序将不会修改或使用它。
这组ID给桥驱动器控制如何调用回调例如,可能有多个音频芯片在板子上每一个都能改变音量。但通常情况下只有一个将被用來当用户想改变音量时被操作你可以设置subdev组ID,例如AUDIO_CONTROLLER和改变指定组ID值时调用v4l2_device_call_all()以确保它只会去的subdev需要。
如果子设备需要通知v4l2_device父设备一個事件那么它可以调用v4l2_subdev_notify(sd,notificationarg).这个宏检查是否有一个notify()的回调函数被定义,如果没有返回-ENODEV否则调用回掉函数并正常返回。
使用v4l2_subdev优勢是它是一个通用结构不包含任何对底层硬件操作。因此驱动程序可能包含几个subdevs使用I2C总线进行控制,但也通过GPIO引脚控制subdev这种区别只昰设置设备时有关,一旦subdev注册是后是完全透明的
事件ioctls函数与V4L2中定义是相同的。他们的行为是相同的唯一不同的是,他们只处理子设备嘚事件产生根据驱动程序,这些控制也可以通过一个(或几个)V4L2的设备节点来报告
没有在上述列表所有ioctls函数调用会直接传递到子设备驅动程序通过core::ioctl操作。
确保remove()回调时被调用时调用v4l2_device_unregister_subdev(sd函数这将从桥驱动中注销子设备,即使是没有注册子设备这个调用也是安全的。
這样做的原因时:当桥式驱动器的注销I2C适配器时remove()回调函数被适配器上的I2C设备调用。这样之后相应v4l2_subdev结构就会变成无效所以它们必须艏先被注销。从remove()回掉函数调用v4l2_device_unregister_subdev(sd)是为了保证这样做的正确性
2)、i2c 从设备地址探测
桥式驱动器也有一些辅助功能,它可以使用:
这個是加载模块(如果没有需要加载的模块可以为NULL)并调i2c_new_device()输入的参数是i2c_adapter和芯片/地址。如果一切顺利那么它注册这个v4l2_device 子设备。
您还可以使鼡v4l2_i2c_new_subdev()最后一个参数传递一个可能的I2C地址数组它可以被探测。如果之前的参数是零那么这些探测地址就会被用。一个非零的参数意味着你囿已知的i2c地址所以在这种情况下,测将不会发生
如果出错了,函数返回NULL
给v4l2_i2c_new_subdev()的chipid参数通常跟模块名称相同。它允许你指定一个芯片嘚变型例如“SAA7114”或“SAA7115”。一般来说虽然I2C驱动程序会自动检测这个。在后些时候要用的的chipid一般是寻找最近。它不同于之间的I2C驱动程序囷因为有时候可能会造成混淆你可以在I2C驱动程序代码的i2c_device_id表中寻找支持该的芯片变种,它将列出所有的可能性芯片
当v4l2_device作为父设备被注册為NULL时,应该设置这个成员这仅仅发生在一个硬件设备有多个PCI设备,并且它们都共享相同的v4l2_device核心.
不要使用ioctl,它在将来会被丢弃。
pad阵列必须預先初始化没有必要手动设置的结构media_entity的 type和name字段。
一个被引用的media 实体在视频设备打开和关闭时自动请求和释放
驱动开发者会来决定用哪种方法然而,你的驱动中有一个很长的延迟操作那么这是就最好不要用这个mutex_lock,而用你自己的锁,这样可以让用户在等待这个长延迟完成时莋其他的工作
如果一个锁被指定,那么所有的文件操作将被依次上锁如果你使用videobuf那么你必须通过相同的锁来锁videobuf队列初始化函数:如果videobuf茬等待一帧到达,那么它要短暂的解锁之后在重新上锁。如果你的驱动程序代码中的存在等待那么你应该在第一个进程等待时,允许其他进程访问该设备节点
2)、设备节点号的获取
最后一个参数给你一定数量的控制了设备使用设备节点(即在videoX中的X)通常情况下只需传-1讓V4L2框架选择第一个空闲的节点号。
但有时用户想指定一个特定的节点号常见的驱动程序允许用户通过驱动模块选项选择一个特定的设备節点号。然后这一数字被传递给video_register_device函数它将尝试选择该设备节点号。如果该节点号已经使用那么下一个空闲的设备节点数量将被选中,哃时会向内核日志发出警告信息
另外使用情况是,如果一个驱动程序创建许多设备在这种情况下它可以是有用的放置在不同范围的不哃视频设备。例如视频捕获设备节点从0开始,视频输出设备节点从16开始
所以,你可以使用最后一个参数指定一个最小设备节点号V4L2框架将尽量选择与你传递的节点号相近的空闲号。如果失败那么它会选择第一个空闲的节点号。
在这种情况下如果你不想关心系统不能夠选择你指定的设备节点时发出的有关警告,可以调用的函数video_register_device_no_warn()代替注册视频设备
3)、系统中设备的属性
每当创建一个设备节点时,咜的的一些属性也会被创建
“index”属性是设备节点的索引:每次调用video_register_device()之后,该索引就会自加1注册第一个视频设备的设备节点总是以0開始的。
用户可以设置udev的规则利用索引属性设置一些花哨的设备名称(如视频捕捉设备节点的名称为mpegX MPEG)。
该设备注册成功之后你可以使用这些字段:
如果注册失败,那么你需要调用video_device_release()来释放分配的video_device结构或者自己定义的嵌入video_deviced的结构。如果注册失败vdev-〉release()回调函数将詠远不会被调用。如果注册失败也不应该尝试注销该设备。
当设备节点被删除、驱动程序被卸载、或因为USB设备被断开那么你应该用下邊函数注销它们:
这将从sysfs系统中移除设备节点(会引起从/dev中移除udev).
video_unregister_device()函数返回之后,没有新的设备打开然而,在这种情况下USB设备一些应用可能仍然有节点打开,因此要注销所有操作函数(除了release() ),有可能返回错误
当最后一个用户视频设备节点退出后,个vdev->release()回调函数被调用莋最后的清除。
如果它已经被初始化媒体视频设备的相关实体那么也要掉用下边的函数清除它:
有一些有用的辅助功能:
A、文件或视频設备的私有数据
可以用下边的操作设置或获取video_device结构体中的驱动私有数据
结构体v4l2_fh提供了一种轻松地保持文件处理特定数据的方法,这个数据被V4L2框架使用新的驱动程序必须使用v4l2_fh结构体,如果的video_device标志中V4L2_FL_USE_FH_PRIO也设置那么它也可以用来实现优先处理VIDIOC_G/ S_PRIORITY)。
下面是一些v4l2_fh函数的简短说明:
事件通过一个类型和一个可选择的ID被定义这个ID可能跟V4L2目标有关系,例如控制ID通常情况下,这个ID为0
当用户要用一个事件时,驱动将会给這个事件分配一个kevent结构体这可以确保驱动在短时间内产生单一类型大量事件时,不会覆盖其他类型的事件
如果你得到的单一类型事件哆于保留的kevents数目时,旧的事件将被丢弃新的事件被添加。
的两个回掉函数merge()和replace()要在驱动中设置当一个新的事件被提高,并且没有更多的涳间时这些回掉函数被调用,replace()被调用时允许用新的事件代替有负载效应的旧事件会将旧事件中相关数据合并到新的事件中去。当这个倳件类型仅仅有一个kevent被分配时会调用它merge()回掉函数允许你合并旧的事件到第二个旧的事件,当两个或更多个kevent被分配时它也会被调用。
这种方法不会有状态信息丢失正确的内部信息导致了这种状态。
使用事件驱动程序必须分配的文件句柄的事件驱动程序通过调用函數不止一次,
可以保证至少n个总事件已分配功能可能无法在原子上下文中被调用。
视频设备的队列中的事件驱动程序的唯一责任是填寫它的类型和数据字段。其他字段将被V4L2填充
在特殊类型V4L2_EVENT_ALL的可能被用来取消所有事件。驱动程序可能用一种特殊的方式来处理这些事件
返回挂起的事件数量。实施调查时非常有用
用户空间通过poll系统调用实现事件的传递,驱动可以用v4l2_fh->wait作为poll_wait调用的参数
有标准的和私有的事件,新的标准事件必须用最小的可用事件类型驱动必须从它们所属的类开始到类基址分配它们的事件。类基址是
类中的第一个事件类型昰被保留将来用的一次第一个有效类类型是“基址+1”