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 函数完成硬件初始化。
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 字符串的匹配。
2.3 设备树与 platform 设备的关联
在支持设备树(Device Tree)的 ARM/ARM64 或 RISC-V 平台上,platform_device 的创建不再由板级文件(board file)手动注册,而是由内核在启动阶段自动完成:
- Bootloader 将设备树二进制(.dtb)传递给内核。
- 内核解析设备树,为每个
compatible属性匹配到platform_driver的节点创建platform_device。 - 设备树中的
reg、interrupts等属性被转换为struct resource挂载到设备上。 - 驱动通过
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 | 获取资源、注册中断、初始化硬件、注册字符设备或网络设备等。 |