2. Linux 设备模型基础:总线、设备、驱动模型

Linux 内核从 2.6 版本开始引入了统一的设备驱动模型(Device Driver Model),旨在将系统中的硬件设备、驱动程序和通信总线抽象为三个核心对象,并通过内核对象(kobject)与 sysfs 文件系统将它们组织成层次化的拓扑结构。理解这一模型是掌握网关驱动加载流程的前提。

2.1 核心三要素:总线、设备、驱动

设备模型将硬件系统抽象为三个基本角色,它们之间的协作关系决定了驱动加载的完整路径:

角色 内核数据结构 职责描述
总线(Bus) struct bus_type 定义设备与驱动之间的匹配规则(match 函数),管理挂载在该总线上的设备链表和驱动链表。
设备(Device) struct device 代表一个物理或虚拟硬件实体,包含资源信息(如 I/O 地址、中断号、DMA 通道)以及指向所属总线的指针。
驱动(Driver) struct device_driver 封装操作特定设备的代码逻辑,提供 probe(探测)、remove(移除)、suspend/resume(电源管理)等回调函数。
关键机制:当系统注册一个新设备或新驱动时,总线会遍历其维护的链表,调用 match 函数进行配对。配对成功后,内核调用驱动的 probe 函数完成硬件初始化。
Linux 设备模型三要素关系 总线 (bus_type) 设备 (device) 驱动 (driver) 管理设备链表 管理驱动链表 match() 配对 probe 成功 → 驱动绑定设备;probe 失败 → 继续等待匹配

2.2 platform 总线与 platform 驱动

在嵌入式系统中,大量设备(如 CAN 控制器、GPIO、SPI/I2C 控制器)并不挂载在 PCI、USB 等可枚举总线上,而是直接集成在 SoC 内部,通过内存映射寄存器与 CPU 通信。为此,内核引入了 platform 总线(虚拟总线),用于管理这些“非可枚举”设备。

2.2.1 platform 总线的特点

  • 虚拟性:platform 总线不是一个物理硬件总线,而是内核软件抽象层,对应 struct bus_type platform_bus_type。
  • 匹配方式:默认通过设备名称(name 字段)进行字符串匹配;在设备树使能的内核中,则通过设备树中的 compatible 属性匹配。
  • 资源传递:platform 设备使用 struct resource 描述 I/O 内存、中断等硬件资源,驱动通过 platform_get_resource() 系列 API 获取。

2.2.2 platform_driver 与 platform_device

platform 驱动模型在标准设备模型基础上扩展了两个专用结构体:

结构体 关键字段 说明
struct platform_driver probe、remove、driver.name、id_table 继承 struct device_driver,增加 platform 特有的 probe/remove 回调。
struct platform_device name、id、num_resources、resource 继承 struct device,携带硬件资源数组和设备编号。
实践要点:在设备树环境下,platform_device 由内核在解析设备树时动态创建,驱动开发者只需关注 platform_driver 的 probe 实现和 compatible 字符串的匹配。
platform 总线匹配与驱动注册流程 注册 platform_driver 总线 match() 匹配 匹配成功? 等待 调用 probe() 驱动绑定设备 匹配依据 传统方式:name 字段 设备树方式: compatible 属性

2.3 设备树与 platform 设备的关联

在支持设备树(Device Tree)的 ARM/ARM64 或 RISC-V 平台上,platform_device 的创建不再由板级文件(board file)手动注册,而是由内核在启动阶段自动完成:

  1. Bootloader 将设备树二进制(.dtb)传递给内核。
  2. 内核解析设备树,为每个 compatible 属性匹配到 platform_driver 的节点创建 platform_device。
  3. 设备树中的 reg、interrupts 等属性被转换为 struct resource 挂载到设备上。
  4. 驱动通过 of_match_table 声明支持的 compatible 列表,总线 match 时优先使用设备树匹配。
常见误区:不要将设备树中的“设备节点”与内核中的 struct device 混淆。设备树节点是硬件描述数据,内核设备对象是运行时数据结构。一个设备树节点可能对应多个内核设备(如通过 mfd 子设备拆分)。

2.4 驱动加载的完整路径

结合上述概念,一个典型的 platform 驱动加载流程可归纳为以下步骤:

步骤 执行者 动作描述
1 内核启动 解析设备树,为每个 compatible 匹配的节点创建 platform_device 并添加到 platform 总线。
2 驱动模块加载 调用 platform_driver_register() 将驱动注册到 platform 总线。
3 platform 总线 遍历设备链表,调用 match() 函数(设备树模式下比对 compatible)。
4 内核核心 匹配成功后,调用驱动的 probe() 函数,传入匹配的 platform_device 指针。
5 驱动 probe 获取资源、注册中断、初始化硬件、注册字符设备或网络设备等。