工业IO(Industrial I/O)是专用于ADC和DAC的内核子系统,加速度计、陀螺仪、电流电压测量芯片、光传感器、压力传感器等都属于IIO系列设备。
IIO模型采用设备和通道架构。其中设备属于芯片本身,通道则表示设备的单个采集线,设备可能有若干个通道。例如加速度计就有3个通道,每个轴(X、Y和Z)都有一个通道。
IIO设备和用户空间交互有两种方式:
- /sys/bus/iio/iio:deviceX/,代表传感器及其通道
- /dev/iio:deviceX,字符设备,用于输出设备事件和数据缓冲区
设备驱动程序使用IIO内核提供的功能和API来管理设备,并向IIO内核报告处理情况;IIO内核通过sysfs和字符设备将底层机制抽象到用户空间。
一、IIO数据结构
IIO设备在内核中表示为struct iio_dev{},并由struct iio_info{}结构描述。IIO通道则由struc iio_chan_spec{}表示。
1. 设备结构iio_dev
结构体struct iio_dev{}的定义:
struct iio_dev {
[...]
int modes;
/* 支持不同的模式:
INDIO_DIRECT_MODE: 设备提供/sysfs类型的接口
INDIO_BUFFER_TRIGGERED: 设备支持硬件触发,当使用iio_triggered_buffer_setup()时函数设置缓冲区时,该模式会自动添加到设备;
INDIO_BUFFER_HARDWARE: 该设备支持硬件缓冲区;
INDIO_ALL_BUFFER_MODES: 上述两种模式的组合
*/
struct device dev;
int scan_bytes; // 捕捉并提供给缓冲区的字节数。
const ulong *available_scan_mask;
/*
用来标志那个通道可以启用缓冲,例如三通道设备允许掩码0x7(0b111)和0(0b000),这意味着可以不启用和全部启动,例如不能只启用X和Y,
static const ulong my_scan_masks[] = {0x7, 0x0};
indio_dev->available_scan_masks = my_scan_masks;
*/
const ulong *active_scan_mask;
/* 已启用的通道掩码,只有这些通道的数据才被推入buffer,例如对于8通道的ADC转换器,如果仅启用第一(0)、第三(2)和最后一个(7)通道,则位掩码我0b10000101(0x85),active_scan_mask设置为0x85,然后驱动程序可以使用for_each_set_bit宏遍历每个设备位,获取数据并放入缓冲区中。
*/
bool scan_timestamp; // 是否将捕获时间推入缓冲区,缓冲区作为最后一个元素推入buffer,时间戳是8字节长。
struct iio_trigger *trig; // 当前设备的触发器
struct iio_poll_fun *pollfunc; // 在接收的触发器上运行的函数
struct iio_chan_spec *channels; // 设备通道
int num_channels;
const char *name;
const struct iio_info *info; // 驱动程序的回调和常量信息
const struct iio_buffer_setup_ops *setup_ops; // 用户启用、禁用缓冲区之前和之后的一组函数,如果未指定则使用iio内核默认的函数iio_triggered_buffer_setup_ops
struct cdev chrdev;
};
// 其中结构体struct iio_buffer_setup_ops定义如下:
struct iio_buffer_setup_ops {
int (*preenable)(struct iio_dev *); // enable缓冲之前的回调函数
int (*postenable)(struct iio_dev *); // enable缓冲之后的回调函数
int (*predisable)(struct iio_dev *); // disable缓冲之前的回调函数
int (*postdisable)(struct iio_dev *); // disable缓冲之后的回调函数
int (*validate_scan_mask)(struct iio_dev *indio_dev, const ulong *scan_mask);
};
用于结构体struct iio_dev{}的操作函数:
// iio_dev分配函数
struct iio_dev *iio_device_alloc(int sizeof_priv);
struct iio_dev *devm_iio_device_alloc(int sizeof_priv); // devres版本的alloc函数
void iio_device_free(struct iio_dev);
// iio_dev的注册和注销
int iio_device_register(struct iio_dev *indio_dev);
void iio_device_unregister(struct iio_dev *indio_dev);
// 分配函数使用示例,在驱动程序的probe函数中
struct iio_dev *indio_dev;
struct my_private_data *data;
indio_dev = iio_device_alloc(sizeof(*data));
data = iio_priv(indio_dev);
[...]// 其他配置
iio_device_register(indio_dev);
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); // 用户读取sysfs设备时的会调用函数
int (*write_raw)(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val

最低0.47元/天 解锁文章
180

被折叠的 条评论
为什么被折叠?



