SPI总线框架对这两类设备进行管理,具体的框架如图7-6所示。通常的SPI驱动都是在内核实现并在内核态执行的,所以就不对spidev进行详细的分析。SPI总线框架整体的功能就是这样,接下来看看具体各部分的实现。在SPI总线框架中相应的实体是spi_board_info,内容如下:其中的主要信息是与总线信号相关的属性。......
2023-11-22
为了满足以上的需求,视频驱动框架分别在不同的层次进行了设计,以实现不同层面的巨大挑战。
1ᤫ应用层设备访问以及控制
要了解应用层如何访问设备还是先从顶层的文件操作开始,视频框架提供的顶层文件操作接口是v4l2_fops,详细内容如下:
可见与其他类型的功能设备并没有太大的差别,继续从open接口了解框架是如何管理其设备的。
首先代码中出现了CONFIG_MEDIA_CONTROLLER宏,这是可配置单元,与设备内拓扑及连接管理相关,后续会进行详细介绍。从代码分析中可见,函数主要是通过video_devdata来获得一个video_device结构体的指针,紧接着就调用其中的open函数,这个video_device就是针对应用层的管理实体,相应的所有应用层的调用都会通过其中转到实际设备的操作中。这个管理实体如此重要,相应的系统就应该提供其注册函数,其中底层的注册接口是_video_register_device,详细分析如下:
从代码分析中可见,应用层见到的设备文件后面的标号如video0并不是子设备号,而是设备的索引号。在注册中还涉及了ctrl handler和v4l2_fh,都与设备对用户开放的功能相关,后续会进行详细介绍。另外其中还包含了设备连接等信息的初始化。从中可以一定程度上了解视频驱动的框架。不管怎样,对于注册函数,首先应该明确video_device的作用是针对应用层接口的管理实体。下面先来看看video_device的详细内容:
从结构分析中可见,其中提供了两个操作接口:fops和ioctl_ops。fops是针对应用层的操作接口,其形式与文件操作接口基本相似,细节如下:
ioctl_ops是具体设备的ioctl接口。一般来说ioctl直接在应用层操作接口提供即可,为什么又定义一个ioctl_ops来做相关的工作呢?这是由于视频设备的多样性导致其IO控制太多太复杂,视频驱动框架提供了video_ioctl2作为标准的处理,可以在fops中将ioctl设置为video_ioctl2,这样具体的设备只要定义其自身相关的控制接口函数即可。当然驱动也可以完全重新定义自己的ioctl来替代系统提供的标准操作。这样提供了灵活性。
由于视频设备的复杂度高,标准的ioctl操作无法覆盖到所有的设备,设备还需要能对一定范围的量进行控制的接口,而且还要提供一定的扩展性来使得应用层能够对设备特殊参数进行控制,另外还需要能从设备中获得特殊的事件信息。视频驱动框架也考虑到这两种需求,并提供了解决方法。
首先,看一下设备特殊控制的解决方法,该功能不仅需要对单一功能的设备进行支持,当设备有多个功能模块的时候,也需要能够支持。之前在分析音频设备的时候看到,应用层只有一个控制接口,这样可以将所有的控制都加入到该接口中。但是对视频设备并不完全适用,主要是因为视频设备的控制流和数据流在对应用层的接口video_device中很难完全分离,而且某些设备会有多个数据流入口或者出口,这样对一个视频设备来说,会有多个针对应用层的video_device实体以及多个视频文件,但是在设备参数的控制方面最好还是有单一的控制流,这就要求多个功能模块的控制部分能够统一到一起进行管理。
这些控制的统一管理是由结构v4l2_ctrl_handler来完成的。下面来看一下细节:
而实际的控制元素是由struct v4l2_ctrl来表示的,其中包含控制值的类型、范围、属性和操作接口等信息。操作接口由struct v4l2_ctrl_ops来表示,定义的操作接口内容如下:
内核通过ioctl命令对控制进行操作,相关的命令具体包括:
以上是应用层的操作接口,驱动添加控制元素框架也提供了相应的接口。首先要初始化控制管理实体,通过v4l2_ctrl_handler_init来完成。
控制实体系统提供了几种添加的接口函数,具体如下:
系统提供了一些标准的ID来表示相应的控制元素,例如:
以上只是很少的一部分,可见控制包含各种与设备相关的部分,包括视频、图像调整、编解码、音频等各个方面,这些都是设备的需要。
框架还提供了对所有控制元素统一设置的接口v4l2_ctrl_handler_setup来方便设置操作。下面举一个DM 3730中ISP驱动的例子看控制接口是如何使用的。
这里prev是ISP中的一个子设备模块,最终会通过v4l2_ctrl_add_handler将其包含的控制元素加入到ISP设备中统一管理,而在针对应用层管理实体video_device的注册函数中会将其v4l2_ctrl_handler指针指向v4l2_device相同的v4l2_ctrl_handler实体,这样就完成了统一的管理。
另一部分针对应用层的功能是事件的处理,这部分功能需要看一下v4l2_fh结构。
v4l2_events中是所有事件的管理实体,下面来看一下详细的内容:
其操作方式是应用层注册需要关注哪些事件,而内核会对产生的事件加入队列进行管理,并在应用要获得时将事件的详细信息上报。具体的事件是由v4l2_event定义,内容如下:
框架提供了相关的操作接口,具体如下:
另外内核提供了标准的ioctl命令VIDIOC_DQEVENT、VIDIOC_SUBSCRIBE_EVENT和VIDIOC_UNSUBSCRIBE_EVENT来完成这方面的功能。
通过以上的分析,v4l2_fh起到容器的功能,既然是容器应该可以承担更多功能,最新的内核已经包含了v4l2_ctrl_handler,将控制功能包含进来,这样的实现更合理。v4l2_fh就完全包含了对应用层的功能。
2ᤫ设备层次管理
前面部分主要涉及视频驱动框架中对应用层接口实体的管理,框架还需要提供实际设备的管理层。对特定的视频设备,框架的管理实体是v4l2_device。
v4l2_device是对整个视频设备的管理实体,其中可能包含多个子功能模块,而这些子功能模块会作为子设备加入到视频设备中进行管理,从结构中可见视频设备管理实体主要是管理功能,并不包含操作接口,所以这里偏重于逻辑管理,具体功能的操作则由子设备来完成,视频框架中对于子设备进行管理,细节如下:
对子设备特点,系统提供了以下说明:
前面两个是总线接口,后面两个是设备针对应用层的特点,分别表示对应用层的接口设备文件和对应用层的事件,这样系统会根据这些设置做相应的操作。子设备为什么也需要设备文件接口呢?这是由于视频设备中很多子功能模块同样需要应用层操作,如图像的统计模块。由于特殊事件的存在,也需要应用层进行相应的处理,设备文件是最直接的方法,在设备文件注册时系统会对这种子设备的文件名做特殊处理,以进行区分。
子设备驱动相关的操作接口如下:
从中可见,视频子设备的操作是多种多样的,设备驱动可以根据自身的特点选择合适的操作接口进行设置。由于调用子设备的接口比较复杂,视频驱动框架提供了简易的宏方便接口调用,具体如下:
具体调用如:v4l2_subdev_call(sd,core,g_chip_ident,&chip);
这些操作接口可以在内核中使用,另外也允许应用层对一些接口使用,具体的实现方法需要先来看看子设备的注册接口v4l2_device_register_subdev,详细的分析如下:
从代码中可见,子设备文件操作接口定义为v4l2_subdev_fops,这就是转换操作的入口,具体细节如下:
其只定义了部分操作,ioctl也只定义了一部分操作,主要的操作在控制流上,所以对子设备的应用层接口应该主要关心控制部分。
对于不同类型的硬件操作接口,如I2C和SPI,视频驱动框架还提供了简便的绑定接口,具体如下:
整体的针对物理设备的管理层次与组织就通过v4l2_device和v4l2_subdev这两个实体来实现了。
视频驱动系统无论在设备文件层面还是物理设备管理层面都建立了层次关系。在设备文件层面子设备对应的设备文件只有控制特殊事件的功能,并不作为数据流的出口或者入口,而通常的视频功能设备文件会是数据流的出口或者入口,另外一个物理设备可以有多个数据流的出入口,但是它们都会关联到相同的物理设备管理实体v4l2_device。
3ᤫ设备内拓扑及连接管理(www.chuimin.cn)
以上解决的是应用层接口以及设备管理层次的问题,但是设备内部的拓扑以及连接问题还需要解决,而且要提供用户查询设置的接口,这些功能由media controller部分完成。
类似于音频设备,视频设备内部的通道也可以非常复杂,会有节点进行视频流通道切换等操作。这就需要在内部对设备的拓扑以及连接进行定义和管理,在外部还要提供应用层操作的接口。视频驱动框架对这部分的管理由media_device来提供,具体细节如下:
从结构分析中可见,应用层使用media_devnode进行管理,而在内部则通过entity链表进行管理。先来看看内部的管理,内部具体的管理实体是media_entity,详细内容如下:
实际使用时media_entity要嵌入在管理实体中,如之前所见video_device和v4l2_subdev中都包含了media_entity,由于它们都涉及连接与管理。通过type来区分entity的类型,具体分类如下:
这里devnode表示设备文件管理实体中嵌入的entity,而subdev表示子设备中嵌入的entity。
另外entity还包含端点以及连接的属性,这些属性由下面的结构进行管理:
这些端点以及连接也有属性,相应的属性如下:
框架层还提供一些函数对这些管理实体进行操作,相关的接口及说明如下:
这里主要是初始化、设置和遍历,以及流属性设置等操作,实际的设备操作驱动会通过entity获得嵌入entity实际管理的实体进而执行相关的操作。可见在内部media controller的实体主要起到对输入输出端点进行抽象,对连接进行抽象,并将端点和连接进行管理,由于其嵌入到实际的设备管理中,所以可以进行由抽象到具体的转换,从而进行实际的操作。对抽象和具体之间的转换,视频驱动框架也提供了相关的宏,细节如下:
接下来看看应用层接口管理是如何实现的。相应的管理实体由media_devnode来承担,细节如下:
其属性还是很简单的,也留了一定的扩展余地。下面看看相应的注册管理函数的实现。
可见media controller会创建单独的设备文件,并提供统一的文件操作接口media_dev-node_fops用以与应用层交互信息。框架提供了进一步封装的接口media_device_register用于整体的管理实体media_device注册。
可见操作也十分简单,主要是注册了实际的操作接口media_device_fops,该接口支持设备文件操作,具体如下:
通过这些操作就可以实现各个端点能力的查询以及连接的建立,实现整个系统灵活的查询与控制。
4ᤫ数据流
数据流是视频设备操作的核心。其中包括对数据操作区域、数据格式等,而对数据的操作方式是通过buffer queue来进行的,每次操作单个buffer。相应的数据流操作是通过ioctl命令来完成的,系统对于标准的视频设备文件提供的与数据流相关的操作命令如下:
缓冲buffer的类型由枚举定义为以下的类型:
缓冲的内存分配方式通过枚举包含以下的类型:
数据流的具体操作与其类型以及内存分配方式都是相关的,例如对于capture缓冲类型来说,crop是设置图像源的取景区域;而对于output缓冲类型,crop是设置显示图像的区域。需要明确的是format是针对内存中buffer的数据格式属性,crop是根据设备侧的能力的进行相关的范围设置,实际应用中的缩放都是依据这些参数进行的,而只有理解这些参数的明确意义才能更好地使用它们。在内存分配方式方面对数据流的操作也是有影响的,内存是由应用分配还是内核驱动进行分配,相应的操作也是不同的,主要的差别是在分配内存以及映射操作等方面。
视频设备视频流中的内存管理是一个复杂的过程,包括内存分配、各种流程以及状态的管理,还有映射处理等问题,再加上视频设备数据格式的复杂多样(如yuv420sp要求分离的内存块,而yuv422interleave则要求单一的数据块),也加剧了相应管理的复杂性。
内核为了降低视频设备数据流开发的难度,进行了多种技术的开发,从videobuf到videobuf2,以及CMA、DMA、BUF等都是为了提升视频设备的性能,并降低视频设备的开发难度。由于很多技术还比较新,在驱动中还没有广泛的应用,所以这里并不进行完整的详述,只是对videobuf2以及相关技术进行介绍。
videobuf2开发的目的是为驱动提供一组用于管理streaming IO buffer的接口。videobuf2实现了三种buffer内存管理模型,分别如下:
①vmalloc buffer。这类buffer由vmalloc()分配,在内核空间虚拟地址上是连续的。
②contiguous DMA buffers。在物理内存上连续,通常硬件设备需要在连续物理地址空间上执行DMA操作。
③S/GDMAbuffers。在物理内存上是不连续的,如果硬件上支持scatter/gather DMA,驱动可以使用DMA进行操作。
具体的驱动可以选择这三种的一种方式进行管理,由于每种管理模型都提供了类型为vb2_mem_ops的操作接口,具体内容如下:
该操作接口定义了内存分配与管理的标准接口,通过为queue填入不同的操作接口就可以选择不同的管理模型。
解决了整体上的内存管理方式,相应的buffer在不同状态,设备可能需要有不同的操作,为此框架为驱动提供对于buffer在不同状态进行设备设置的接口,具体如下:
以上的接口分别是videobuf2框架需要驱动实现的接口(根据设计某些接口可以不实现),框架层更多的是对buffer的操作以及管理提供统一的操作接口,还需要将buffer转入驱动中进行实际的操作,框架通过驱动提供的buf_queue接口将统一管理的队列转入驱动进行操作,相应的需要将buffer从驱动转入框架统一管理,框架提供了接口函数vb2_buffer_done来进行该操作,驱动也需要将buffer的状态信息报告给框架,该接口在驱动操作完一个buffer后使用。
以上是驱动的接口,另外videobuf2框架为了驱动的应用层操作方便提供了标准的操作函数接口,具体如下:
驱动可以直接在ioctl中调用相应的接口,从而简化操作并且避免错误。
下面是使用videobuf2的例子,主要是在初始化时的操作。
可见,这类统一的buffer queue管理,主要的功能是在应用层到驱动层之间对buffer queue以及buffer的操作标准化,在应用层到驱动之间建立一层完整的、健壮的数据管理层,从而简化驱动的开发,避免错误。相应的在接口设计方面,通过对buffer不同状态的细化为驱动的操作保留相应的接口,从而提高框架的适用范围,提升整个系统的可移植性以及稳定性。
无论怎样,不同的框架单个buffer的管理实体通常是v4l2_buffer或者相应的变种,相应的细节如下:
相应的信息可以在内核使用,也可以在应用层使用,是一种标准的结构。
关于视频驱动的数据流,还有一部分视频子设备相关的操作。具体操作如下:
可见只有数据格式的操作,并没有对流的操作。这是由于子设备通常是数据流中的一个节点,而视频设备的数据出口或者入口是对应于内存中的buffer的,在单纯的子设备中并没有该功能,也就不需要进行相关的操作了。
从整体上讲,视频设备的数据流管理的主要工作就是保证各个节点格式以及能力的正确设置,并且保证数据的正确操作和处理。
有关深入剖析Linux内核与设备驱动的文章
SPI总线框架对这两类设备进行管理,具体的框架如图7-6所示。通常的SPI驱动都是在内核实现并在内核态执行的,所以就不对spidev进行详细的分析。SPI总线框架整体的功能就是这样,接下来看看具体各部分的实现。在SPI总线框架中相应的实体是spi_board_info,内容如下:其中的主要信息是与总线信号相关的属性。......
2023-11-22
也正是因为Linux内核的唯一性,各个不同发布版本拥有相同的框架。Linux内核是在整个Linux系统的最底层,它负责管理硬件,运行用户程序,并保持系统整体的安全性和完整性。可以说是Linux系统的根和灵魂。图3-1中看到Linux内核还有另一层面的含义。这对于Linux内核同样适用。所以对Linux内核的剖析、学习和研究也不能独立于系统进行,而是要综合考虑应用、内核和硬件等各方面的信息和内容。这样才能更全面、深刻地理解Linux内核。......
2023-11-22
整体的frame buffer框架如图6-5所示。了解frame buffer的框架还要先从为用户提供的接口开始。图6-7可变参数中硬件信息的含义固定信息是在frame buffer的操作过程中并不发生变化的。从整体分析,frame buffer的框架很直接,主要就是直接管理实际的设备,而相关的操作与应用层直接相关。......
2023-11-22
对视频应用来说,主要就是获取视频流的操作。设备的适配同样需要实现HAL层,相应的HAL层实体初始化的操作如下:Android框架加载了相应的HAL模块后,就会通过相应的camera_ops来操作,而这些操作都是适配操作,实际上是调用V4L2CameraHardware中的实际为CameraHardware的函数。Android的适配在使用流程上与应用的实例是相同的,只是在操作上封装成不同的接口,而且将参数与数据流控制分离,这样方便了管理,也易于与其他模块交互。......
2023-11-22
VFS的实现是以“一切皆是文件”为需求出发点的。要理解VFS的框架首先看一下VFS和系统的静态关系框图,如图5-1所示。从图5-1可见,VFS是用户层的直接接口,是面向用户的服务。图5-1VFS和系统静态关系图在图5-2中每个节点被使用时都会在VFS层中创建dentry,这样可以快速通过文件名进行查找和定位,Linux内核中对dentry的管理组织形式如图5-3所示。以上是系统运行时VFS对文件名的组织管理,这是VFS管理的一个方面。......
2023-11-22
对视频驱动的具体实现,以DM3730 ISP驱动的设计与实现为例进行介绍。ISP驱动中使用isp_video作为以上单一矩形节点的抽象以及管理实体。可见实际的操作是由子设备完成的,子设备与具体功能相关。具体如下:这里操作的主要目的就是注册v4l2的子设备和I2C的设备,通过I2C总线适配将视频子设备与I2C的Camera Sensor关联起来,从而实现完整的驱动和设备连接。......
2023-11-22
1框架总体设计从输入设备框架的需求可知,内核的整个输入流程应该分为下层的各种输入设备和上层与用户的控制信息交互两个方面。从图6-1可见,输入设备系统框架的核心部分从底到上分为input driver,input core和event handler三个部分。应用层则要根据输入设备的事件进行相应的操作,为了给应用层统一的接口,输入设备框架对于输入事件进行了规范。......
2023-11-22
考虑到电源管理的需求涉及处理器和各种设备,一方面是处理器尽可能减少功耗,另一方面是设备尽可能减少功耗。图5-30Linux电源管理各个功能从图5-30可见Linux内核的电源管理功能有与处理器相关的CPUIdle和CPUFreq,也有与设备相关的runtime pm,另外还有与整个系统待机时SLM相关的低功耗电源管理功能。下面分别对这些功能框架进行介绍。具体的驱动同样会在SoC电源管理部分进行讲解。对具体设备的电源管理实现,将在设备驱动中进行详细分析。......
2023-11-22
相关推荐