03、IIO数据结构
IIO设备在内核中表示为struct iio_dev的实例,并由struct iio_info结构描述。所有重要的IIO结构都在include/linux/iio/iio.h中定义。
一、iio_dev数据结构
iio_dev结构是描述IIO设备和驱动程序信息的核心结构。它主要说明以下内容:
设备有多少个数据通道?
会明确设备支持多少个数据采集通道。设备支持哪些工作模式?
说明设备可运行的模式,例如:- 单次模式(一次性数据采集)
- 触发缓冲模式(通过触发信号连续采集数据到缓冲区)
驱动程序有哪些功能接口?
列出驱动程序提供的功能接口(例如数据读取、配置控制等),方便其他程序调用这些功能与设备交互。
::: 简单来说,iio_dev结构就像设备的“说明书”,告诉用户设备能做什么、怎么用,以及驱动程序如何与它配合工作。 :::
struct iio_dev {
[...]
int modes;
int currentmode;
struct device dev;
struct iio_buffer *buffer;
int scan_bytes;
const unsigned long *available_scan_masks;
const unsigned long *active_scan_mask;
bool scan_timestamp;
struct iio_trigger *trig;
struct iio_poll_func *pollfunc;
struct iio_chan_spec const *channels;
int num_channels;
const char *name;
const struct iio_info *info;
const struct iio_buffer_setup_ops *setup_ops;
struct cdev chrdev;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
设备支持的模式(modes):
- INDIO_DIRECT_MODE:设备通过标准的sysfs接口直接与用户空间交互。
- INDIO_BUFFER_TRIGGERED:设备支持硬件触发采集。当使用
iio_triggered_buffer_setup()
设置触发缓冲时,系统会自动启用此模式。 - INDIO_BUFFER_HARDWARE:设备自带硬件级数据缓冲区。
- INDIO_ALL_BUFFER_MODES:同时支持上述两种缓冲模式(硬件缓冲+触发模式)。
关键结构体成员:
currentmode:设备当前实际使用的模式(从上述模式中选择)。
dev:设备对应的Linux设备对象(底层设备管理的基础)。
buffer:数据缓冲区。当启用触发缓冲模式时,采集的数据会自动填充到这里,并推送到用户空间。
scan_bytes:单次采集的数据总字节数。用户空间申请的缓冲区大小必须至少等于这个值。
available_scan_masks:允许的通道组合列表。通过位掩码形式指定哪些通道组合可以被同时启用(例如:通道1和3可同时启用)。
active_scan_mask:当前启用的通道集合。用二进制位表示启用的通道,例如:
- 8通道设备启用通道0、2、7时,
active_scan_mask
为二进制10000101
(十六进制0x85
)。 - 驱动会遍历这些启用的通道,将数据填入缓冲区。
- 8通道设备启用通道0、2、7时,
scan_timestamp:是否记录时间戳。若设为
true
,每个数据包末尾会附加一个8字节(64位)的时间戳。
触发与回调机制:
- trig:当前绑定的触发器(当使用缓冲模式时必须配置)。
- pollfunc:触发信号到来时执行的回调函数。
通道管理:
- channels:描述设备所有通道的配置信息(如电压、温度等类型)。
- num_channels:通道总数。
- name:设备名称(用户空间可见的标识符)。
驱动回调与验证:
- info:驱动提供的功能回调(如读写操作、校准等)。
- setup_ops:缓冲区启用/禁用时的钩子函数,包含:
struct iio_buffer_setup_ops {
int (*preenable)(struct iio_dev *); // 启用缓冲前调用
int (*postenable)(struct iio_dev *); // 启用缓冲后调用
int (*predisable)(struct iio_dev *); // 禁用缓冲前调用
int (*postdisable)(struct iio_dev *); // 禁用缓冲后调用
bool (*validate_scan_mask)(...); // 验证用户请求的通道组合是否合法
};
2
3
4
5
6
7
- 若未指定,系统会使用默认实现
iio_triggered_buffer_setup_ops
。
其他组件:
- chrdev:IIO内核为设备创建的字符设备(用户可通过
/dev
接口访问)。
:::
总结
核心流程:设备通过模式(如触发缓冲)管理数据采集,数据经缓冲区传输,通道选择由掩码控制,触发器决定采集时机。
关键点:驱动需配置通道、缓冲区和触发器,通过回调函数控制硬件状态,用户空间通过sysfs或字符设备读取数据。 :::
二、iio_info结构
struct iio_info结构用于声明IIO内核使用的钩子,以读取/写入通道/属性值:
struct iio_info {
struct module *driver_module;
const struct attribute_group *attrs;
int (*read_raw)(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask);
int (*write_raw)(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask);
[...]
};
2
3
4
5
6
7
8
9
10
11
12
13
以下是iio_info结构关键成员的直白解释:
driver_module
模块标识符,确保设备驱动与字符设备正确关联。通常设置为THIS_MODULE,这样系统就知道这个设备属于当前驱动模块。attrs
设备属性集合,用于存储或展示设备的配置信息(比如状态、参数等),方便用户通过sysfs接口查看或修改。read_raw
当用户读取设备sysfs文件时触发的函数。- mask参数:告诉函数需要返回哪种数据类型(比如原始值、标度值等)。
- chan参数:指定当前操作的传感器通道,可能用来获取该通道的采样率或转换原始数据的公式。
write_raw
当用户向设备写入数据时触发的函数。
例如:用来设置传感器的采样频率或其他配置参数。
每个成员的作用都围绕设备的配置、数据读写和状态管理展开,通过回调函数实现用户与硬件的交互。
以下代码显示如何设置iio_info结构:
static const struct iio_info iio_dummy_info = {
.driver_module = THIS_MODULE,
.read_raw = &iio_dummy_read_raw,
.write_raw = &iio_dummy_write_raw,
[...]
/*
* 提供特定设备类型的接口函数和常量数据
*/
indio_dev->info = &iio_dummy_info;
2
3
4
5
6
7
8
9
三、IIO通道
通道代表单条采集线。例如,加速度计有3个通道(X、Y、Z),因为每个轴代表单个采集线。struct iio_chan_spec结构表示和描述内核中的单个通道:
struct iio_chan_spec {
enum iio_chan_type type;
int channel;
int channel2;
unsigned long address;
int scan_index;
struct {
charsign;
u8 realbits;
u8 storagebits;
u8 shift;
u8 repeat;
enum iio_endian endianness;
} scan_type;
long info_mask_separate;
long info_mask_shared_by_type;
long info_mask_shared_by_dir;
long info_mask_shared_by_all;
const struct iio_event_spec *event_spec;
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;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
以下是关于 iio_chan_spec
结构的简单解释:
结构体字段含义
type
指定通道测量的数据类型。例如:- 电压传感器用
IIO_VOLTAGE
, - 光线传感器用
IIO_LIGHT
, - 加速度计用
IIO_ACCEL
。
所有类型在头文件types.h
的enum iio_chan_type
中定义。
- 电压传感器用
channel
当indexed
设为 1 时,表示通道的编号(索引号)。channel2
当modified
设为 1 时,表示通道的修饰符(例如方向或轴向)。例如:IIO_MOD_X
表示 X 轴,IIO_MOD_Y
表示 Y 轴。
modified
如果设为 1,说明channel2
中的修饰符有效(如传感器方向)。indexed
如果设为 1,说明该通道需要编号(索引号),具体编号在channel
字段中指定。scan_index 和 scan_type
scan_index
指定通道在数据缓冲区中的位置,数值小的通道排在前面。- 如果
scan_index
设为 -1,则该通道不会被缓冲存储。 scan_type
描述数据的格式(如字节顺序、位宽)。
属性掩码(info_mask)
这些掩码决定哪些传感器属性会暴露给用户空间程序:
- info_mask_separate
该属性仅属于当前通道,其他通道无法共享。 - info_mask_shared_by_type
同一类型的通道(例如所有电压传感器)共享该属性。 - info_mask_shared_by_dir
同一方向的通道(例如所有 X 轴传感器)共享该属性。 - info_mask_shared_by_all
所有通道共享该属性,无论类型或方向。
常见属性枚举
以下是一些常见的传感器属性(如 IIO_CHAN_INFO_SCALE
表示传感器的灵敏度):
enum iio_chan_info_enum {
IIO_CHAN_INFO_RAW, // 原始数据值
IIO_CHAN_INFO_SCALE, // 数据缩放比例(如电压转换系数)
IIO_CHAN_INFO_OFFSET, // 数据偏移量
IIO_CHAN_INFO_SAMP_FREQ, // 采样频率
IIO_CHAN_INFO_FREQUENCY, // 信号频率
// 其他属性...
};
2
3
4
5
6
7
8
数据排序方式
scan_type
中的 enum iio_endian
定义数据的字节顺序:
IIO_CPU
:使用 CPU 默认的字节顺序(大端或小端)。IIO_BE
:强制大端模式(高位字节在前)。IIO_LE
:强制小端模式(低位字节在前)。
:::
总结
type 定义传感器类型,channel 和 channel2 标识通道编号或方向,
scan_index 控制数据在缓冲区中的位置,
info_mask 决定属性的共享范围,
枚举值描述传感器的具体参数(如灵敏度、频率)。
这些设置帮助内核正确管理传感器数据,并将信息清晰地传递给用户空间程序。 :::