内核spi驱动流程图

1. module_init 与 module_exit 这两个是在模块加载和卸载时需要使用

c 复制代码
流程1: module_init -> spi_register_driver

2. 驱动开发填充两个结构体 XXX_device xxx_driver(spi_driver)

3. 定义一个spi_driver,里面包含了device_driver 基类

1)在spi_register_driver时,匹配会去执行probe函数

2)id_table 和driver结构体中,填充和device匹配的名称

c 复制代码
struct spi_driver {
        const struct spi_device_id *id_table;
        int                     (*probe)(struct spi_device *spi);
        int                     (*remove)(struct spi_device *spi);
        void                    (*shutdown)(struct spi_device *spi);
        struct device_driver    driver;
};
c 复制代码
流程2:                     
spi_register_driver(spi_driver) -> __spi_register_driver(spi_driver) -> driver_register(device_driver) ->  bus_add_driver(device_driver) -> driver_attach(device_driver) -> __driver_attach(在driver注册的总线bus_type上找设备(spi_device))  -> really_probe -> probe(回调到spi_driver)

设备树解析
设备树中的设备(device)是用来描述硬件资源的存在
被内核解析,生成一个 struct device_node;
再由 platform 总线(或其他总线)创建 platform_device/ spi_device等对象;
匹配上驱动的 platform_driver 后调用驱动中的 probe() 函数;

4. 定义一个XXX_device

1) spi_driver 中的probe函数执行

2) 创建cdev设备,这个是给用户层的接口,供用户进行系统调用

3) 创建类class_create

4) 根据定义的XXX_device创建设备

c 复制代码
流程3: 
probe(回调到spi_driver) -> cdev_add (创建cdev设备,设备中包含ops调用接口) -> class_create(创建类) -> device_create(创建 /dev 节点,并连接到类 以及cdev设备接口)
c 复制代码
struct xxx_dev
{
        dev_t devid;                                                    /* 设备号 */                                 
        struct cdev cdev;                                               /* cdev */
        struct class *class;                                    /* 类 */
        struct device *device;                                  /* 设备 */
        struct device_node *nd;                                 /* 设备节点 */
        int major;                                                              /* 主设备号 */
        int pdwn_gpio;
        int cs_gpio;                                                    /* cs所使用的GPIO编号 */
        int reset_gpio;                                                 /* reset所使用的GPIO编号 */
        int drdy_gpio;                                                  /* drdy所使用的GPIO编号 */
        unsigned char channels[8];                              /* 采样通道,最多8个 */
        unsigned char channel_num;                              /* 采样通道数量 */
        int delay_us;                                                   /* 采样间隔时间 */
        void *private_data;                                             /* 私有数据 */
};

匹配结构体流程如下:


升入剖析下结构体的定义:(ads1256 spi 设备)

平台驱动结构体

c 复制代码
static struct spi_driver ads1256_driver = { 
        .probe = ads1256_probe,
        .remove = ads1256_remove,
        .driver = { 
                .owner = THIS_MODULE,
                .name = "ads1256",                                                                                   
                .of_match_table = ads1256_of_match,
        },  
        .id_table = ads1256_id,
};

为什么是上面定义(总线设备驱动模型)

  1. spi_driver 承载着总线驱动的功能,当总线驱动注册时,找到匹配的总线设备后,需要执行我们的回调函数probe函数。
  2. 当卸载时,我们需要remove相应总线下的子设备。
  3. 其他的是需要与总线设备匹配的总线驱动名称。

平台设备结构体

c 复制代码
struct spi_device {
        struct device           dev;
        struct spi_master       *master;
        u32                     max_speed_hz;
        u8                      chip_select;
        u8                      bits_per_word;
        u16                     mode;
        int                     irq;
        void                    *controller_state;
        void                    *controller_data;
        char                    modalias[SPI_NAME_SIZE];
        int                     cs_gpio;        /* chip select gpio */

        /* the statistics */
        struct spi_statistics   statistics;
};
  1. 平台设备也作为一个设备存在dev,也是作为一个设备注册。
  2. 平台设备作为主设备时的一些参数
  3. 其他就是spi设备的一些具体参数,中断号、模式 、速度等。

spi平台设备下具体设备

c 复制代码
struct ads1256_dev
{
        dev_t devid;                                                    /* 设备号 */
        struct cdev cdev;                                               /* cdev */
        struct class *class;                                    /* 类 */
        struct device *device;                                  /* 设备 */
        struct device_node *nd;                                 /* 设备节点 */
        int major;                                                              /* 主设备号 */
        int pdwn_gpio;
        int cs_gpio;                                                    /* cs所使用的GPIO编号 */
        int reset_gpio;                                                 /* reset所使用的GPIO编号 */
        int drdy_gpio;                                                  /* drdy所使用的GPIO编号 */
        unsigned char channels[8];                              /* 采样通道,最多8个 */
        unsigned char channel_num;                              /* 采样通道数量 */
        int delay_us;                                                   /* 采样间隔时间 */
        void *private_data;                                             /* 私有数据 */
};
  1. 作为一个设备注册device
  2. 所属类class
  3. 字符设备cdev
  4. 以及具体设备的一些数据参数
相关推荐
坤坤子吖3 分钟前
Linux网络编程:TCP服务器的多进程与多线程实现
linux·服务器·开发语言·网络·c++·笔记·学习
阡陌数智16 分钟前
Claude API新版本重大变更与安全升级指南
java·linux·安全
奶茶树28 分钟前
【Linux】环境开发工具(vim,gcc,g++,Makefile)
linux·运维·vim
木子欢儿4 小时前
国内 macOS/Linux 安装 rust
linux·运维·服务器·macos·rust
say_fall4 小时前
【Linux网络编程】计算机网络基础:局域网与广域网、OSI七层模型与TCP/IP五层模型、封装解包与MAC/IP地址、端口号与socket编程接口
linux·网络·tcp/ip·计算机网络·信息与通信
进击的荆棘4 小时前
Linux系统——线程同步与互斥
linux·运维·服务器·策略模式·同步·互斥·posix
橙橙笔记5 小时前
QT的学习第四部分
linux·qt·学习·音视频
.道阻且长.5 小时前
Linux基本开发工具:gdb和cgdb的使用
linux·运维·服务器·开发语言
叼烟扛炮5 小时前
Linux 学习笔记(五十四):内网穿透实战——用 frp 让外网访问你的私人电脑
linux·服务器·网络·笔记·学习
Android系统攻城狮5 小时前
Linux FFmpeg深度解析之av_guess_format调用流程与实战(三十六)
linux·运维·服务器·ffmpeg·ffmpeg音视频进阶