1. Linux设备驱动模型概述
Linux 内核从 2.6 版本开始引入统一的设备驱动模型(Device Driver Model),其核心目标是将系统中所有的硬件设备、总线以及对应的驱动程序以标准化的方式组织起来,实现热插拔、电源管理、设备枚举与自动匹配等关键特性。该模型围绕三个核心要素构建:总线(Bus)、设备(Device) 和 驱动(Driver)。
核心思想: 总线是连接设备和驱动的桥梁。设备挂载在总线上,驱动注册到总线上,总线负责将两者进行匹配,匹配成功后调用驱动的 probe 函数完成初始化。
1.1 三要素定义与职责
| 要素 | 内核数据结构 | 核心职责 | 典型示例 |
|---|---|---|---|
| 总线 (Bus) | struct bus_type |
管理设备和驱动的注册/注销;维护设备链表和驱动链表;实现匹配方法(match);提供电源管理回调。 | i2c_bus_type、spi_bus_type、platform_bus_type |
| 设备 (Device) | struct device |
描述一个物理或虚拟硬件实体;包含资源信息(如 I/O 地址、中断号、时钟频率);挂载在特定总线上。 | i2c_client、spi_device、platform_device |
| 驱动 (Driver) | struct device_driver |
封装操作硬件的代码逻辑;提供 probe、remove、suspend、resume 等接口;与设备匹配后驱动硬件工作。 | i2c_driver、spi_driver、platform_driver |
注意: 在 I2C 和 SPI 子系统中,设备结构体分别被封装为
struct i2c_client 和 struct spi_device,驱动结构体分别被封装为 struct i2c_driver 和 struct spi_driver。它们都内嵌了通用的 struct device 和 struct device_driver。
1.2 三要素之间的匹配关系
匹配是设备驱动模型的核心流程。当一个新的设备或驱动注册到总线时,总线会遍历其维护的链表,尝试将设备与驱动进行配对。匹配成功后,总线调用驱动的 probe 方法,驱动开始初始化设备并提供操作接口。
匹配过程通常遵循以下优先级顺序:
- 设备树(Device Tree)匹配: 比较设备节点的
compatible属性与驱动of_match_table中的字符串。 - ACPI 匹配: 在 x86/ARM64 等支持 ACPI 的平台上,使用 ACPI 表进行匹配。
- 名称/ID 表匹配: 比较设备的名称或 ID 与驱动
id_table中的条目(如 I2C 的i2c_device_id,SPI 的spi_device_id)。 - 平台名称匹配: 比较设备名称与驱动名称(常用于 platform 总线)。
关键点: 对于 I2C 和 SPI 总线,设备树匹配是当前 ARM 嵌入式 Linux 中最主流的匹配方式。驱动开发者必须确保
compatible 字符串与设备树中的定义完全一致,否则驱动将无法被加载。
1.3 设备驱动模型架构总览
下图展示了 Linux 设备驱动模型中总线、设备、驱动三要素之间的核心关系与匹配流程:
1.4 匹配流程的代码级体现
总线核心的 match 函数是匹配逻辑的入口。以 I2C 总线为例,其匹配函数 i2c_device_match 的简化流程如下:
// drivers/i2c/i2c-core-base.c (简化示意)
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_driver *driver = to_i2c_driver(drv);
/* 1. 首先尝试设备树匹配 */
if (of_driver_match_device(dev, drv))
return 1;
/* 2. 然后尝试 ACPI 匹配 */
if (acpi_driver_match_device(dev, drv))
return 1;
/* 3. 最后尝试 ID 表匹配 */
if (i2c_match_id(driver->id_table, client))
return 1;
return 0;
}
理解要点: 匹配顺序是固定的,一旦某个条件满足,匹配立即成功并返回 1,不再继续尝试后续匹配方式。这保证了设备树匹配具有最高优先级。
1.5 三要素在 I2C/SPI 子系统中的具体体现
下表对比了 I2C 和 SPI 子系统在三要素上的具体实现差异:
| 要素 | I2C 子系统 | SPI 子系统 |
|---|---|---|
| 总线类型 | i2c_bus_type |
spi_bus_type |
| 设备结构体 | struct i2c_client包含:addr(7位/10位地址)、adapter(所属适配器) |
struct spi_device包含:chip_select(片选号)、max_speed_hz(最大速率)、mode(SPI 模式) |
| 驱动结构体 | struct i2c_driver包含:id_table、probe、remove、shutdown |
struct spi_driver包含:id_table、probe、remove、shutdown |
| 匹配方式 | 设备树 compatible → ACPI → i2c_device_id | 设备树 compatible → ACPI → spi_device_id |
| 通信接口 | i2c_master_send() / i2c_master_recv() |
spi_write() / spi_read() / spi_sync_transfer() |