---
title: 设备模型
url: https://doc.liz6.com/linux-kernel/10-drivers-and-device-model/01-device-model
locale: zh
area: linux-kernel
tags:
- linux-kernel
- 驱动与设备模型
date: 2026-06-30
modified: 2026-07-11
description: '覆盖: kobject/kset → device/driver/bus/class → sysfs 绑定 → probe 生命周期 → udev → device tree (DT) → ACPI → platform device 内核版本: 2.6 ~ 6.x'
---

# 设备模型

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

## 概述

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

## kobject: 基础构建块

```c
// 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 集合

```c
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

```c
// 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

```c
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

```c
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;                   // 设备链表 + 驱动链表
};
```

### 绑定流程

```c
// 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 与属性

```c
// /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

<svg viewBox="0 0 720 260" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="Device Tree、ACPI、PCIe 三种硬件描述方式与驱动匹配路径对比">
  <defs><marker id="dtah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="260" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">Device Tree / ACPI / PCIe:硬件描述方式不同,匹配机制各异</text>

  <rect x="40" y="50" width="200" height="26" rx="6" fill="#4f46e5"/>
  <text x="140" y="68" text-anchor="middle" font-size="12" font-weight="700" fill="#ffffff">ARM/RISC-V · Device Tree</text>
  <rect x="40" y="84" width="200" height="56" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="52" y="100" font-size="10.5" fill="#3730a3">静态描述硬件拓扑</text>
  <text x="52" y="114" font-size="10.5" fill="#3730a3">bootloader 传给内核</text>
  <text x="52" y="128" font-size="10.5" fill="#3730a3">platform_device 绑定 DT 节点</text>
  <line x1="140" y1="140" x2="140" y2="156" stroke="#475569" stroke-width="1.6" marker-end="url(#dtah)"/>
  <rect x="40" y="158" width="200" height="40" rx="6" fill="#e0e7ff"/>
  <text x="140" y="174" text-anchor="middle" font-size="11" font-weight="700" fill="#3730a3">of_match_table</text>
  <text x="140" y="189" text-anchor="middle" font-size="10.5" fill="#3730a3">匹配 compatible 字符串</text>

  <rect x="260" y="50" width="200" height="26" rx="6" fill="#0d9488"/>
  <text x="360" y="68" text-anchor="middle" font-size="12" font-weight="700" fill="#ffffff">x86 · ACPI</text>
  <rect x="260" y="84" width="200" height="56" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="272" y="104" font-size="10.5" fill="#0f766e">UEFI/BIOS 提供</text>
  <text x="272" y="118" font-size="10.5" fill="#0f766e">固件动态描述硬件</text>
  <text x="272" y="132" font-size="10.5" fill="#0f766e">+ 电源管理方法</text>
  <line x1="360" y1="140" x2="360" y2="156" stroke="#475569" stroke-width="1.6" marker-end="url(#dtah)"/>
  <rect x="260" y="158" width="200" height="40" rx="6" fill="#ccfbf1"/>
  <text x="360" y="174" text-anchor="middle" font-size="11" font-weight="700" fill="#115e59">acpi_match_table</text>
  <text x="360" y="189" text-anchor="middle" font-size="10.5" fill="#115e59">匹配 _HID / _CID</text>

  <rect x="480" y="50" width="200" height="26" rx="6" fill="#64748b"/>
  <text x="580" y="68" text-anchor="middle" font-size="12" font-weight="700" fill="#ffffff">PCIe · 自枚举</text>
  <rect x="480" y="84" width="200" height="56" rx="6" fill="#f1f5f9" stroke="#cbd5e1"/>
  <text x="492" y="104" font-size="10.5" fill="#334155">不管什么架构</text>
  <text x="492" y="118" font-size="10.5" fill="#334155">不依赖 DT / ACPI 描述</text>
  <text x="492" y="132" font-size="10.5" fill="#334155">总线自身枚举设备</text>
  <line x1="580" y1="140" x2="580" y2="156" stroke="#475569" stroke-width="1.6" marker-end="url(#dtah)"/>
  <rect x="480" y="158" width="200" height="40" rx="6" fill="#e2e8f0"/>
  <text x="580" y="174" text-anchor="middle" font-size="11" font-weight="700" fill="#334155">vendor:device ID</text>
  <text x="580" y="189" text-anchor="middle" font-size="10.5" fill="#334155">匹配 pci_device_id</text>

  <rect x="40" y="212" width="640" height="34" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="360" y="233" text-anchor="middle" font-size="12.5" fill="#3730a3">硬件描述方式不同,但终点一致:都要落到各自的 match_table 上完成设备-驱动匹配</text>
