# 通知設計書 16-DEVICE イベント

## 概要

本ドキュメントは、FreeBSDカーネルにおけるUSB DEVICEイベント通知の設計を記述する。USBデバイスの接続（ATTACH）または切断（DETACH）が検出された際にdevctl(4)サブシステムを通じてユーザーランドに通知を送信する仕組みについて定義する。

### 本通知の処理概要

USB DEVICEイベント通知は、USBデバイスのアタッチまたはデタッチ時にusb_notify_addq()関数内でdevctl_notifyにより発行されるカーネル通知である。デバイスのベンダーID、プロダクトID、シリアル番号等の詳細情報が含まれる。

**業務上の目的・背景**：USBデバイスのホットプラグ（動的な接続・切断）はFreeBSDシステムにおいて日常的に発生するイベントである。ユーザーランドのデバイス管理デーモン（devd(8)）がUSBデバイスの接続・切断を検知し、ドライバのロード、デバイスノードの作成、マウント処理、セキュリティポリシーの適用などを自動的に行うために本通知が必要である。

**通知の送信タイミング**：USBデバイスの列挙（enumeration）が完了しデバイスが正常にアタッチされた時点（ATTACH）、またはデバイスのデタッチ処理の開始時点（DETACH）で送信される。

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

**通知内容の概要**：システム名「USB」、サブシステム名「DEVICE」、タイプ「ATTACH」または「DETACH」、データとしてUSBデバイスの詳細情報（ugen名、ベンダーID、プロダクトID、デバイスクラス、シリアル番号、リリース番号、モード、ポート番号、親ハブ）が通知される。

**期待されるアクション**：devd(8)がUSBデバイスイベントを検知し、ATTACH時にはドライバのロード、デバイスノードの設定、自動マウント等を行い、DETACH時にはデバイスノードの削除、アンマウント等を行う。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

### devctl通知の場合

| 項目 | 内容 |
|-----|------|
| システム名 | USB |
| サブシステム名 | DEVICE |
| タイプ | ATTACH / DETACH |
| データ | USBデバイス情報（下記参照） |

### 本文テンプレート

```
!system=USB subsystem=DEVICE type=ATTACH ugen={ugen_name} cdev={ugen_name} vendor=0x{idVendor} product=0x{idProduct} devclass=0x{bDeviceClass} devsubclass=0x{bDeviceSubClass} sernum="{serial}" release=0x{bcdDevice} mode={host|device} port={port_no} parent={parent_name}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| ugen | ugenデバイス名 | udev->ugen_name | Yes（USB_HAVE_UGEN有効時） |
| cdev | キャラクタデバイス名 | udev->ugen_name | Yes（USB_HAVE_UGEN有効時） |
| vendor | ベンダーID | udev->ddesc.idVendor | Yes |
| product | プロダクトID | udev->ddesc.idProduct | Yes |
| devclass | デバイスクラス | udev->ddesc.bDeviceClass | Yes |
| devsubclass | デバイスサブクラス | udev->ddesc.bDeviceSubClass | Yes |
| sernum | シリアル番号 | usb_get_serial(udev) | Yes |
| release | リリース番号 | udev->ddesc.bcdDevice | Yes |
| mode | USBモード | udev->flags.usb_mode | Yes |
| port | ポート番号 | udev->port_no | Yes |
| parent | 親ハブ名 | udev->parent_hub->ugen_name | Yes（USB_HAVE_UGEN有効時） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| カーネル内部 | USBデバイスアタッチ完了 | USB_HAVE_DEVCTL有効 | usb_notify_addq("ATTACH", udev) |
| カーネル内部 | USBデバイスデタッチ開始 | USB_HAVE_DEVCTL有効 | usb_notify_addq("DETACH", udev) |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| USB_HAVE_DEVCTL無効 | コンパイル時にUSB_HAVE_DEVCTLが無効の場合、通知は発行されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[USBデバイスイベント発生] --> B{ATTACH or DETACH?}
    B -->|ATTACH| C[usb_notify_addq ATTACH]
    B -->|DETACH| D[usb_notify_addq DETACH]
    C --> E[sbuf_new_auto]
    D --> E
    E --> F[デバイス情報をsbufに書き込み]
    F --> G[sbuf_finish]
    G --> H[devctl_notify USB/DEVICE/type/sbuf_data]
    H --> I[sbuf_delete]
    I --> J[各インターフェースの通知ループ - No.17参照]
    J --> K[終了]
```

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| usb_device構造体 | USBデバイス情報の参照 | ugen_name, ddesc, port_no等 |
| usb_device_descriptor | USBデバイスディスクリプタ | idVendor, idProduct等 |

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

