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 方法,驱动开始初始化设备并提供操作接口。

匹配过程通常遵循以下优先级顺序:

  1. 设备树(Device Tree)匹配: 比较设备节点的 compatible 属性与驱动 of_match_table 中的字符串。
  2. ACPI 匹配: 在 x86/ARM64 等支持 ACPI 的平台上,使用 ACPI 表进行匹配。
  3. 名称/ID 表匹配: 比较设备的名称或 ID 与驱动 id_table 中的条目(如 I2C 的 i2c_device_id,SPI 的 spi_device_id)。
  4. 平台名称匹配: 比较设备名称与驱动名称(常用于 platform 总线)。
关键点: 对于 I2C 和 SPI 总线,设备树匹配是当前 ARM 嵌入式 Linux 中最主流的匹配方式。驱动开发者必须确保 compatible 字符串与设备树中的定义完全一致,否则驱动将无法被加载。

1.3 设备驱动模型架构总览

下图展示了 Linux 设备驱动模型中总线、设备、驱动三要素之间的核心关系与匹配流程:

Linux 设备驱动模型:总线、设备、驱动三要素与匹配关系 总线 (Bus) 设备链表 (devices list) 驱动链表 (drivers list) 设备 A (i2c_client) compatible = "vendor,dev-a" 设备 B (spi_device) compatible = "vendor,dev-b" 驱动 X (i2c_driver) of_match_table = "vendor,dev-a" 驱动 Y (spi_driver) of_match_table = "vendor,dev-b" 匹配 (match) 调用 probe() 驱动初始化设备

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()