# 通知設計書 18-汎用ACPI通知

## 概要

本ドキュメントは、FreeBSDカーネルにおける汎用ACPI通知の設計を記述する。ACPIサブシステムからのNotifyイベントが発生した際にacpi_UserNotify()関数を通じてdevctl(4)サブシステムにユーザーランド通知を送信する仕組みについて定義する。

### 本通知の処理概要

汎用ACPI通知は、ACPIサブシステムからNotifyイベントを受信した際にacpi_UserNotify()関数内でdevctl_notifyにより発行されるカーネル通知である。ACPIの各種デバイス（電源ボタン、蓋スイッチ、バッテリー、サーマルゾーン等）からの通知を統一的なフォーマットでユーザーランドに中継する。

**業務上の目的・背景**：ACPIは電源管理やハードウェア設定の標準インターフェースであり、BIOSやファームウェアからの多様なイベント（電源状態変更、デバイス状態変化、温度警告等）をカーネルに通知する。これらのイベントをユーザーランドのデーモン（devd(8)、powerd(8)等）に中継し、適切な電源管理アクション（サスペンド、シャットダウン、輝度調整等）を実行するために本通知が必要である。

**通知の送信タイミング**：ACPIサブシステムがNotifyイベントを受信し、acpi_UserNotify()関数が呼び出された時点で送信される。subsystemがNULLでなく、ACPIハンドルのパス名取得が成功した場合に発行される。

**通知の受信者**：devctl(4)デバイスをオープンしているユーザーランドプロセス。主にdevd(8)デーモンとpowerd(8)デーモンが受信する。

**通知内容の概要**：システム名「ACPI」、サブシステム名（ACPIデバイスの種別：例えば"Lid"、"Button"等）、タイプとしてACPIオブジェクトのパス名、データとして通知値（notify=0xNN）が通知される。

**期待されるアクション**：devd(8)がACPIイベントを検知し、通知の種類に応じてサスペンド、シャットダウン、画面のロック、電源プロファイルの変更などを実行する。

## 通知種別

カーネルdevctl通知（devctl_notify経由）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（devctl(4)キュー経由） |
| 優先度 | 通常 |
| リトライ | なし |

### 送信先決定ロジック

devctl(4)デバイスファイル(/dev/devctl)をオープンしているすべてのプロセスに対してブロードキャスト送信される。

## 通知テンプレート

### devctl通知の場合

| 項目 | 内容 |
|-----|------|
| システム名 | ACPI |
| サブシステム名 | {ACPIデバイス種別} |
| タイプ | {ACPIオブジェクトのフルパス名} |
| データ | notify=0x{通知値(16進)} |

### 本文テンプレート

```
!system=ACPI subsystem={subsystem} type={acpi_path} notify=0x{notify_value}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| subsystem | ACPIデバイス種別 | 呼び出し元が指定 | Yes |
| acpi_path | ACPIオブジェクトのフルパス名 | AcpiNsHandleToPathname(h) | Yes |
| notify_value | ACPI通知値（0-255） | notify引数（uint8_t） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ACPI Notify | ACPIサブシステムからのNotifyイベント | subsystem != NULLかつパス名取得成功 | 各種ACPIデバイスのNotifyハンドラから呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| subsystemがNULL | subsystem引数がNULLの場合、関数は即座にリターン |
| パス名取得失敗 | AcpiNsHandleToPathname()がACPI_FAILUREを返した場合、通知は発行されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[acpi_UserNotify呼び出し] --> B{subsystem == NULL?}
    B -->|Yes| C[リターン]
    B -->|No| D[handle_buf初期化]
    D --> E[AcpiNsHandleToPathname]
    E --> F{ACPI_FAILURE?}
    F -->|Yes| G[リターン]
    F -->|No| H[notify_buf生成 notify=0xNN]
    H --> I[devctl_notify ACPI/subsystem/path/notify_buf]
    I --> J[AcpiOsFree handle_buf]
    J --> K[終了]
    C --> K
    G --> K
```

## データベース参照・更新仕様

該当なし（カーネル内メモリ構造体の操作のみ）

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| ACPI_HANDLE | ACPIオブジェクトハンドル | ACPIネームスペースのオブジェクト参照 |
| ACPI_BUFFER | パス名バッファ | AcpiNsHandleToPathnameで使用 |

### テーブル別参照項目詳細

#### ACPI名前空間

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| オブジェクトパス名 | devctl通知のタイプフィールド | AcpiNsHandleToPathname()で変換 |

### 更新テーブル一覧

