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

Linux 总线设备驱动模型

  • 2026-10-10 19:48:41
Linux 总线设备驱动模型
大家好,我是王鸽,大家都知道Linux设备驱动非常重视软件的可重用和跨平台能力,如果没有总线设备驱动模型,驱动代码里写死寄存器地址、中断号,换一块芯片,驱动全改,内核也不知道有多少设备,谁能用得上,这个时候需要一个驱动适配多个设备,让驱动标准化不用修改,在设备和驱动之间添加一层总线,总线则负责匹配设备和驱动, 而驱动则以标准途径拿到板级信息, 这样子就引出Linux 内核中总线 - 设备 - 驱动(Bus-Device-Driver)模型的核心概念。
主机驱动和设备驱动分隔开来,主机控制器驱动已经由半导体厂家编写好了,而设备驱动一般也由设备器件的厂家编写好了。

一、模型核心定义(通俗理解)

Linux 的总线 - 设备 - 驱动模型是内核为了解耦设备和驱动设计的核心框架,各个层级负责的内容:

总线(Bus)

设备和驱动的 “中介 / 匹配器”,比如 I2C、SPI、USB、PCI、platform(虚拟总线)等,负责管理挂在总线上的设备和驱动,并完成二者的匹配;

总线类型
适用场景
核心匹配方式
典型设备
platform
片上外设(无物理总线)
ACPI/DT/ID/ 名字
LED、按键、控制器
pci
PCI/PCIe 设备
PCI 厂商 ID / 设备 ID
网卡、显卡、SSD
usb
USB 设备
USB 类码 / 厂商 ID / 产品 ID
U 盘、鼠标、摄像头
i2c
I2C 外设
从地址 / 设备名
传感器、EEPROM
spi
SPI 外设
片选号 / 设备名
Flash、显示屏
内核通过总线可以:

设备(Device)

硬件设备在内核中的抽象(比如一个温度传感器、一个 U 盘),包含设备的硬件信息(地址、中断号、名称等);

驱动(Driver)

操作硬件的代码集合,包含设备的初始化、读写、中断处理等逻辑,驱动不直接绑定设备,而是由总线负责匹配。

核心目标:让驱动和设备 “分离开发、动态匹配”—— 新增设备时无需修改驱动,新增驱动时无需修改设备代码,由总线自动完成匹配。

二、核心结构体(关键基础)

Linux 内核通过以下核心结构体描述总线、设备、驱动,新手先掌握核心字段即可:

1. 总线(bus_type)

#include<linux/device.h>struct bus_type {    const char *name;                  // 总线名称(如"i2c"、"platform")    // 设备和驱动的匹配函数(核心!总线通过这个函数判断驱动是否支持设备)    int (*match)(struct device *dev, struct device_driver *drv);    // 匹配成功后调用的probe函数(驱动的初始化入口)    int (*probe)(struct device *dev);    // 设备/驱动添加/移除时的回调    int (*add_device)(struct device *dev);    int (*remove_device)(struct device *dev);    // 其他字段(暂无需深入)    struct subsys_private *p;    struct lock_class_key lock_key; };
核心函数:match是总线的 “匹配规则”,比如按设备名称、兼容属性(compatible)匹配。总线就是使用 match 函数来根据注册的设备来查找对应的驱动,或者根据注册的驱动来查找相应的设备,因此每一条总线都必须实现此函数。 match 函数有两个参数: dev 和 drv,这两个参数分别为 device 和 device_driver 类型,也就是设备和驱动。

2. 设备(device)

struct device {    struct kobject kobj;               // 内核对象(用于sysfs)    const char *init_name;             // 设备名称    struct bus_type *bus;              // 设备所属的总线    struct device_driver *driver;      // 匹配成功的驱动    void *platform_data;               // 设备私有数据(硬件参数)    // 其他字段(地址、中断号等)    dev_t devt;                        // 设备号    struct device_node *of_node;       // 设备树节点(DTB)};
每个硬件设备都会被封装成device结构体,挂到对应的总线上。

3. 驱动(device_driver)

struct device_driver {    const char *name;                  // 驱动名称(用于匹配)    struct bus_type *bus;              // 驱动所属的总线    // 驱动的probe函数(匹配成功后执行,初始化硬件)    int (*probe)(struct device *dev);    // 驱动移除时的回调    int (*remove)(struct device *dev);    // 匹配表(比如platform驱动的of_match_table)    const struct of_device_id *of_match_table;};
驱动的核心逻辑在probe函数中实现(比如初始化寄存器、申请中断、创建字符设备等)。

总线 - 设备 - 驱动模型,就是为了三件事:

驱动与硬件分离(驱动可复用)内核统一管理所有设备(结构不乱)自动匹配 + 热插拔(即插即用)
总线有一个匹配函数(match):
设备有名字
驱动有兼容表(compatible)
总线自动比对,匹配成功就调用 probe
这就是:
  • USB 插上自动加载驱动
  • I2C/SPI 设备自动匹配
  • 设备树(DT)自动匹配驱动的原理

没有总线,就没有热插拔。

有了这个模型后,驱动可以无限复用,同一个驱动:可以接在不同的控制器,可以接在不同总线,可以用在不同芯片,可以对应多个设备。
例如:一个 I2C 传感器驱动,可以在 NXP、STM、Rockchip 上跑,总线把 “平台差异” 全屏蔽了。

三、核心工作流程(可视化)

最新文章

随机文章