LINUX IIO子系统分析之二 IIO子系统相关数据结构分析
上一章我们简要说明了IIO子系统的架构,本章我们通过数据结构的定义,分析IIO子系统的设计实现,本章的主要内容如下:
一、IIO子系统各数据结构说明
二、数据结构间的关联说明
一、IIO子系统各数据结构说明
在上一章我们大概说明了IIO子系统的框架,IIO子系统大概包含几个主要的部分,此处我们再说
明一下:
- 对于连续数据采集相关功能,主要由iio buffer实现;
- 连续数据采集的触发机制,主要由iio trigger实现;
- Iio device的事件触发机制,主要由iio event实现;
- 提供单次原始数据的采集功能,主要通过syfs属性文件实现。
基本就是这些内容,iio子系统主要借助字符设备文件以及sysfs属性文件实现数据的获取与参数设定等操作。
而在iio子系统中,主要包括如下几个数据结构:
- struct iio_dev,描述一个iio device
- struct iio_event_interface,描述iio device的事件触发模块的数据结构;
- struct iio_buffer,描述iio device连续数据采集功能相关的数据结构;
- struct iio_trigger,描述iio device的trigger机制相关的数据结构
- struct iio_chan_spec,描述iio device的一个通道的属性信息;
- struct iio_info,描述iio device各通道的原始数据读取接口、event使能与event参数读写相关接口、trigger有效性检测接口、设备树节点解析等接口;
- struct iio_buffer_setup_ops,描述iio buffer使能与否的接口(建立iio buffer与iio tigger的关联,从而保证iio trigger触发后,可将数据刷新到对应的iio buffer中);
- struct iio_chan_spec_ext_info,描述一个channel扩展属性相关的信息,包括属性名称、读写接口等
- struct iio_trigger_ops,表示iio trigger的操作接口,包括设置trigger的状态(使能与否)、重新使能trigger、设备有效性判断等接口;
- struct iio_buffer_access_funcs,描述iio buffer的access接口,包括数据写入到iio buffer的缓存、缓存数据是否有效、从缓存中读取数据等等接口。
基本上就是这些数据结构,iio子系统的数据结构比较多,但是数据结构间的关联并不太复杂,主要就是数据结构太多了。下面我们对每一个数据结构进行简要说明
struct iio_dev
该数据结构表示一个iio device,它属于IIO子系统中的核心数据结构,它负责将所有的IIO子系统的数据结构关联起来,下面即是该数据结构主要的内容,下面我们分几部分进行说明。
- modes与currentmode表示该iio device支持的模式及当前所处的模式,目前支持的模式如下,DIRECT_MODE表示不对采集数据进行缓存,可直接读取单次的数据(可通过访问sysfs下的属性文件方式,读取数据);INDIO_BUFFER_XXX表示支持对iio device采集数据进行缓存的模式,可理解为采集连续的数据(这些数据则需要通过访问字符设备文件进行读取);INDIO_EVENT_TRIGGRED则主要表示事件触发功能,如针对温度传感器可监控当前温度是否超过温度告警上限或下限,当出现温度告警后则向SOC发送中断信号,若支持这类功能则增加INDIO_EVENT_TRIGGRED模式的支持即可(事件告警信息也是通过访问字符设备文件读取,但这个字符设备文件有点特殊,其是一个匿名文件)。
/* Device operating modes */
#define INDIO_DIRECT_MODE 0x01
#define INDIO_BUFFER_TRIGGERED 0x02
#define INDIO_BUFFER_SOFTWARE 0x04
#define INDIO_BUFFER_HARDWARE 0x08
#define INDIO_EVENT_TRIGGERED 0x10
- dev则主要借助系统的设备驱动模型,实现对iio device的引用计数,并绑定至iio总线上,同时借助设备驱动模型可在sysfs目录下创建该iio dev的目录,并创建该iio device所有属性文件等等;
- event_interface表示event事件相关的数据结构,该数据结构内部包含一个kfifo,存储iio device push的event信息;
- buffer表示该iio device对应的iio buffer,若系统不支持buffer模式,则无需创建该buffer;
- buffer_list则在一个iio buffer enable时,将active iio buffer加入到该链表中(目前基本上即将iio_dev->buffer添加到该链表上);
- scan_bytes表示单次采集数据的长度,该值主要根据当前active channel的个数、每一个通道采集数据的长度计算而得;
- available_scan_masks表示当前iio device可使用的channel的掩码(如当前由8个通道,仅前四个通道可用,则可以设置available_scan_maks值为{0x0F}),而active_scan_mask则表示当前已enable的channelmask,该mask是available_scan_masks的子集scan_bytes、available_scan_masks、active_scan_mask主要由iio buffer使用,scan_bytes是单次采集数据的长度,因此通过字符设备文件读取buffer采集数据时,传递的内存长度至少应为scan_bytes;
- scan_timestamp、scan_index_timestamp主要对于通过buffer采集的数据是否需要时间戳,如果需要对采集的数据增加时间戳,则增加IIO_TIMESTAMP类型的虚拟channel,主要用于对采集的数据增加时间戳;
- trig表示一个trigger,针对event、buffer而言,均需要结合trigger机制作为数据可采集的信号,一般在trigger中将event信息、数据信息刷新到event的kfifo或buffer中去(不过目前event信息一般并没有使用trigger机制,大多数event信息均是在event irq的中断处理函数中push到event 的kfifo中,虽然IIO子系统设计上期望通过trigger将数据push到buffer或event上去,但event信息一般并不是连续事件,且trigger内部又实现了虚拟的irq chip,而在虚拟irq的中断处理函数中实现数据push到buffer或event的kfifo中。显然对于event信息处理而言,若使用trigger机制,则多了一个虚拟中断的触发与处理操作,也没有必要啊,因此现有系统中基本上没有使用trigger机制将event信息push到event kfifo的驱动);
- pollfunc、pollfunc_event则为buffer、event的中断处理函数的接口信息(使用的中断即为trigger中virtual irq chip注册的irq),现在仅需要关注pollfunc即可,基本上没有使用pollfunc_event的;
- channels是该iio device所有channel相关的参数信息,我们在iio_chan_spec中将详细说明;
- channel_attr_list链表包含了IIO子系统为所有channel创建的动态属性(针对hwmon子系统我们之前也分析过,其主要通过在sysfs下创建属性文件实现与hwmon device的通信,而IIO子系统也类似,其也在sysfs下创建属性文件实现与iio device的通信,而channel_attr_lis则主要是channel相关的属性的集合);
- groups中包含了所有的group指针,包括channel、event、buffer子模块创建的group,而在调用device_add将该iio device对应的struct device类型变量注册到设备驱动模型子系统中,即遍历该数组,创建属性文件或目录。
- setup_ops则主要是建立buffer与trigger的关联,在该ops中的enable接口中,主要是申请trigger的virt irq chip提供的中断及中断处理函数;在该ops的disable接口中则释放中断。
struct iio_event_interface
该数据结构主要是对event子模块的定义,其中:
- 等待队列wait,当应用程序读取触发事件信息时,若当前无数据可读,则将当前进程加入到该等待队列,待调用iio_push_event将触发事件信息加入kfifo后,则wakeup该队列中的进程;
- 定义kfifo,存储所有触发的事件信息,供应用程序获取;
- 将even子模块动态定义的event attribute均添加至该链表中(属性名称格式为{iio_dir}_{iio_channel_type}{channel-Index/channel_modify}_{ev_type}_{ev_dir}_{ev_info});
- flags标记该event是否已使能(即应用程序是否通过ioctl调用创建一个匿名fd,若使能则置位IIO_BUSY_BIT_POS)
struct iio_buffer与struct iio_buffer_setup_ops
iio_buffer主要是用于存储连续采集数据的缓存,其主要包括两个主要的数据结构struct iio_buffer、struct
iio_buffer_access_func(其实是三个数据结构,还有数据结构struct iio_kfifo,其内部包含struct iio_buffer类型变量和struct kfifo类型变量用于缓存数据)。
针对struct iio_buffer主要包括如下几个方面的内容:
- iio_buffer缓存数据的个数(即length);
- iio_buffer每一次采集数据的长度(bytes_per_datum,而bytes_per_datum*length即为kfifo存储数据的内存空间大小);
- Scan_el_dev_attr_list主要用于将所有iio_buffer子模块创建的属性变量集合在一起(iio_buffer);
- scan_el_attrs存储各设备驱动自行定义的静态属性(生成的属性文件在scan_elements子目录下);
- attrs也是存储存储各设备驱动自行定义的静态属性(该变量定义的属性文件在buffer子目录下);
- buffer_group、scan_el_group包含iio buffer子模块下所有属性,其中buffer_group里的属性均在buffer子目录下创建对应的属性文件;scan_el_group里的属性均在scan_elements子目录下创建对应的属性文件;
- pollq为等待队列,主要为iio device的字符设备文件使用(该字符设备文件对应的读接口和poll接口使用,当buffer中不存在数据时则sleep在该等待队列中);
- watermark为缓存多少个数据后,唤醒pollq(实际内存空间大小为watermark*bytes_per_datum)。
针对struct iio_buffer_access_funcs则是该iio_buffer对应的缓存空间的访问访问,目前使用kfifo缓存数据,则其访问方法为iio_store_to_kfifo、iio_read_first_n_kfifo等,主要是将数据存储至kfifo或从kfifo中取出缓存数据等
struct iio_trigger与struct iio_trigger_ops
这两个数据结构主要实现iio 的trigger机制,类似于led子系统的led trigger。主要内容如下:
- id表示trigger的id、name为名称;
- 该iio trigger也使用struct device类型的变量加入到iio总线上,iio trigger与iio device均注册到iio总线上,因此它们在sysfs目录下是同级的;
- list用于将struct iio trigger添加系统全局链表iio_trigger_list中;
- alloc_list主要用于同一类型的trigger可注册多个trigger实例的请求,如trigger-period则使用该变量将trigger插入到iio_prtc_trigger_list中,目前使用这一变量的trigger并不多;
- 使用计数use_count;
- 而subirq_chip、subirq_base、subirqs、pool则主要用于创建虚拟的irq chip,在trigger内部,当多个trigger consumer注册时,则trigger内部会为其分配一个虚拟的irq,并根据trigger consumer提供给pollfunc,为该irq注册中断处理函数,这样当该trigger触发后,则会遍历所有该trigger上已注册的虚拟irq,调用其中断处理函数从而执行trigger consumer提供的处理函数(关于linux中断子系统的内容可参考我之前写的中断子系统专栏,我在中断子系统专栏也实现了一个虚拟的irq chip,实现的原理和此处trigger实现的虚拟irq chip的原理是一样的)。
iio trigger也提供了操作接口,set_trigger_state主要设置trigger的状态(使能与否)、reenable接口(try_reenable),validate_device(如实现的trigger只允许父device相同的iio device绑定,则可以实现该接口进行限制操作)
struct iio_chan_spec
该数据结构主要说明iio device一个channel的信息,主要涉及struct iio_chan_spec、struct iio_event_spec、struct iio_chan_spec_ext_info
针对struct iio_chan_spec主要涉及如下内容:
- 该channel的类型,channel类型的定义为等等enum iio_chan_type,包括IIO_TEMP、IIO_VOLTAGE等;
- channel表示该channel的index,当indexed为1时,才使用该index表示channel里的属性参数;
- channel2表示channel的别称,当modified为1时,则使用该index对应的string描述channel的别称(如针对三轴陀螺仪而言,如果还使用channel0、channel1进行识别的话不好区分,可使用modified识别为channelX、channelY、channelZ等)
- info_mask_separate表示channel的某一个属性为channel专属的
- Shared_by_type则表示该iio device下所有相同类型channel所共享的属性;
- Shared_by_dir则表示该iio device下所有相同方向channel所共享的属性;
- Shared_by_all则表示该iio device下所有channel所共享的属性
- scan_index、scan_type则表示采集数据的index及数据的类型等(这两个变量主要由buffer使用)
- event_spec定义event相关的信息;
该数据结构定义的变量,主要用于创建channel相关的属性参数,命名规则为{iio_dir}_{iio_channel_type}{channel-Index/channel_modify}_xxx。
而struct iio_event_spec主要内容如下:
- 该event的type、dir,而mask_separate等参数与iio_chan_spec中的info_mask_xxx的意义类似;
而该数据结构体也主要用于创建该channel中event相关的属性参数,属性参数在sysfs文件系统创建的属性文件的名称规则为
{iio_dir}_{iio_channel_type}{channel-Index/channel_modify}_{ev_type}_{ev_dir}_{ev_info})
struct iio_info
该数据结构主要定义了通过syfs读写channel属性的接口,其中read_raw、write_raw可用于读取通道的raw数据等;而write_event_value则主要用于event事件触发的阈值参数的设置与读取等、而read_event_config、write_event_config则可以用于实现event的使能与否;而event_attrs、attrs则主要用于设备驱动自定义的属性参数(包括event属性参数以及iio device相关的属性参数)
二、数据结构间的关联说明
如下为上述这些数据结构间的关联图,通过struct iio_dev,将所有定义的数据结构关联起来,这些数据结构基本上是在iio_device_register时完成关联的。借助这种数据结构间的关联也方便我们较好的理解该子系统的设计实现。
以上即是本章的主要内容,对于iio子系统而言,其定义的数据结构种类虽然多,但大多数数据结构主要用于创建sysfs的attribute而设计的.而真正体现到架构设计部分的设计,主要就是trigger、buffer、event这几个方面,而我认为设计的比较好的就是其trigger机制中,每一个trigger均实现一个虚拟irq chip,对于所有attach到该trigger上的consumer均为其分配虚拟的irq并注册对应的中断处理函数,当一个trigger触发后,则通过generic_handle_irq触发所有已注册的虚拟中断的处理操作。下一章我们就介绍iio trigger的设计。
LINUX IIO子系统分析之二 IIO子系统相关数据结构分析相关推荐
- dev 点击子控件触发panelcontrol事件_LINUX IIO子系统分析之二 IIO子系统数据结构分析...
上一章我们简要说明了IIO子系统的架构,本章我们通过数据结构的定义,分析IIO子系统的设计实现,本章的主要内容如下: 一.IIO子系统各数据结构说明 二.数据结构间的关联说明 一.IIO子系统各数据结 ...
- Linux虚拟化KVM-Qemu分析(二)之ARMv8虚拟化
Table of Contents 1. 概述 2. ARMv8虚拟化 2.1 Exception Level 2.2 Stage 2 translation 2.2.1 内存映射 2.2.2 MMI ...
- LINUX IIO子系统分析之七 虚拟iio device驱动实现
前面几章我们基本完成了IIO子系统的所有内容,而该章即为本专栏的结束篇,主要用来实现一个虚拟的IIO DEVICE DRIVER,本章的内容主要包括如下几部分: 一. 虚拟IIO DEVICE的说明 ...
- Linux Power supply子系统分析之二
1.概述 在上一篇博文中参考窝窝科技的文章分析了linux Power Supply子系统的框架.这篇我们以一个实际的例子来看一下PSY driver的编程方式,比便于更深刻理解power suppl ...
- linux内存管理分析 二,linux内存管理分析【二】
为建立内存管理系统,在内核初始化过程中调用了下面几个函数: init/main.c asmlinkage void __init start_kernel(void) { ...... 初始化持久映射 ...
- linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析
1 mini2440的ADC驱动实例 这节与输入子系统无关,出现在这里是因为后面的章节会讲到触摸屏输入子系统驱动,由于触摸屏也使用ADC,因此本节是为了说明ADC通过驱动代码是如何控制的. ...
- SPI子系统分析之二:数据结构【转】
转自:http://www.cnblogs.com/jason-lu/articles/3164901.html 内核版本:3.9.5 spi_master struct spi_master用来描述 ...
- EMC存储产品介绍分析(二):大数据利器Isilon (2)
3.3.4性能上的线性可扩性 OneFS的一个很重要优势在于能够很方便的为用户扩展容量和性能,并且容量和性能的增长近似线性的关系.下图展示了Isilon容量和性能之间的关系: 另外一个有效的技术使得I ...
- EMC存储产品介绍分析(二):大数据利器Isilon (1)
1.概述 Isilon是EMC收购的NAS集群产品,其最大的特点在于可以进行线性扩展.随着节点数目的增加,Isilon的性能可以线性增长.在大数据时代,和传统的Scale Up存储相比,Isilon是 ...
最新文章
- 计算机科学与技术专业认证研讨,信息学院召开计算机科学与技术专业IEET认证暨人才培养方案修订研讨会...
- 项目管理和缺陷跟踪工具Redmine
- Access快速连接SQL Server的方法(VB代码为例)
- 空缺十年,百度再任命CTO!加盟十年,王海峰现集AI大权为一身
- web开发快速提高工作效率的一些资源
- 给刚入职开发人员的几句心里话
- 爬虫 spider10——搭建elk平台,开发服务提供者
- linux之head命令
- 机器学习硕士、博士如何自救?
- 数字化时代,规模不再是优势
- Android 手机进入不了fastboot模式的解决方案
- 2018年美赛E题M奖论文心得分享
- Unmapped Spring configuration files found.Please configure Spring facet.”
- matlab短均线滞后项,如何解决均线理论时间滞后性? 方法其实很简单!
- C#验证是不是合法的18位身份证号码
- python~运算符_python运算符
- secureCRT免密安装
- github如何开启两步验证
- 【本科课程学习】数据库考试复习题(带答案)
- SpectralNet: Spectral Clustering Using Deep Neural Networks