Linux 总线-设备-驱动(Bus-Device-Driver)完整协作原理

一、核心三角色定义

  1. 总线 bus_type

    物理总线:I2C、SPI、PCI、CAN、Platform 平台总线;

    内核抽象 struct bus_type,统一管理匹配规则、探测、卸载、sysfs 接口。

    作用:作为中介,负责设备和驱动匹配、管理挂载在这条总线上的所有设备/驱动。

  2. 设备 device(struct device)

    描述一个真实硬件外设,保存硬件资源(地址、中断、GPIO、时钟、设备树compatible字符串)。

    设备只描述「硬件有什么资源」,不含操作硬件的代码。

  3. 驱动 driver(struct device_driver / platform_driver)

    包含操作硬件的代码(寄存器初始化、read/write、中断处理),提供 probe 探测函数。

    驱动只描述「怎么操作硬件」,不绑定固定硬件。

二、核心协作逻辑:总线做媒人,设备、驱动自动配对

匹配核心规则

总线内部提供匹配回调函数,内核自动遍历:

  1. 新注册设备 → 遍历当前总线上所有已注册驱动,挨个匹配;
  2. 新注册驱动 → 遍历当前总线上所有已注册设备,挨个匹配;
    匹配成功 → 执行驱动 .probe() 函数,完成硬件初始化;
    匹配失败 → 二者保持独立,无任何交互。

不同总线匹配规则不一样:

  • Platform总线:匹配设备树 compatible 字符串;
  • I2C/SPI:匹配设备ID表;
  • PCI:匹配厂商ID、设备ID。

三、完整工作流程分两种场景

场景1:先有设备,后加载驱动(设备树常用,RK3568主流)

  1. 内核解析设备树,在Platform总线下创建 struct device 设备实例;
    存入:总线维护的设备链表,此时只有设备,无驱动。
  2. 加载驱动 .ko,驱动调用 platform_driver_register() 向Platform总线注册 platform_driver
  3. 总线触发匹配流程:拿驱动的id_table/compatible和总线上所有设备对比;
  4. 找到compatible完全一致的设备 → 匹配成功;
  5. 总线调用驱动的 .probe() 函数:
    • probe内从device中提取硬件资源(寄存器基地址、中断、PWM引脚);
    • 初始化时钟、GPIO、寄存器;
    • 内部创建cdev、class、device_create,生成/dev/xxx字符设备节点;
  6. 用户层open /dev/xxx,调用file_operations操作硬件。

场景2:先注册驱动,后出现设备(热插拔硬件,USB/I2C)

  1. 开机先加载驱动,驱动注册到对应总线,挂在驱动链表;
  2. 硬件热插入总线,内核检测到硬件,生成struct device挂入总线设备链表;
  3. 总线自动拿新设备和所有驱动匹配;
  4. 匹配成功执行probe,初始化硬件。

四、三者数据结构关联关系

  1. struct bus_type

    • 维护两条双向链表:设备链表、驱动链表;
    • 核心回调:match()(匹配)、probe()remove()shutdown()
    • sysfs目录:/sys/bus/xxx/,存放devices、drivers子目录。
  2. struct device(硬件)

    • 挂载在对应bus的设备链表;
    • 成员 bus 指向所属总线;
    • 成员 driver:匹配成功后,指向绑定的驱动;
    • 存放硬件资源:struct resource 寄存器、irq、dma、设备树节点。
  3. struct device_driver(驱动代码)

    • 挂载在对应bus的驱动链表;
    • 成员 bus 指向所属总线;
    • 内置匹配表(compatible字符串/ID列表);
    • 提供 .probe 初始化硬件,.remove 卸载释放资源。

绑定关系一句话

device.bus = 所属总线

driver.bus = 所属总线

匹配成功后 device.driver = 对应驱动

五、以你之前的PWM字符驱动举完整实例(Platform总线)

  1. 设备(设备树)
dts 复制代码
pwm_demo@10000000 {
    compatible = "rockchip,pwm-demo";
    reg = <0x10000000 0x1000>;
    gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
};

