---
title: Device Model
url: https://doc.liz6.com/en/linux-kernel/10-drivers-and-device-model/01-device-model
locale: en
area: linux-kernel
tags:
- linux-kernel
- drivers-and-device-model
date: 2026-06-30
modified: 2026-07-16
description: 'Coverage: kobject/kset → device/driver/bus/class → sysfs binding → probe lifecycle → udev → device tree (DT) → ACPI → platform device Kernel versions: 2.6 ~ 6.x'
---

# Device Model

> Coverage: kobject/kset → device/driver/bus/class → sysfs binding → probe lifecycle → udev → device tree (DT) → ACPI → platform device
> Kernel versions: 2.6 ~ 6.x

## Overview

The Linux device model is an internal kernel framework that provides a unified representation and lifecycle management for all devices, drivers, and buses. Its core value lies not in "how devices work," but in "how devices and drivers find each other"—namely, **device-driver binding**.

## kobject: The Basic Building Block

```c
// include/linux/kobject.h
struct kobject {
    const char      *name;           // Name displayed in sysfs
    struct kobject  *parent;         // Parent node → sysfs directory hierarchy
    struct kset     *kset;           // Belonging kset (collection)
    struct kernfs_node *sd;         // dentry in sysfs (kernfs)
    struct kref     kref;            // Reference count
    unsigned int    state_initialized:1;
};

// kobject itself does not manage devices — it provides:
//   1. Directory/file representation in sysfs
//   2. Reference counting → automatic release
//   3. Parent-child hierarchical relationships
```

### kset: A Collection of kobjects

```c
struct kset {
    struct list_head list;           // List of all member kobjects
    struct kobject  kobj;            // Embedded kobject (the collection itself in sysfs)
    const struct kobj_type *ktype;   // Type operations
};

// Example: /sys/devices/ → devices_kset
//          /sys/bus/ → bus_kset
```

---

## Device / Driver / Bus

### struct device

```c
// include/linux/device.h
struct device {
    struct kobject      kobj;               // sysfs representation
    struct device       *parent;            // Parent device (e.g., PCI bridge)
    const char          *init_name;
    struct bus_type     *bus;               // Bus it belongs to
    struct device_driver *driver;           // Bound driver
    void                *driver_data;       // Driver-specific private data
    struct device_node   *of_node;          // DT node
    u64                 *dma_mask;          // DMA addressing range
    const struct attribute_group **groups;  // sysfs attribute groups
    void (*release)(struct device *dev);    // Mandatory! (release callback)
};
```

### struct device_driver

```c
struct device_driver {
    const char              *name;
    struct bus_type         *bus;
    int (*probe)(struct device *dev);           // Probe: driver binds to device
    void (*remove)(struct device *dev);         // Remove: unbind
    void (*shutdown)(struct device *dev);
    const struct of_device_id *of_match_table;  // DT matching
    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);           // Bus-level probe
    struct subsys_private *p;                   // Device list + driver list
};
```

### Binding Flow

```c
// drivers/base/dd.c
// Device registration:
device_register(dev)
  → device_add(dev)
    → bus_add_device(dev)     // Attach to bus->p->klist_devices
    → bus_probe_device(dev)
      → device_initial_probe(dev)
        → __device_attach(dev, true)
          → bus_for_each_drv(dev->bus, ...)  // Iterate through all registered drivers
            → driver_match_device(drv, dev)  // bus->match() or 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)
```

**Key Point**: Binding is bidirectional—when a new device arrives, it iterates through drivers; when a new driver registers, it iterates through devices. Regardless of who registers first, the match will occur.

---

## sysfs and Attributes

```c
// Each directory under /sys = one kobject
// Attribute files = 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);
};

// Macros: DEVICE_ATTR_RO(name) → generates read-only attribute
//         DEVICE_ATTR_WO(name) → write-only
//         DEVICE_ATTR_RW(name) → read-write
```

---

## 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="Comparison of three hardware description methods: Device Tree, ACPI, PCIe, and their respective driver matching paths">
  <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: Different hardware description methods, different matching mechanisms</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">Static description of hardware topology</text>
  <text x="52" y="114" font-size="10.5" fill="#3730a3">Passed to kernel by bootloader</text>
  <text x="52" y="128" font-size="10.5" fill="#3730a3">platform_device binds to DT node</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">Matches compatible strings</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">Provided by UEFI/BIOS</text>
  <text x="272" y="118" font-size="10.5" fill="#0f766e">Firmware dynamically describes hardware</text>
  <text x="272" y="132" font-size="10.5" fill="#0f766e">+ Power management methods</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">Matches _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 · Self-Enumeration</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">Regardless of architecture</text>
  <text x="492" y="118" font-size="10.5" fill="#334155">Does not rely on DT / ACPI description</text>
  <text x="492" y="132" font-size="10.5" fill="#334155">Bus enumerates devices itself</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">Matches 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">Different hardware description methods, but the destination is the same: all must fall back to their respective match_table to complete device-driver matching</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="Flowchart of udev processing kernel uevents to create device nodes and apply rules">
  <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: Processing chain from kernel uevent to device nodes/rule application</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">Kernel detects event</text>
  <text x="135" y="93" text-anchor="middle" font-size="10" fill="#475569">Generates 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">Kernel → User-space channel</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 daemon</text>
  <text x="585" y="93" text-anchor="middle" font-size="10" fill="#ffffff">Receives 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">Load kernel module</text>
  <text x="140" y="217" text-anchor="middle" font-size="10" fill="#0f766e">Based on 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">Create device node</text>
  <text x="360" y="217" text-anchor="middle" font-size="10" fill="#0f766e">/dev/sda, etc.</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">Apply custom rules</text>
  <text x="580" y="217" text-anchor="middle" font-size="10" fill="#0f766e">Permissions / Symlinks</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">The kernel only sends uevent notifications; module loading, device node creation, and rule application are all handled by user-space udev</text>
</svg>

## References

- **Source Code**: `drivers/base/core.c`, `drivers/base/bus.c`, `drivers/base/dd.c`, `include/linux/device.h`
- **Kernel Documentation**: `Documentation/driver-api/driver-model/`

*Keywords: kobject, device, driver, bus, probe, sysfs, device tree, ACPI, udev, modalias*