該当なし（通知の発行のみ）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| パス名取得失敗 | ACPI名前空間の解決エラー | 通知を発行せずリターン |
| devctl送信失敗 | devctlキューが満杯 | 通知は破棄される |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。

## セキュリティ考慮事項

- devctl(4)デバイスへのアクセスにはroot権限が必要
- ACPI通知値はハードウェアイベントの種類を示す（0x00-0xFF）
- ACPIオブジェクトパス名にはハードウェアトポロジ情報が含まれる

## 備考

- acpi_UserNotify()関数はsys/dev/acpica/acpi.cの4561行目に定義されている
- devctl_notify()呼び出しは4577行目で行われる
- handle_buf.LengthにはACPI_ALLOCATE_BUFFERが設定され、ACPICAが動的にメモリを割り当てる
- notify_bufは16バイトの固定サイズバッファ
- AcpiOsFree()でACPICAが割り当てたメモリを解放する（4578行目）
- 本関数は多くのACPIドライバ（acpi_button、acpi_lid、acpi_thermal等）から呼び出される汎用通知関数である

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

ACPI_HANDLEとACPI_BUFFERの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | acpi.h | `sys/contrib/dev/acpica/include/acpi.h` | ACPI型定義のインクルード構造 |
| 1-2 | actypes.h | `sys/contrib/dev/acpica/include/actypes.h` | ACPI_HANDLE、ACPI_BUFFER、ACPI_STATUSの定義 |

**読解のコツ**: ACPI_HANDLEは不透明ポインタ型であり、ACPIネームスペース上のオブジェクトを参照する。ACPI_BUFFERはPointer/Lengthのペアで、ACPI_ALLOCATE_BUFFERを設定するとACPICA内部で自動的にメモリが割り当てられる。

#### Step 2: エントリーポイントを理解する

acpi_UserNotify()がACPIイベントのdevctl通知の中心関数である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | acpi.c | `sys/dev/acpica/acpi.c` | acpi_UserNotify()関数（4561-4579行目） |

**主要処理フロー**:
1. **4568行目**: subsystem == NULLチェック（NULLなら即リターン）
2. **4571-4572行目**: handle_buf初期化（Pointer=NULL、Length=ACPI_ALLOCATE_BUFFER）
3. **4573行目**: AcpiNsHandleToPathname()でハンドルをパス名に変換
4. **4574-4575行目**: ACPI_FAILURE時は即リターン
5. **4576行目**: notify_buf生成（"notify=0x%02x"フォーマット）
6. **4577行目**: devctl_notify("ACPI", subsystem, handle_buf.Pointer, notify_buf)
7. **4578行目**: AcpiOsFree()でメモリ解放

#### Step 3: 呼び出し元を理解する

acpi_UserNotify()がどのようなACPIイベントから呼び出されるかを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | acpivar.h | `sys/dev/acpica/acpivar.h` | acpi_UserNotify()のプロトタイプ宣言 |

### プログラム呼び出し階層図

```
[各種ACPIドライバのNotifyハンドラ]
    |
    +-- acpi_button_notify_handler()  [電源/スリープボタン]
    +-- acpi_lid_notify_handler()     [蓋スイッチ]
    +-- acpi_thermal_notify_handler() [温度センサ]
    +-- acpi_battery_notify_handler() [バッテリー]
    +-- ...
    |
    +-- acpi_UserNotify() [sys/dev/acpica/acpi.c:4561]
           |
           +-- AcpiNsHandleToPathname()
           +-- devctl_notify("ACPI", subsystem, path, notify_buf)
           +-- AcpiOsFree()
```

### データフロー図

```
[入力]                       [処理]                          [出力]

subsystem (文字列)  --->  acpi_UserNotify()          --->  devctl(4)キュー
ACPI_HANDLE (h)           |                              |
notify (uint8_t)          +-- パス名変換                  +-- devd(8)
                          +-- notify_buf生成              +-- powerd(8)
                          +-- devctl_notify
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| acpi.c | `sys/dev/acpica/acpi.c` | ソース | acpi_UserNotify()の実装、devctl_notify呼び出し |
| acpivar.h | `sys/dev/acpica/acpivar.h` | ヘッダー | acpi_UserNotify()のプロトタイプ |
| acpi.h | `sys/contrib/dev/acpica/include/acpi.h` | ヘッダー | ACPI型定義 |
| actypes.h | `sys/contrib/dev/acpica/include/actypes.h` | ヘッダー | ACPI_HANDLE、ACPI_BUFFER等の定義 |
| devctl.h | `sys/sys/devctl.h` | ヘッダー | devctl_notify()のプロトタイプ |
