1. 平台驱动基础概念解析
在嵌入式Linux开发中,平台驱动(platform_driver)是管理片上系统(SoC)集成设备的核心框架。与传统的PCI、USB等总线驱动不同,平台驱动专门为那些无法自动枚举的固定设备设计。我第一次接触这个概念是在开发一块定制化的ARM开发板时,当时为了驱动板载的GPIO控制器,不得不深入研究这套机制。
1.1 平台驱动的设计初衷
平台驱动主要解决嵌入式系统中的三个核心问题:
-
静态设备管理:SoC内部的UART、I2C等控制器在芯片出厂时就已固定存在,不像PCI设备可以热插拔。平台驱动通过设备树或ACPI等静态描述方式告知内核这些设备的存在。
-
固定资源配置:片上设备的寄存器地址、中断号等资源在芯片设计阶段就已确定。例如,某款SoC的UART0寄存器基地址可能是固定的0x101f0000,中断号为32。
-
统一抽象接口:为各类片上设备提供一致的驱动模型,简化开发流程。无论开发GPIO还是SPI驱动,都可以使用相同的platform_driver框架。
1.2 平台设备与传统设备的对比
通过下表可以清晰看出平台设备与PCI/USB等标准设备的本质区别:
| 特性 | 平台设备 | 标准设备(PCI/USB) |
|---|---|---|
| 枚举方式 | 静态定义(设备树/ACPI) | 总线自动枚举 |
| 地址分配 | 固定物理地址 | 动态分配 |
| 中断分配 | 固定IRQ号 | 动态分配 |
| 典型应用场景 | SoC内置UART/I2C/SPI | 网卡、声卡等外设 |
| 配置变更 | 需重新编译设备树 | 即插即用 |
在实际项目中,我曾遇到一个典型案例:客户需要在同一款SoC上支持两种不同的板级设计。通过设备树机制,我们只需维护两份不同的.dts文件,而驱动代码完全无需修改,这正是平台驱动设计的精妙之处。
2. 平台驱动核心架构剖析
理解平台驱动的实现架构是开发高质量驱动的关键。经过多个项目的实践,我总结出平台驱动的三大核心要素,它们构成了整个框架的基石。
2.1 驱动-设备匹配模型
平台驱动采用经典的"驱动-设备"匹配模型,其工作流程如下:
- 设备注册:通过设备树、ACPI或代码静态定义platform_device
- 驱动注册:实现并注册platform_driver结构体
- 匹配触发:内核比较device和driver的匹配条件
- probe执行:匹配成功后调用驱动的probe函数
这个过程中最关键的匹配依据是:
- 设备树使用
compatible字符串匹配 - ACPI使用_HID/_CID匹配
- 旧式方法直接比较name字段
c复制// 典型设备树匹配示例
static const struct of_device_id mydrv_of_match[] = {
{ .compatible = "vendor,uart-2023" }, // 精确匹配
{ .compatible = "vendor,uart" }, // 通用匹配
{}
};
2.2 关键数据结构详解
2.2.1 platform_device结构体
这个结构体描述了一个平台设备的所有硬件特性:
c复制struct platform_device {
const char *name; // 设备名称(匹配关键)
int id; // 设备实例ID
struct device dev; // 基础设备结构
struct resource *resource; // 资源数组
u32 num_resources; // 资源数量
// ...
};
在调试一个SPI控制器驱动时,我曾通过/sys/devices/platform/下的目录结构直观看到每个platform_device的实例化情况。
2.2.2 platform_driver结构体
这是驱动开发者需要实现的核心结构:
c复制struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
struct device_driver driver;
const struct platform_device_
