---
title: デバイスモデル
url: https://doc.liz6.com/ja/linux-kernel/10-drivers-and-device-model/01-device-model
locale: ja
area: linux-kernel
tags:
- linux-kernel
- drivers-and-device-model
date: 2026-06-30
modified: 2026-07-16
description: 'カバー範囲: kobject/kset → device/driver/bus/class → sysfs バインディング → probe ライフサイクル → udev → デバイスツリー (DT) → ACPI → platform device | カーネルバージョン: 2.6 ~ 6.x'
---

# デバイスモデル

> カバー範囲: kobject/kset → device/driver/bus/class → sysfs バインディング → probe ライフサイクル → udev → デバイスツリー (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);           // バスレベルのプロブ
    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 下の各ディレクトリ = 1つの 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 の3つのハードウェア記述方法とドライバマッチングパスの比較">
  <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">ブートローダからカーネルへ渡される</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 ソケット</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*
