
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,
};
为什么是上面定义(总线设备驱动模型)
- spi_driver 承载着总线驱动的功能,当总线驱动注册时,找到匹配的总线设备后,需要执行我们的回调函数probe函数。
- 当卸载时,我们需要remove相应总线下的子设备。
- 其他的是需要与总线设备匹配的总线驱动名称。
平台设备结构体
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;
};
- 平台设备也作为一个设备存在dev,也是作为一个设备注册。
- 平台设备作为主设备时的一些参数
- 其他就是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; /* 私有数据 */
};
- 作为一个设备注册device
- 所属类class
- 字符设备cdev
- 以及具体设备的一些数据参数