一、Platform总线在内核中的位置
1、Linux驱动模型的层次结构
Platform 总线处于驱动模型的核心位置,它连接了:
- 上层的字符设备框架(cdev)
- 下层的硬件资源(寄存器、中断等)
2、Platform总线的内核实现位置
Platform 总线相关的核心代码在内核源码中的位置:
bash
TaishanPi-3-Linux/kernel-6.1/drivers/base/
├── platform.c # Platform 总线核心实现
├── dd.c # 设备-驱动匹配核心逻辑
└── core.c # 设备模型核心代码
TaishanPi-3-Linux/kernel-6.1/include/linux/platform_device.h/
├── platform_device.h # platform_device 结构体定义
└── of_platform.h # 设备树相关的 Platform 接口1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
内核启动时会自动注册 Platform 总线:struct bus_type platform_bus_type 和 platform_bus_init()
二、Platform总线的核心数据结构
1、三大核心结构体
2、设备结构体
struct platform_device(设备结构体)用来描述一个 Platform 设备的硬件资源:
c
struct platform_device {
const char *name;
int id;
bool id_auto;
struct device dev;
u64 platform_dma_mask;
struct device_dma_parameters dma_parms;
u32 num_resources;
struct resource *resource;
const struct platform_device_id *id_entry;
/*
* Driver name to force a match. Do not set directly, because core
* frees it. Use driver_set_override() to set or clear it.
*/
const char *driver_override;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const char *name:用于标识设备的名称字符串,通常与对应的platform_driver的name匹配,例如:"serial"、"i2c-controller"等。int id:当系统中存在多个相同类型的设备时,用于区分不同实例。bool id_auto:系统自动为设备分配唯一ID。struct device dev:所有设备的基础结构,包含设备模型的核心信息。u64 platform_dma_mask:用于指示设备可以访问的物理地址范围。struct device_dma_parameters dma_parms:包含设备DMA传输的具体参数,如最大段大小、对齐要求等。u32 num_resources:该设备拥有的资源(如内存、中断、IO端口等)的总数。struct resource *resource:指向struct resource数组,描述设备使用的硬件资源。const struct platform_device_id *id_entry:指向匹配的platform_device_id条目。const char *driver_override:用于绕过正常的设备-驱动匹配机制,强制绑定到指定的驱动。struct mfd_cell *mfd_cell:当设备是MFD的子设备时使用,指向描述该子功能的mfd_cell结构。struct pdev_archdata archdata:存储特定CPU架构所需的私有数据。
资源类型(struct resource):
c
/*
* Resources are tree-like, allowing
* nesting etc..
*
* 资源结构体 - 描述硬件资源(内存、IO、IRQ等)
* 采用树形结构,支持资源的嵌套和层次管理
*/
struct resource {
resource_size_t start; /* 资源起始地址/编号 */
resource_size_t end; /* 资源结束地址/编号 (包含) */
const char *name; /* 资源名称 */
unsigned long flags; /* 资源类型和标志 (IORESOURCE_MEM/IRQ/IO/DMA等) */
unsigned long desc; /* 资源描述符 (如E820内存类型) */
struct resource *parent; /* 父资源 (所属的更大资源范围) */
struct resource *sibling; /* 兄弟资源 (同级的下一个资源) */
struct resource *child; /* 子资源 (嵌套在此资源内的子范围) */
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
设备树如何转换成 platform_device:
3、驱动结构体
c
struct platform_driver {
int (*probe)(struct platform_device *); // 设备探测函数,设备和驱动匹配成功时调用
int (*remove)(struct platform_device *); // 设备移除函数(旧版本)
void (*remove_new)(struct platform_device *); // 设备移除函数(新版本)
void (*shutdown)(struct platform_device *); // 系统关闭/重启时调用
int (*suspend)(struct platform_device *, pm_message_t state); // 系统挂起(休眠)时调用
int (*resume)(struct platform_device *); // 系统恢复(唤醒)时调用
struct device_driver driver; // 通用设备驱动结构体,包含驱动名称、匹配表等
const struct platform_device_id *id_table; // 设备 ID 匹配表(用于非设备树匹配)
bool prevent_deferred_probe; // 阻止延迟探测
bool driver_managed_dma; // 驱动自行管理 DMA
};1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
设备树匹配表(of_device_id):
c
struct of_device_id {
char name[32]; /* 设备节点名称 */
char type[32]; /* 设备类型 */
char compatible[128]; /* 设备兼容性字符串 */
const void *data; /* 驱动私有数据指针 */
};1
2
3
4
5
6
2
3
4
5
6
驱动代码如何定义匹配表:
c
// 驱动代码中定义匹配表
static const struct of_device_id my_of_match[] = {
{ .compatible = "lckfb,mychardev" }, // 告知总线匹配这个compatible
{ /* 结束符 */ }
};
static struct platform_driver my_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "mychardev",
.of_match_table = my_of_match, // 指定匹配表
},
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
三、Platform总线的工作流程详解
1、时序图
2、设备注册流程
3、驱动注册流程
4、设备与驱动匹配流程
匹配优先级:
| 优先级 | 匹配方式 | 匹配字段 | 应用场景 |
|---|---|---|---|
| 1 | 设备树匹配 | compatible | ARM/ARM64 平台 |
| 2 | ACPI 匹配 | ACPI ID | x86 平台 |
| 3 | ID 表匹配 | id_table. name | 兼容旧代码 |
| 4 | 名称匹配 | device.name == driver.name | 手动注册设备 |
5、probe函数调用流程
四、总线上的设备和驱动链表
1、链表结构示意图
2、查看系统中的设备和驱动
通过 sysfs 查看系统中注册的所有 Platform 设备和驱动:
bash
# 查看所有 Platform 设备
ls /sys/bus/platform/devices/
# 查看所有 Platform 驱动
ls /sys/bus/platform/drivers/
# 查看某个设备的详细信息
cat /sys/bus/platform/devices/mychardev.0/uevent
# 查看某个驱动绑定的设备
ls /sys/bus/platform/drivers/mychardev/1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
五、Platform总线架构总结
1、核心组件关系图
| 概念 | 说明 |
|---|---|
| platform_bus_type | Platform 总线的核心结构体,内核启动时注册 |
| platform_device | 描述硬件资源,由设备树自动创建 |
| platform_driver | 描述驱动能力,由我们编写并注册 |
| of_match_table | 设备树匹配表,包含 compatible 字符串 |
| platform_match() | 总线的匹配函数,有4种匹配方式 |
| probe() | 匹配成功后自动调用,用于初始化设备 |
| resource | 硬件资源(寄存器地址、中断号等) |
| 设备链表 | bus->devices,存储所有已注册的设备 |
| 驱动链表 | bus->drivers,存储所有已注册的驱动 |