</svg>

## udev

<svg viewBox="0 0 720 300" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="udev 处理内核 uevent 到创建设备节点、应用规则的流程">
  <defs><marker id="udevah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="300" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">udev:内核 uevent 到设备节点/规则应用的处理链</text>

  <rect x="40" y="60" width="190" height="40" rx="6" fill="#e2e8f0"/>
  <text x="135" y="78" text-anchor="middle" font-size="11" font-weight="700" fill="#334155">内核检测到事件</text>
  <text x="135" y="93" text-anchor="middle" font-size="10" fill="#475569">产生 uevent</text>
  <line x1="230" y1="80" x2="263" y2="80" stroke="#475569" stroke-width="1.6" marker-end="url(#udevah)"/>

  <rect x="265" y="60" width="190" height="40" rx="6" fill="#e2e8f0"/>
  <text x="360" y="78" text-anchor="middle" font-size="11" font-weight="700" fill="#334155">netlink socket</text>
  <text x="360" y="93" text-anchor="middle" font-size="10" fill="#475569">内核 → 用户态通道</text>
  <line x1="455" y1="80" x2="488" y2="80" stroke="#475569" stroke-width="1.6" marker-end="url(#udevah)"/>

  <rect x="490" y="60" width="190" height="40" rx="6" fill="#4f46e5"/>
  <text x="585" y="78" text-anchor="middle" font-size="11" font-weight="700" fill="#ffffff">udev 守护进程</text>
  <text x="585" y="93" text-anchor="middle" font-size="10" fill="#ffffff">接收到 uevent</text>

  <line x1="585" y1="100" x2="140" y2="178" stroke="#475569" stroke-width="1.6" marker-end="url(#udevah)"/>
  <line x1="585" y1="100" x2="360" y2="178" stroke="#475569" stroke-width="1.6" marker-end="url(#udevah)"/>
  <line x1="585" y1="100" x2="580" y2="178" stroke="#475569" stroke-width="1.6" marker-end="url(#udevah)"/>

  <rect x="40" y="180" width="200" height="50" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="140" y="200" text-anchor="middle" font-size="11" font-weight="700" fill="#115e59">加载内核模块</text>
  <text x="140" y="217" text-anchor="middle" font-size="10" fill="#0f766e">基于 modalias</text>

  <rect x="260" y="180" width="200" height="50" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="360" y="200" text-anchor="middle" font-size="11" font-weight="700" fill="#115e59">创建设备节点</text>
  <text x="360" y="217" text-anchor="middle" font-size="10" fill="#0f766e">/dev/sda 等</text>

  <rect x="480" y="180" width="200" height="50" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="580" y="200" text-anchor="middle" font-size="11" font-weight="700" fill="#115e59">应用自定义规则</text>
  <text x="580" y="217" text-anchor="middle" font-size="10" fill="#0f766e">权限 / 符号链接</text>

  <rect x="40" y="248" width="640" height="34" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="360" y="269" text-anchor="middle" font-size="12.5" fill="#115e59">内核只管发 uevent 通知;模块加载、设备节点创建、规则应用全部由用户态 udev 完成</text>
</svg>

## 参考

- **源码**: `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*