#### usb_device構造体

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| ugen_name | ugenデバイス名 | USB_HAVE_UGEN有効時 |
| ddesc.idVendor | ベンダーID | UGETWマクロで取得 |
| ddesc.idProduct | プロダクトID | UGETWマクロで取得 |
| ddesc.bDeviceClass | デバイスクラス | 直接参照 |
| ddesc.bDeviceSubClass | デバイスサブクラス | 直接参照 |
| ddesc.bcdDevice | リリース番号 | UGETWマクロで取得 |
| flags.usb_mode | USBモード（host/device） | 直接参照 |
| port_no | ポート番号 | 直接参照 |
| parent_hub | 親ハブへのポインタ | USB_HAVE_UGEN有効時 |

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| devctl送信失敗 | devctlキューが満杯 | 通知は破棄される |
| sbuf割り当て失敗 | メモリ不足 | sbuf_new_autoがNULLを返す場合の処理 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし。

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

- devctl(4)デバイスへのアクセスにはroot権限が必要
- USBデバイスのシリアル番号が通知データに含まれる（プライバシー情報の可能性）
- ベンダーID・プロダクトIDによりデバイスの種類が識別可能

## 備考

- usb_notify_addq()関数はsys/dev/usb/usb_device.cの2699行目に定義されている
- devctl_notify()呼び出しは2743行目で行われる
- USB_HAVE_DEVCTLコンパイル条件（2697行目）で通知機能の有効/無効が制御される
- USB_HAVE_UGENが有効な場合のみugen名とcdev名が通知に含まれる
- 本通知の後にNo.17のINTERFACE通知が各インターフェースに対して発行される

---

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

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

### 推奨読解順序

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

USBデバイス構造体とデバイスディスクリプタの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | usb_device.h | `sys/dev/usb/usb_device.h` | usb_device構造体のugen_name、ddesc、flags等 |
| 1-2 | usb.h | `sys/dev/usb/usb.h` | usb_device_descriptor構造体、UGETWマクロ |

**読解のコツ**: USBデバイス情報はusb_device構造体に集約されており、ddescフィールドがUSB標準のデバイスディスクリプタを保持する。マルチバイト値はUGETWマクロでホストバイトオーダーに変換される。

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

usb_notify_addq()の呼び出し元（アタッチ・デタッチ処理）を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | usb_device.c | `sys/dev/usb/usb_device.c` | usb_probe_and_attach()内のusb_notify_addq("ATTACH", ...)呼び出し（2105行目） |
| 2-2 | usb_device.c | `sys/dev/usb/usb_device.c` | usb_free_device()内のusb_notify_addq("DETACH", ...)呼び出し（2304行目） |

#### Step 3: 通知生成処理を理解する

usb_notify_addq()関数の内部でのsbufによるデータ生成とdevctl_notify呼び出しを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | usb_device.c | `sys/dev/usb/usb_device.c` | usb_notify_addq()関数（2699-2792行目） |

**主要処理フロー**:
- **2706行目**: sbuf_new_auto()でsbufを作成
- **2707-2741行目**: sbuf_printf()でデバイス情報を書き込み
- **2742行目**: sbuf_finish()
- **2743行目**: devctl_notify("USB", "DEVICE", type, sbuf_data(sb))
- **2744行目**: sbuf_delete(sb)
- **2747-2791行目**: 各インターフェースに対するINTERFACE通知ループ

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

```
usb_probe_and_attach() [ATTACH時]
    |
    +-- usb_notify_addq("ATTACH", udev) [sys/dev/usb/usb_device.c:2105]

usb_free_device() [DETACH時]
    |
    +-- usb_notify_addq("DETACH", udev) [sys/dev/usb/usb_device.c:2304]

usb_notify_addq() [sys/dev/usb/usb_device.c:2699]
    |
    +-- sbuf_new_auto() / sbuf_printf() / sbuf_finish()
    +-- devctl_notify("USB", "DEVICE", type, sbuf_data)
    +-- sbuf_delete()
    +-- [ループ] devctl_notify("USB", "INTERFACE", type, ...)  -- No.17参照
```

### データフロー図

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

usb_device (udev) --->  usb_notify_addq()           --->  devctl(4)キュー
type ("ATTACH"/          |                              |
      "DETACH")          +-- sbufでデータ生成           +-- devd(8)
                         +-- devctl_notify(DEVICE)
                         +-- devctl_notify(INTERFACE) x N
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| usb_device.c | `sys/dev/usb/usb_device.c` | ソース | usb_notify_addq()の実装、devctl_notify呼び出し |
| usb_device.h | `sys/dev/usb/usb_device.h` | ヘッダー | usb_device構造体の定義 |
| usb.h | `sys/dev/usb/usb.h` | ヘッダー | USB定数・マクロの定義 |
| usb_core.h | `sys/dev/usb/usb_core.h` | ヘッダー | USBコア定義 |
| devctl.h | `sys/sys/devctl.h` | ヘッダー | devctl_notify()のプロトタイプ |
