设备驱动管理
设备驱动管理覆盖从spi_driver注册、匹配、probe 到 remove 的完整生命周期。分五部分讲。
一、struct spi_driver——设备驱动的结构体
定义在spi.h:261~270:
struct spi_driver { const struct spi_device_id *id_table; // 匹配表 int (*probe)(struct spi_device *spi); // probe 回调 int (*remove)(struct spi_device *spi); // remove 回调 void (*shutdown)(struct spi_device *spi);// 关机回调 struct device_driver driver; // 嵌入通用驱动模型 };设备驱动开发者要做的事就是填这个结构体,然后注册到内核。例如一个 SPI 触摸屏驱动:
static const struct spi_device_id my_touch_id[] = { { "edt-ft5406", 0 }, { } }; static struct spi_driver my_touch_driver = { .driver = { .name = "edt_ft5406", // 驱动名字 .of_match_table = my_touch_of_match, // DT 匹配表 }, .id_table = my_touch_id, // id_table 匹配表 .probe = my_touch_probe, .remove = my_touch_remove, }; module_spi_driver(my_touch_driver);二、注册——spi_register_driver
开发者用module_spi_driver宏,展开后实际调用的是spi_register_driver:
// spi.h:283 #define spi_register_driver(driver) \ __spi_register_driver(THIS_MODULE, driver) // spi.h:289 #define module_spi_driver(__spi_driver) \ module_driver(__spi_driver, spi_register_driver, spi_unregister_driver)module_driver宏展开为:
static int __init __spi_driver##_init(void) { return spi_register_driver(&(__spi_driver)); } static void __exit __spi_driver##_exit(void) { spi_unregister_driver(&(__spi_driver)); } module_init(__spi_driver##_init); module_exit(__spi_driver##_exit);所以一个module_spi_driver(my_touch_driver)替换了手写module_init和module_exit的模板代码。
__spi_register_driver(spi.c:389)是关键:
int __spi_register_driver(struct module *owner, struct spi_driver *sdrv) { sdrv->driver.owner = owner; sdrv->driver.bus = &spi_bus_type; // ↑ 告诉内核:这个 driver 挂在 spi 总线上 if (sdrv->probe) sdrv->driver.probe = spi_drv_probe; // 包装 probe if (sdrv->remove) sdrv->driver.remove = spi_drv_remove; // 包装 remove if (sdrv->shutdown) sdrv->driver.shutdown = spi_drv_shutdown; // 包装 shutdown return driver_register(&sdrv->driver); // ↑ 注册到 driver core,加入 spi_bus_type 的 driver 链表 }做了两件事:
- 把 SPI 驱动的回调包装成通用驱动的回调
- 调
driver_register注册到 driver core
注册后 sysfs 中出现/sys/bus/spi/drivers/edt_ft5406/。
三、匹配——spi_match_device
当一个新的spi_device被device_add时,driver core 遍历spi_bus_type上所有已注册的 driver,调.match回调:
// spi.c:294 static int spi_match_device(struct device *dev, struct device_driver *drv) { const struct spi_device *spi = to_spi_device(dev); const struct spi_driver *sdrv = to_spi_driver(drv); // 1. DT compatible 匹配 if (of_driver_match_device(dev, drv)) return 1; // 2. ACPI 匹配 if (acpi_driver_match_device(dev, drv)) return 1; // 3. id_table 匹配 if (sdrv->id_table) return !!spi_match_id(sdrv->id_table, spi); // 4. name 回退匹配 return strcmp(spi->modalias, drv->name) == 0; }spi_match_id逐一比较 id_table 中的 name 和spi->modalias:
static const struct spi_device_id *spi_match_id( const struct spi_device_id *id, const struct spi_device *sdev) { while (id->name[0]) { if (!strcmp(sdev->modalias, id->name)) return id; id++; } return NULL; }设备树中的信息流:
设备树: touch@0 { compatible = "edt,edt-ft5406"; }; ↓ of_modalias_node spi_device.modalis = "edt-ft5406" ↓ spi_match_device → of_driver_match_device spi_driver.of_match_table 中 compatible = "edt,edt-ft5406" → 匹配 ↓ 或走 id_table spi_driver.id_table 中 name = "edt-ft5406" → 匹配四、Probe——spi_drv_probe
匹配成功后,driver core 调sdrv->driver.probe(dev),也就是spi_drv_probe:
// spi.c:335 static int spi_drv_probe(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); struct spi_device *spi = to_spi_device(dev); int ret; // 1. 设置时钟 default ret = of_clk_set_defaults(dev->of_node, false); if (ret) return ret; // 2. 从 DT 获取中断号 if (dev->of_node) { spi->irq = of_irq_get(dev->of_node, 0); if (spi->irq == -EPROBE_DEFER) return -EPROBE_DEFER; if (spi->irq < 0) spi->irq = 0; } // 3. 挂载电源管理域 ret = dev_pm_domain_attach(dev, true); // 4. 调真正的设备驱动 probe if (ret != -EPROBE_DEFER) { ret = sdrv->probe(spi); if (ret) dev_pm_domain_detach(dev, true); } return ret; }设备驱动 probe 的标准写法:
static int my_touch_probe(struct spi_device *spi) { struct my_data *data; // 1. 设置设备参数(如果 spi_add_device 的默认值不合适) spi->mode = SPI_MODE_0; spi->max_speed_hz = 1000000; spi_setup(spi); // ← 调 master->setup 配置硬件 // 2. 分配私有数据 data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL); >// spi.c:363 static int spi_drv_remove(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); int ret; ret = sdrv->remove(to_spi_device(dev)); dev_pm_domain_detach(dev, true); return ret; }设备驱动的 remove 做 probe 的逆操作:释放中断、注销子系统、释放内存。
六、Uevent——spi_uevent
当设备被device_add时,内核想发送一个 uevent 给用户态(udev/mdev),调.uevent回调:
// spi.c:313 static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) { const struct spi_device *spi = to_spi_device(dev); // 优先 ACPI rc = acpi_device_uevent_modalias(dev, env); if (rc != -ENODEV) return rc; // 否则生成 MODALIAS=spi:xxx add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias); return 0; }用户态收到的环境变量:MODALIAS=spi:edt-ft5406。udev 据此自动加载驱动。
七、完整生命周期图
模块加载 │ ├─ module_spi_driver(my_driver) │ └─ module_init → spi_register_driver │ └─ driver_register(&sdrv->driver) │ ├─ sdrv->driver.bus = &spi_bus_type │ └─ 加入 /sys/bus/spi/drivers/my_driver/ │ ├─ [已存在的 spi_device 触发匹配] │ └─ bus_probe_device │ └─ spi_match_device │ ├─ of_driver_match_device ← DT compatible │ ├─ acpi_driver_match_device │ ├─ spi_match_id(id_table) ← name 匹配 │ └─ strcmp(modalias, name) │ ├─ 匹配成功 │ └─ spi_drv_probe │ ├─ 获取 irq │ └─ sdrv->probe(spi) ← 设备驱动开始工作 │ ├─ spi_setup │ ├─ request_irq │ └─ 注册上层子系统 │ ├─ [正常工作] │ └─ spi_sync / spi_async / spi_write_then_read │ ├─ [模块卸载] │ └─ module_exit → spi_unregister_driver │ └─ driver_unregister │ └─ 调 sdrv->remove(spi) │ └─ 释放中断、注销子系统八、设备驱动的两种匹配方式总结
| 匹配方式 | 驱动中提供什么 | 设备中提供什么 | 匹配依据 |
|---|---|---|---|
| DT compatible | driver.of_match_table | DT 节点的compatible | "edt,edt-ft5406"字符串匹配 |
| id_table | id_table数组 | spi_device.modalis | modalias字符串匹配 |
| name 回退 | driver.name | spi_device.modalis | 字符串比较 |