一、IIO子系统各数据结构说明
IIO子系统大概包含几个主要的部分
对于连续数据采集相关功能,主要由iio buffer实现;
连续数据采集的触发机制,主要由iio trigger实现;
IIO device的事件触发机制,主要由iio event实现;
提供单次原始数据的采集功能,主要通过syfs属性文件实现。
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的缓存、缓存数据是否有效、从缓存中读取数据等等接口。
二、数据结构
struct iio_dev
</include/linux/iio/iio.h>
/*DIRECT_MODE表示不对采集数据进行缓存,可直接读取单次的数据(可通过访问sysfs下的属性文件方式,读取数据);
*INDIO_BUFFER_XXX表示支持对iio device采集数据进行缓存的模式,可理解为采集连续的数据(这些数据则需要通过
*访问字符设备文件进行读取);
*NDIO_EVENT_TRIGGRED则主要表示事件触发功能,如针对温度传感器可监控当前温度是否超过温度告警上限或下限,
*当出现温度告警后则向SOC发送中断信号,若支持这类功能则增加INDIO_EVENT_TRIGGRED模式的支持即可。*/
#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
#define INDIO_HARDWARE_TRIGGERED 0x20
</include/linux/iio/iio.h>
struct iio_dev {
int id;
struct module *driver_module;
int modes;//表示设备支持的不同模式
int currentmode;//设备实际使用的模式
struct device dev;//IIO设备绑定的设备
struct iio_event_interface *event_interface;//事件相关的数据结构
struct iio_buffer *buffer;//该iio device对应的iio buffer
struct list_head buffer_list;
//表示单次采集数据的长度,该值主要根据当前active channel的个数、每一个通道采集数据的长度计算而得
int scan_bytes;
struct mutex mlock;
const unsigned long *available_scan_masks;//表示当前iio device可使用的channel的掩码
unsigned masklength;
const unsigned long *active_scan_mask;//已启用通道的位掩码
bool scan_timestamp;// 对于通过buffer采集的数据是否需要时间戳
unsigned scan_index_timestamp;
struct iio_trigger *trig;//当前设备的触发器
bool trig_readonly;
struct iio_poll_func *pollfunc;//为buffer的中断处理函数的接口信息
struct iio_poll_func *pollfunc_event;//为event的中断处理函数的接口信息,基本不用
struct iio_chan_spec const *channels;//所有channel相关的参数信息
int num_channels;//指定通道数量
struct list_head channel_attr_list;//包含了IIO子系统为所有channel创建的动态属性
struct attribute_group chan_attr_group;
const char *name;//设备名称
const struct iio_info *info;//来自驱动程序的回调和常量信息
clockid_t clock_id;
struct mutex info_exist_lock;
//启用/禁用缓冲区之前和之后调用的一组回调函数
const struct iio_buffer_setup_ops *setup_ops;//建立buffer与trigger的关联
struct cdev chrdev;//IIO内核创建的相关字符设备
#define IIO_MAX_GROUPS 6
const struct attribute_group *groups[IIO_MAX_GROUPS + 1];
int groupcounter;
unsigned long flags;
#if defined(CONFIG_DEBUG_FS)
struct dentry *debugfs_dentry;
unsigned cached_reg_addr;
#endif
};
struct iio_event_interface
struct iio_event_interface {
/*当应用程序读取触发事件信息时,若当前无数据可读,则将当前进程加入到该等待队列,
*待调用iio_push_event将触发事件信息加入kfifo后,则wakeup该队列中的进程*/
wait_queue_head_t wait;
DECLARE_KFIFO(det_events, struct iio_event_data, 16);//定义kfifo,存储所有触发的事件信息,供应用程序获取
/*将even子模块动态定义的event attribute均添加至该链表中(属性名称格式为
*{iio_dir}_{iio_channel_type}{channel-Index/channel_modify}_{ev_type}_{ev_dir}_{ev_info})*/
struct list_head dev_attr_list;
//标记该event是否已使能,(即应用程序是否通过ioctl调用创建一个匿名fd,若使能则置位IIO_BUSY_BIT_POS)
unsigned long flags;
struct attribute_group group;
struct mutex read_lock;
};
三、IIO_buffer与struct iio_buffer_setup_ops
对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机制
</include/linux/iio/trigger.h>
struct iio_trigger {
const struct iio_trigger_ops *ops;
struct module *owner;
int id;
const char *name;
struct device dev;
struct list_head list;
struct list_head alloc_list;
atomic_t use_count;
/*主要用于创建虚拟的irq chip,在trigger内部,当多个trigger consumer注册时,
*则trigger内部会为其分配一个虚拟的irq,并根据trigger consumer提供给pollfunc,
*为该irq注册中断处理函数,这样当该trigger触发后,则会遍历所有该trigger上已注
*册的虚拟irq,调用其中断处理函数从而执行trigger consumer提供的处理函数*/
struct irq_chip subirq_chip;
int subirq_base;
struct iio_subirq subirqs[CONFIG_IIO_CONSUMERS_PER_TRIGGER];
unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)];
struct mutex pool_lock;
bool attached_own_device;
};
struct iio_trigger_ops {
int (*set_trigger_state)(struct iio_trigger *trig, bool state);//设置trigger的状态(使能与否)
int (*try_reenable)(struct iio_trigger *trig);//重新使能
//如实现的trigger只允许父device相同的iio device绑定,则可以实现该接口进行限制操作
int (*validate_device)(struct iio_trigger *trig,
struct iio_dev *indio_dev);
};
四、struct iio_chan_spec
</include/linux/iio/iio.h>
struct iio_chan_spec {
enum iio_chan_type type;//指出通道产生的测量类型,包括IIO_TEMP、IIO_VOLTAGE等
int channel;//当indexed设置为1时,指定通道索引
int channel2;//当.modfied设置为1时,指定通道修饰符
unsigned long address;
int scan_index;//表示采集数据的index及数据的类型等(这两个变量主要由buffer使用)
struct {//负责确定如何将通道的值存储到缓冲区中的元素
char sign;//n表示数据的符号,并匹配模式中的[s | u]
u8 realbits;
u8 storagebits;
u8 shift;
u8 repeat;
enum iio_endian endianness; //排序
} scan_type;
long info_mask_separate;//将属性标记为专属于此通道
long info_mask_separate_available;
long info_mask_shared_by_type;//将该属性标记为由相同类型的所有通道共享
long info_mask_shared_by_type_available;
long info_mask_shared_by_dir;//将该属性标记为由相同方向的所有通道共享
long info_mask_shared_by_dir_available;
long info_mask_shared_by_all;//将该属性标记为所有类型的所有通道共享
long info_mask_shared_by_all_available;
const struct iio_event_spec *event_spec; //定义event相关的信息
unsigned int num_event_specs;
const struct iio_chan_spec_ext_info *ext_info;
const char *extend_name;
const char *datasheet_name;
unsigned modified:1;
unsigned indexed:1;//指出通道属性名称是否具有索引
unsigned output:1;
unsigned differential:1;
};
五、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相关的属性参数)