HIDレポートディスクリプタのデバッグ:デバイスは列挙できるのにホストが読み違える原因

USBデバイスが正常に列挙されてもホスト側で誤動作するHIDレポートディスクリプタの不備を診断する方法を解説します。

USB, HID, レポートディスクリプタ, ファームウェア, デバッグ

HIDの魅力は、なんといっても「独自ドライバなしでも動く」点ですよね。キーボード、センサ、ノブ、バーコードリーダ、操作パネル、ベンダー固有のHID機器など、いずれも標準ホストスタックの恩恵を受けられます。その一方で、HIDは複雑さをレポートディスクリプタ側に押し込みます。そのため、デバイスは正常に列挙されたのに、ホスト側では誤ったデータとして解釈される、というケースが頻発します。

これはUSBファームウェアで最も多い落とし穴のひとつで、「列挙に成功=HIDも正しい」と誤解されてしまうパターンです。

レポートディスクリプタは「データ契約」を定義する

HIDレポートディスクリプタは、ホストに対して「バイト列をどう解釈するか」を伝えます。Usage、Report Size、Report Count、Logical Minimum/Maximum、Physical Minimum/Maximum、Collection、Report IDなどを定義します。ディスクリプタがAと言っているのにファームウェアがBを送ってきた場合、ホストは必ずディスクリプタ側を信頼します。

よくある不具合には、次のようなものがあります。

  • ファームウェアは8バイト送っているが、ディスクリプタは7バイトと記述している
  • Report IDが抜けている/余分に入っている
  • 符号付き値を符号なしとして記述している
  • Logical Min/Maxが実際のレンジと合っていない
  • Usage Pageを間違えている
  • パディングビットのカウントがズレている
  • 複数レポートのレイアウトが分かりにくい
  • InputレポートとOutputレポートを取り違えている

症状としては、アプリケーション側で「値がおかしい」「ボタンが反応しない」「レポートが無視される」「不定期に欠落する」といった形で現れます。

ディスクリプタとレポートを同時にキャプチャする

HIDのデバッグを、レポートディスクリプタだけでは不十分ですし、ペイロードの生バイトだけでも不十分です。両方が揃って初めて議論できます。

有用なHIDキャプチャには、次の情報が含まれます。

  • デバイスディスクリプタ
  • コンフィギュレーション/インターフェースディスクリプタ
  • HIDディスクリプタ
  • レポートディスクリプタのリクエストと応答
  • Interrupt IN レポート
  • (必要に応じて)Interrupt OUT レポート
  • フィーチャーレポート用のコントロール転送
  • Report IDとペイロード長

こうして初めて、宣言されたレイアウトと実際のバイト列を比較できます。ディスクリプタで Report Count 3 と言っているのに、Interruptのペイロードが4つの値を載せているなら、キャプチャ上でその不一致が一目で分かるべきです。

「ホスト側が正しく見えるのに間違って見える」こともある

ファームウェア開発者の方が「ホストがデータを捨てている」と感じるとき、実際には「ホストがディスクリプタに従ってパースしているだけ」というケースがよくあります。ディスクリプタがパディングや異なるReport IDを宣言していれば、データの位置がズレたり、切り詰められたり、無視されたりして見えます。

だからこそ、サポートレポートには「生バイト」を残しておくべきです。デコード済みの解釈も便利ですが、議論を最終的に決めるのは生バイトです。突き詰めるべき問いは次の4つに集約されます。

  • ファームウェアは何を送ったか?
  • ファームウェアは何を宣言したか?
  • ホストは何を要求したか?
  • ホストは何を受け取ったか?

この4点が、HIDデバッグの正しい境界線です。

複合HIDデバイスは特に慎重に

複合デバイスでは、HIDとCDC、ストレージ、ベンダー固有インターフェースが同居することがあります。HID部分単体としては正しくても、インタフェース番号やエンドポイント割り当て、ディスクリプタ全体の長さエラーなどの影響を受けて、不具合が出るケースがあります。

複合HIDをデバッグするときは、次の点を確認しましょう。

  • 該当する場合はInterface Association
  • インターフェース番号
  • エンドポイントアドレスの一意性
  • HIDディスクリプタの位置
  • レポートディスクリプタの長さ
  • クラス固有リクエストのルーティング

ホストがレポートディスクリプタを誤ったインターフェースから取得したり、長さを間違って受け取ったりすると、そのあとのレポートトラフィック全体が誤解を招くものになります。

Bus Scopeが活きる場面

Bus Scopeは、証拠に基づいてUSBをデバッグしたいファームウェア/デバイスチームのために設計されています。HIDレポートディスクリプタのケースでは、ディスクリプタツリー・生バイト・エンドポイントトラフィック・保存済み.bscopeセッションを、同じ場所でまとめて確認できるように作られています。

最終的に残すべきレポートは、次のような構造になっているはずです。

  • HIDレポートディスクリプタが要求され、返されたこと
  • ディスクリプタが宣言するレポート長
  • 実際のInterruptペイロード長
  • Report IDの挙動
  • 宣言とトラフィックの一致/不一致
  • ファームウェアのディスクリプタ、レポートパッキング、ホストパーサ側の想定に対する次のアクション

これは「HIDデバイスが動かない」という漠然とした課題ではなく、USBの契約(contract)の不一致という具体的な問題に変換します。