内核启动自动生成platform device,挂载到platform总线。

  1. 驱动(platform_driver)
c 复制代码
static const struct of_device_id pwm_of_match[] = {
    { .compatible = "rockchip,pwm-demo" },
    {}
};

static struct platform_driver pwm_plat_drv = {
    .probe = pwm_probe,
    .remove = pwm_remove,
    .driver = {
        .name = "pwm_drv",
        .of_match_table = pwm_of_match,
    },
};

module_platform_driver(pwm_plat_drv);
  1. 加载驱动,注册到platform总线;
  2. 总线匹配compatible字符串,匹配成功调用 pwm_probe
  3. probe函数内部:
    解析reg获取寄存器、解析gpio、使能时钟;
    执行字符设备整套流程:alloc_chrdev_region、cdev_init、cdev_add、class_create、device_create;
  4. 用户操作/dev/pwm_subsystem控制硬件;
  5. rmmod驱动,总线调用 .remove,逆序释放硬件、销毁字符设备。

六、如果自己自定义一套全新总线(拓展你提问的"创建自己的总线")

1. 自定义总线核心结构

定义 struct bus_type my_bus,实现match/probe/remove;

内核调用 bus_register(&my_bus) 注册全新总线。

2. 自定义设备、自定义驱动

  • 自定义设备结构体内嵌 struct device dev
  • 自定义驱动内嵌 struct device_driver drv
  • 设备注册进自定义总线,驱动也注册到同一总线;
  • 总线match函数实现自定义匹配规则(比如自定义硬件ID)。

3. 适用场景

极少需要自定义总线;现有Platform/I2C/SPI/PCI总线已经覆盖绝大多数外设,仅自研私有硬件协议才会新建总线。

七、总线模型核心优势(为什么Linux要这套架构)

  1. 设备、驱动完全解耦
    驱动不写死寄存器地址,硬件信息全部放设备树(设备侧);更换硬件只需改设备树,驱动代码不用修改。
  2. 一份驱动适配多个同类型硬件
    只要compatible匹配,同一个驱动可以驱动多个同型号外设。
  3. 自动管理生命周期
    热插拔、卸载、电源管理由总线统一调度,不用驱动单独处理。
  4. sysfs统一可视化管理
    /sys/bus/ 下可直观查看总线、挂载的设备、绑定的驱动,方便调试。

八、极简总结协作流程

  1. 总线作为统一管理容器,分别维护设备链表、驱动链表;
  2. 新增设备/驱动时,总线执行match匹配规则;
  3. 匹配成功,总线调用驱动probe完成硬件初始化;
  4. probe中创建字符设备等交互接口,供用户层使用;
  5. 卸载时总线调用remove,释放硬件与内核资源;
    设备和驱动永远不直接互相查找,全部通过总线中转配对。
相关推荐
早点睡啊Y9 小时前
深入学 LangChain 官方文档(一):总览、安装与快速开始
linux·服务器·langchain
梦想的旅途29 小时前
JavaScript 实现企业微信消息自动发送的技术实践
运维·javascript·自动化·企业微信
优橙教育10 小时前
5G网优工程师证书怎么选:HCSP/HCIA/5G认证全解析
运维·服务器
国产化创客10 小时前
Kindle完整越狱改造:从闲置泡面盖到Linux开发与智能家居终端
linux·运维·物联网·嵌入式·智能家居·智能硬件
qetfw10 小时前
CentOS 7 搭建 MariaDB 数据库服务
linux·数据库·centos·mariadb
皮卡狮11 小时前
进程的地址空间
linux
田里的水稻11 小时前
FA_数字相机成像原理、分级和分类
运维·数码相机·机器人·自动驾驶
Darkwanderor11 小时前
动、静态库相关内容的详细介绍
linux·c语言·开发语言·c++
极客先躯12 小时前
高级java每日一道面试题-2026年04月18日-实战篇[Docker]-如何处理金融行业的时序数据容器化?
java·运维·docker·容器·金融·时序数据·高级面试