2. 基础知识
在 Linux 设备模型中,设备注册与依赖管理并不是孤立操作,而是围绕一组核心抽象展开的:设备(device)、驱动(driver)、总线(bus)、类(class)与子系统(subsystem)。理解它们之间的职责边界与匹配关系,是后续掌握 probe 顺序、依赖解析、热插拔与电源管理的基础。
一、五个核心对象及其职责
Linux 设备模型用 struct device、struct device_driver、struct bus_type、struct class 和 struct subsys_private 等结构描述这些对象。它们不是并列关系,而是有明确的层次与引用关系。
- 设备(device):描述一个具体的硬件实例或逻辑功能单元,例如一颗 I2C 温度传感器、一个 GPIO 按键、一块 PCIe 网卡。它携带资源信息:寄存器基址、中断号、时钟、GPIO、DMA 通道等。
- 驱动(driver):描述“如何操作某一类设备”的代码逻辑,包含
probe、remove、suspend、resume等回调。驱动通过id_table或of_device_id声明自己能匹配哪些设备。 - 总线(bus):设备与驱动之间的“红娘”。它维护设备链表和驱动链表,负责在设备或驱动注册时触发匹配,并在匹配成功后调用驱动的
probe。常见总线有 platform、I2C、SPI、PCI、USB 等。 - 类(class):面向用户空间的抽象,用于把功能相似的设备归为一类,并在
/sys/class/下生成统一视图,例如/sys/class/net/、/sys/class/tty/、/sys/class/leds/。 - 子系统(subsystem):对某一类设备和驱动的统一管理框架,通常包含总线、类、设备模型和电源管理策略,例如 input 子系统、TTY 子系统、网络子系统、LED 子系统。
二、设备与驱动如何匹配
匹配过程由总线完成。以 platform 总线为例,设备树中的节点会被转换成 platform_device,驱动则注册为 platform_driver。总线依次比较驱动中的 of_device_id.compatible、acpi_match_table、id_table 与设备名称,匹配成功后调用 probe。
static const struct of_device_id demo_of_match[] = {
{ .compatible = "vendor,demo-sensor" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, demo_of_match);
static struct platform_driver demo_driver = {
.probe = demo_probe,
.remove = demo_remove,
.driver = {
.name = "demo-sensor",
.of_match_table = demo_of_match,
},
};
module_platform_driver(demo_driver);
当设备树中存在 compatible = "vendor,demo-sensor" 的节点时,总线会将该设备与上述驱动绑定,随后进入 demo_probe。若匹配失败,设备会停留在“未绑定”状态,在 /sys/bus/platform/devices/ 下可见,但不会产生功能。
三、典型应用场景与依赖关系
实际系统中,设备之间往往存在依赖。例如一颗摄像头模组依赖 I2C 总线、MIPI CSI 控制器、时钟控制器、GPIO 控制器和电源 regulator。只有这些依赖先就绪,摄像头驱动才能成功 probe。Linux 通过 device_link、fwnode 引用、EPROBE_DEFER 机制表达并解决这些依赖。
| 对象 | 典型路径 | 作用 | 常见误区 |
|---|---|---|---|
| 设备 device | /sys/devices/... | 描述硬件实例与资源 | 把设备当成驱动 |
| 驱动 driver | /sys/bus/*/drivers/ | 提供操作回调 | 认为驱动一定先于设备注册 |
| 总线 bus | /sys/bus/ | 匹配设备与驱动 | 忽略总线匹配优先级 |
| 类 class | /sys/class/ | 用户空间统一视图 | 把 class 当作总线 |
| 子系统 subsystem | /sys/class/*、/sys/bus/* | 统一管理同类设备 | 混淆子系统与总线 |
四、案例:一个 GPIO 按键的注册链路
以 GPIO 按键为例:设备树中定义 gpio-keys 节点,platform 总线将其转换为 platform_device;gpio_keys_driver 通过 of_match_table 匹配后 probe;probe 中申请 GPIO、注册中断、创建 input 设备;input 子系统再通过 /sys/class/input/ 和 /dev/input/eventX 向用户空间暴露事件。整个链路中,设备、驱动、总线、类、子系统各司其职。
五、常见误区与复盘
误区二:把 class 当成 bus。class 只负责用户空间视图,不参与设备与驱动的匹配。
误区三:忽略 probe 顺序。若依赖的时钟、GPIO、regulator 尚未就绪,probe 会返回
-EPROBE_DEFER,设备会被延迟重试,而不是直接失败。
复盘时建议按以下顺序排查:先看设备是否出现在 /sys/bus/<bus>/devices/,再看驱动是否出现在 /sys/bus/<bus>/drivers/,然后检查 compatible 或 id_table 是否匹配,最后查看 dmesg 中是否有 probe 失败或 EPROBE_DEFER 日志。掌握这五个基本对象及其关系,后续学习设备注册、依赖管理与 probe 顺序时就能建立清晰的系统观。