本页目录

设备模型

覆盖: kobject/kset → device/driver/bus/class → sysfs 绑定 → probe 生命周期 → udev → device tree (DT) → ACPI → platform device 内核版本: 2.6 ~ 6.x

概述

Linux 设备模型是一套内核内部框架,为所有设备、驱动、总线提供统一的表示和生命周期管理。它的核心价值不在于"设备怎么工作",而在于"设备和驱动怎么找到对方"——即设备-驱动匹配 (device-driver binding)。

kobject: 基础构建块

// include/linux/kobject.h
struct kobject {
    const char      *name;           // sysfs 中显示的名字
    struct kobject  *parent;         // 父节点 → sysfs 目录层次
    struct kset     *kset;           // 所属 kset (集合)
    struct kernfs_node *sd;         // sysfs 中的 dentry (kernfs)
    struct kref     kref;            // 引用计数
    unsigned int    state_initialized:1;
};

// kobject 本身不做设备管理 — 它提供:
//   1. sysfs 中的目录/文件表示
//   2. 引用计数 → 自动释放
//   3. 父-子层次关系

kset: kobject 集合

struct kset {
    struct list_head list;           // 所有成员 kobject
    struct kobject  kobj;            // 内嵌 kobject (集合自身在 sysfs 中)
    const struct kobj_type *ktype;   // 类型操作
};

// 例: /sys/devices/ → devices_kset
//     /sys/bus/ → bus_kset

Device / Driver / Bus

struct device

// include/linux/device.h
struct device {
    struct kobject      kobj;               // sysfs 表示
    struct device       *parent;            // 父设备 (如 PCI bridge)
    const char          *init_name;
    struct bus_type     *bus;               // 所在总线
    struct device_driver *driver;           // 绑定到的驱动
    void                *driver_data;       // 驱动私有数据
    struct device_node   *of_node;          // DT 节点
    u64                 *dma_mask;          // DMA 可寻址范围
    const struct attribute_group **groups;  // sysfs 属性组
    void (*release)(struct device *dev);    // 必须! (释放回调)
};

struct device_driver

struct device_driver {
    const char              *name;
    struct bus_type         *bus;
    int (*probe)(struct device *dev);           // 探测: 驱动绑定到设备
    void (*remove)(struct device *dev);         // 移除: 解绑
    void (*shutdown)(struct device *dev);
    const struct of_device_id *of_match_table;  // DT 匹配
    const struct acpi_device_id *acpi_match_table;
    const struct attribute_group **groups;
};

struct bus_type

struct bus_type {
    const char      *name;                      // PCI, USB, platform, ...
    int (*match)(struct device *dev, struct device_driver *drv);
    int (*probe)(struct device *dev);           // 总线级 probe
    struct subsys_private *p;                   // 设备链表 + 驱动链表
};

绑定流程

// drivers/base/dd.c
// 设备注册:
device_register(dev)device_add(dev)bus_add_device(dev)     // 挂到 bus->p->klist_devices
bus_probe_device(dev)device_initial_probe(dev)__device_attach(dev, true)bus_for_each_drv(dev->bus, ...)  // 遍历所有注册的驱动
driver_match_device(drv, dev)  // bus->match() 或 of_match/acpi_match
device_driver_attach(drv, dev)driver_probe_device(drv, dev)really_probe(dev, drv)call_driver_probe(dev, drv) → drv->probe(dev)

关键⁠: 绑定是双向的——新设备到来时遍历驱动,新驱动注册时也遍历设备。无论谁先注册,匹配都会发生。


sysfs 与属性

// /sys 下每个目录 = 一个 kobject
// 属性文件 = struct device_attribute
struct device_attribute {
    struct attribute attr;
    ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
    ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
};

// 宏: DEVICE_ATTR_RO(name) → 生成只读属性
//      DEVICE_ATTR_WO(name) → 只写
//      DEVICE_ATTR_RW(name) → 读写

Device Tree vs ACPI

Device Tree / ACPI / PCIe:硬件描述方式不同,匹配机制各异 ARM/RISC-V · Device Tree 静态描述硬件拓扑 bootloader 传给内核 platform_device 绑定 DT 节点 of_match_table 匹配 compatible 字符串 x86 · ACPI UEFI/BIOS 提供 固件动态描述硬件 + 电源管理方法 acpi_match_table 匹配 _HID / _CID PCIe · 自枚举 不管什么架构 不依赖 DT / ACPI 描述 总线自身枚举设备 vendor:device ID 匹配 pci_device_id 硬件描述方式不同,但终点一致:都要落到各自的 match_table 上完成设备-驱动匹配

udev

udev:内核 uevent 到设备节点/规则应用的处理链 内核检测到事件 产生 uevent netlink socket 内核 → 用户态通道 udev 守护进程 接收到 uevent 加载内核模块 基于 modalias 创建设备节点 /dev/sda 等 应用自定义规则 权限 / 符号链接 内核只管发 uevent 通知;模块加载、设备节点创建、规则应用全部由用户态 udev 完成

参考

  • 源码⁠: drivers/base/core.c, drivers/base/bus.c, drivers/base/dd.c, include/linux/device.h
  • 内核文档⁠: Documentation/driver-api/driver-model/

关键词: kobject, device, driver, bus, probe, sysfs, device tree, ACPI, udev, modalias