当前位置:首页>Linux>Linux 设备模型:总线、驱动、设备三位一体

Linux 设备模型:总线、驱动、设备三位一体

  • 2026-10-11 08:37:49
Linux 设备模型:总线、驱动、设备三位一体

在 Linux 内核驱动开发中,设备模型(Device Model) 是一切驱动的骨架与基石。它解决了多硬件、多平台、多总线的统一管理问题,让驱动与硬件解耦、让系统能自动匹配与枚举设备。

本文目的是理清总线、设备、驱动三者的关系、内核数据结构、匹配流程,以及它如何支撑起整个 Linux 驱动世界。


一、为什么需要 Linux 设备模型?

早期 Linux 驱动非常“硬编码”,即代码实现于可参数的内容并没有分离,均是在驱动代码中写死实现,比如:

  • 驱动直接写死硬件地址、中断号;
  • 无法热插拔、无法自动加载;
  • 同一驱动不能跨平台、跨总线复用;
  • 内核无法统一管理电源、功耗、拓扑;

由于这种实现方式,在适配不同的硬件时成本太高,需要修改驱动代码,因此提出了设备模型的概念与实现。设备模型的核心价值为:

  1. 统一抽象
    :不管是 PCI、USB、I2C、SPI、平台总线,都用同一套框架管理;
  2. 支持热插拔自动匹配
    :设备插入 → 内核找到对应驱动 → 自动绑定运行;
  3. 拓扑呈现
    :用 sysfs 把硬件结构暴露给用户空间;
  4. 生命周期统一
    :probe/remove等流程标准化;
  5. 驱动复用
    :一套驱动可在不同总线、不同平台上运行;

可以这样总结,即:设备模型 = 总线(通道)+ 设备(硬件)+ 驱动(软件)+ 匹配机制。


二、设备模型的三大核心结构体

Linux 设备模型围绕3个基础结构体构建,所有总线、驱动、设备都基于它们展开。

1. struct bus_type (总线)

代表一种总线类型(PCI、USB、I2C、platform、SPI 等)。

struct bus_type {    const char      *name;    int             (*match)(struct device *dev,                              struct device_driver *drv);    int             (*probe)(struct device *dev);    struct bus_attribute    *bus_attrs;    struct device_driver    *drv;    struct device           *dev;    // ...};

结构体struct bus_type的核心作用:

  • 管理挂在这条总线上的所有设备;
  • 管理注册到这条总线的所有驱动;
  • 提供 match() 匹配函数:决定设备和驱动能否绑定;
  • 提供统一的电源、热插拔、遍历能力;

2. struct device (设备)

代表一个真实硬件设备,是所有设备的“基类”。

struct device {    struct bus_type  *bus;      // 属于哪条总线    struct device_driver *driver;// 绑定的驱动    const char       *init_name;    void             *platform_data;    struct device_node *of_node; // 设备树节点    // ...};

结构体struct device 只描述“硬件本身”:

  • 硬件地址、中断、时钟、供电;
  • 来自设备树 / ACPI / 平台描述;
  • 不包含任何业务逻辑;

3. struct device_driver (驱动)

代表驱动程序,负责操作硬件、实现功能。

struct device_driver {    const char      *name;    struct bus_type *bus;    int   (*probe) (struct device *dev);    int   (*remove)(struct device *dev);    const struct of_device_id *of_match_table;    // ...};

结构体struct device_driver的核心回调:

  • probe()
    :设备与驱动匹配成功后调用(初始化硬件);
  • remove()
    :设备移除/驱动卸载时调用(清理资源);
  • of_match_table
    :与设备树 compatible 匹配;

三、经典且常用的总线:平台总线(Platform Bus)

其中嵌入式 Linux 90% 的驱动都跑在平台总线上,为什么要用 platform 总线?

该总线专门管理:

  • 常见的片上控制器(UART、I2C、SPI、GPIO、时钟等);
  • 无法自动枚举的硬件;
  • 设备树描述的设备;

平台驱动标准结构

// 1. 匹配表(与设备树 compatible 对应)static const struct of_device_id xxx_dt_ids[] = {    { .compatible = "vendor,xxx-ip" },    { /* Sentinel */ }};MODULE_DEVICE_TABLE(of, xxx_dt_ids);// 2. 平台驱动结构体static struct platform_driver xxx_driver = {    .probe = xxx_probe,    .remove = xxx_remove,    .driver = {        .name = "xxx-driver",        .of_match_table = xxx_dt_ids,    },};// 3. 注册/卸载module_platform_driver(xxx_driver);

probe 注册函数什么时候被调用?

满足以下任一条件:

  • 设备树节点 compatible 与驱动匹配;
  • 内核启动时创建了 platform_device;
  • 设备热插拔插入;

probe 函数内部的常见操作:

  • 获取控制器基址、驱动需要的空间资源与使能时钟等(地址、中断、时钟);
  • 初始化硬件;
  • 注册字符设备/输入设备/IIO 等子系统;
  • 开启时钟、复位释放;

四、设备模型完整工作流程

1. 总线注册

Linux内核启动—>注册各类总线(platform/i2c/usb/pci);

2. 设备生成

硬件信息来自:

  • ARM平台,设备树 DTB;
  • x86平台,ACPI 表;
  • 板级代码,内核个别驱动C代码写死生成对应的 struct device;

3. 驱动注册

驱动加载(或内核内置)—> 注册 struct device_driver,并指定所属总线;

4. 自动匹配 & 绑定

总线的 .match() 函数开始工作:

  • 比较设备树 compatible列表定义字段
  • 比较 ID 表;
  • 比较name;

如果匹配成功,则调用驱动的 probe() 函数进行初始化,然后硬件开始工作。


五、设备模型呈现给用户的方式:sysfs

设备模型把硬件拓扑变成文件系统,挂载在 /sys目录。

/sys  /bus      所有总线    /platform    /pci    /i2c    /usb  /dev      设备号  /class    设备分类(input/tty/block/net)  /devices  全局设备树拓扑

开发者可以直接看到:

  • 设备挂载在哪条总线;
  • 驱动与设备是否绑定;
  • 硬件地址、中断、当前供电状态;
  • 支持的功能;

七、总结

设备只提供数据,驱动只提供逻辑,总线只提供匹配与管理,设备模型使三者完全解耦。

  • Linux 设备模型 = 总线 + 设备 + 驱动;
  • 三大结构体:bus_type、device、device_driver ;
  • 平台总线是嵌入式驱动最核心总线;
  • 流程:1)注册总线;2)生成设备;3)注册驱动;4)匹配;5) probe;
  • sysfs 是设备模型的用户空间呈现。

最新文章

随机文章