USB複合デバイスのデバッグ:インターフェース番号、IAD、エンドポイント、ドライババインド
あるインターフェースは動くが別のインターフェースは失敗する、ホストが誤ったドライバをバインドする、といったUSB複合デバイスの問題をデバッグする方法を解説します。
USB複合デバイスは便利である一方、落とし穴も多い存在です。1つのデバイスでHIDコントロール、CDCシリアル、マスストレージ、ベンダー固有エンドポイント、オーディオ、ビデオ、診断用インターフェースを公開できます。すべてが正しく記述されていれば、ホストは適切なドライバをバインドし、各機能が動きます。しかしディスクリプタのどこか1つでも間違えると、デバイス全体が「なんだか不安定」に見えてしまいます。
「USB composite device not recognized」「CDC interface not showing」「HID works but serial does not」「wrong driver binding USB interface」といった検索ワードは、ほぼ間違いなく「ディスクリプタ構造」「インターフェース番号」「エンドポイント割り当て」「IAD(Interface Association Descriptor)の挙動」を示しています。
複合デバイスには一貫したコンフィギュレーションが必要
コンフィギュレーションディスクリプタはトップレベルの地図です。トータル長さ、インターフェース数、電源属性、すべての入れ子になったインターフェース/エンドポイントディスクリプタを記述しなければなりません。wTotalLength が間違っていれば、ホストはすべての機能を読まないかもしれません。インターフェース数が間違っていれば、後のインターフェースが無視されます。エンドポイントアドレスが衝突すれば、転送が曖昧になるか無効になります。
確認ポイント:
- コンフィギュレーションのトータル長さ
- インターフェース数
- インターフェース番号
- Alternate Setting
- エンドポイントアドレス
- エンドポイントの方向
- class、subclass、protocolの値
- ディスクリプタの順序
キャプチャを見れば、ホストが完全なコンフィギュレーションを要求したか、デバイスが何を返したかが分かります。
IADは関連インターフェースをまとめる
IAD(Interface Association Descriptor)は、CDCのCommunication+Dataのように、1つの機能に属する複数のインターフェースをまとめるために使われます。グループ化が正しくないと、ホストはドライバを誤バインドしたり、機能の一部しか公開しなかったりします。
IADで見るべき証拠:
- 最初のインターフェース番号
- インターフェース数
- function class、subclass、protocol
- まとめられたインターフェース群より前に配置されているか
- 実際のインターフェースディスクリプタと整合しているか
CDCシリアルが現れないのにHIDが動くなら、HID側は健全で、CDCのグループ化が壊れている可能性があります。
エンドポイントアドレスの衝突は見落とされがち
エンドポイントアドレスには方向が含まれます。エンドポイント 0x81 と 0x01 は方向が違うので別物ですが、同じコンフィギュレーション内で2つのINエンドポイントが同じアドレスを持つことは不正です。ファームウェアチームによっては、エンドポイントディスクリプタをインターフェース間でコピーして、アドレスの更新を忘れてしまうことがあります。
症状:
- あるインターフェースは動くが、別のインターフェースは無反応
- ホストが想定外のエンドポイントに転送を送る
- クラスドライバは読み込まれるがアプリにデータがこない
- コンフィギュレーション後にエンドポイントSTALLまたはタイムアウト
- 同時に動く機能が1つだけ
キャプチャでエンドポイントディスクリプタとその後の転送トラフィックを並べて確認しましょう。
ドライババインドも「証拠」の一部
ホストはディスクリプタを見てドライバを選びます。バインドが間違っているなら、ディスクリプタ側にその理由が必ず残っています。class、subclass、protocol、インターフェース関連、Compatible ID、OS固有ディスクリプタ、いずれもバインドに影響します。
デバイスマネージャやアプリのログだけでバインド問題を診断しないでください。ホストのクラス固有リクエストとディスクリプタツリーを突き合わせること。期待していたクラスリクエストが来ていないなら、ホストが想定どおりのドライバをバインドしていない可能性が高いです。
Bus Scopeが活きる場面
Bus Scopeは、複合デバイスを2つのレイヤーで観察できるよう設計されています。
- ディスクリプタマップ
- ドライババインド後の転送証拠
複合デバッグのための良い .bscope セッションは、次の情報を含みます。
- すべてのインターフェース
- IADによるグループ化
- エンドポイント割り当て
- インターフェースごとのクラス固有リクエスト
- 生ディスクリプタバイト
- コンフィギュレーション後の転送ステータス
これがあれば、サポート会話が具体的になります。「Windowsが複合デバイスを受け付けない」ではなく、「グループ化ディスクリプタが宣言されたインターフェース配置と一致しないため、interface 2にはCDCクラスリクエストが届いていない」と報告できる。これは、ファームウェアチームが必要としている証拠レベルです。