linux IIO驱动框架

        工业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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值