USBコントロール転送とSetupパケットのデバッグ:bmRequestType、bRequest、wValue、wIndexの読み方

USB STALLエラーとコントロール転送の失敗を修正。bmRequestType、bRequest、wValue、wIndex、ファームウェアデバッグ用ディスクリプタリクエストの証拠を使って、Setupパケットの問題を診断します。

USB, コントロール転送, Setupパケット, ディスクリプタ, ファームウェア

USBコントロール転送は、ホストとデバイスとの「最初の真剣な会話」です。列挙はこれに依存し、クラスセットアップもこれに依存し、ベンダー固有の初期化も多くの場合これに依存します。コントロール転送が失敗したとき、ユーザーの目には「デバイスが認識されない」「ドライバが失敗した」としか映りませんが、証拠は大抵Setupパケットの中にあります。

ファームウェアエンジニアにとって、bmRequestTypebRequestwValuewIndexwLength を読めるようになるのは、推測から「ピンポイントの修正」へ進む最短ルートです。

Setupパケットはリクエストの「契約」

USB Setupパケットはデバイスに以下を伝えます。

  • 転送の方向
  • リクエスト種別:standard、class、vendor、reserved
  • 受信者:device、interface、endpoint、other
  • リクエストコード
  • valueフィールド
  • indexフィールド
  • 期待されるデータ長

ファームウェアがこれらのフィールドを誤って解釈すると、誤ったディスクリプタを返したり、正しいリクエストをストールさせたり、無効なコマンドを受け付けたりします。ホストが想定外のリクエストを送ってきた場合も、キャプチャにはそれが映ります。

GET_DESCRIPTORが最初のチェックポイント

列挙中、ホストは標準ディスクリプタリクエストを送ります。典型的なシーケンスは次のとおりです。

  • デバイスディスクリプタのリクエスト
  • コンフィギュレーションディスクリプタのリクエスト
  • 文字列ディスクリプタのリクエスト
  • HIDデバイスの場合HIDレポートディスクリプタのリクエスト
  • 新しいホストではBOSディスクリプタのリクエスト

Setupパケット内では、bRequestGET_DESCRIPTOR を示し、wValue にディスクリプタ種別とインデックスが入ります。wIndex は文字列ディスクリプタの言語IDや、クラス固有ディスクリプタのインターフェース番号を示すことがあります。wLength はホストが期待するバイト数です。

ディスクリプタ応答の長さが間違っている、あるいはファームウェアがホストの必要バイト数より少なく返した場合、列挙は後段で「まったく別件」のように見える失敗をすることがあります。

方向の取り違えは高くつく

コントロール転送には方向があります。Device-to-Hostリクエストはデータを返し、Host-to-Deviceリクエストはデータを運ぶか状態を構成します。ファームウェアが読み取りリクエストを書き込みとして扱ったり、書き込みリクエスト中にデータを送信したりすると、ホスト側は忖度してくれません。

注目ポイント:

  • IN方向だがデータステージがない
  • OUT方向なのにファームウェアがデータ送信を待っている
  • Zero-Length Status Stageが抜けている
  • 妥当な標準リクエストをSTALLしている
  • クラスリクエストを誤ったインターフェースで処理している

キャプチャには、リクエスト・データステージ・ステータスステージが並びます。

クラス/ベンダーリクエストにはインターフェース文脈が必要

列挙後、クラスドライバがクラス固有リクエストを送ります。CDCならラインコーディング、HIDならレポートディスクリプタやフィーチャーレポート、ベンダーツールなら初期化コマンド。同じ bRequest 値でも、リクエスト種別と受信者によって意味が変わります。

確認ポイント:

  • リクエスト種別
  • 受信者
  • wIndex 内のインターフェース番号
  • 受信者がエンドポイントの場合はエンドポイント番号
  • ペイロードバイト
  • 応答またはSTALL

複合デバイスで複数のインターフェースがある場合、誤ったインターフェースにリクエストをルーティングするのは定番バグです。

Bus Scopeがどう役立つか

Bus Scopeは「USBの証拠」のために作られています。コントロール転送のデバッグには、デコード済みのセットアップフィールドと生バイトが両方必要です。ファームウェアエンジニアが意味的なフィールドを読みながら、正確なパケットバイトを検証できるビューが理想です。

コントロール転送デバッグ向けの良いBus Scopeセッションは、次の問いに答えてくれます。

  • どのSetupパケットが失敗したか?
  • standard、class、vendorのどれか?
  • どのディスクリプタまたはインターフェースが要求されたか?
  • デバイスは期待された長さを返したか?
  • ファームウェアのSTALLは意図的か、不適切か?
  • 次の列挙ステップはこの応答に依存していたか?

問題は「USBコントロール転送失敗」と書かれますが、修正点は5フィールドのSetupパケットの中にあります。