USBエンドポイントSTALLとバルク転送タイムアウト:ファームウェア変更前にキャプチャを読む

USBエンドポイントSTALL、バルク転送タイムアウト、ファームウェア側データパスの失敗を、転送証拠を使ってデバッグする方法を解説します。

USB, エンドポイント, STALL, バルク転送, ファームウェア

列挙が成功したあとも、USBデバイスはアプリ開発者から見ると不可解な失敗をします。バルク読み出しがタイムアウトする、書き込みが永遠に完了しない、HIDレポートが来なくなる、ホストがエンドポイント STALL を報告する。こうした失敗はドライババグやランダムなファームウェアハング扱いされがちですが、キャプチャがあれば大抵はるかに早く原因を絞り込めます。

エンドポイントの失敗は「データパスの証拠」です。ホストがデバイスの形状を把握し終わったあとに起きます。つまり、ディスクリプタが正しくてもエンドポイント挙動は壊れている、ということが普通に起きます。

STALLは単なるエラーではなく「シグナル」

USBエンドポイントは、リクエストを処理できない/クラス/ベンダーコマンドが未サポートである、という意味でSTALLを返せます。クラス要求中のコントロールエンドポイントSTALLは、リクエストが無効なら正当なこともあります。データエンドポイントが通常転送中にSTALLするなら、詳しく見る価値があります。

キャプチャでの問い:

  • どのエンドポイントがストールしたか?
  • control、bulk、interrupt、isochronousのどれか?
  • ストールの前にどんなリクエスト/転送があったか?
  • ホストはHALT状態をクリアしたか?
  • CLEAR_FEATURE(ENDPOINT_HALT) のあとトラフィックは再開したか?
  • ファームウェアが意図的に未サポートコマンドをストールさせたか?

この文脈なしに「endpoint stalled」と言われても動きようがありません。

バルクタイムアウトには方向とキューの文脈が必要

バルク転送のタイムアウトはいろいろな意味を持ちます。

  • ホストがINデータを期待したがデバイス側に準備がない
  • デバイスがOUTデータを期待したがアプリが書き込みを止めた
  • ファームウェアのエンドポイントバッファがプライムされていない
  • ホストドライバがファームウェアの許容サイズを超える読み出しを発行
  • デバイスがタイムアウトまでNAKを返した
  • エンドポイントアドレスまたは方向が間違っていた
  • 直前のSTALLがクリアされていない

最初に確認すべきは方向です。バルクINタイムアウトとバルクOUTタイムアウトは別の話。INなら「デバイスは一度でもデータを返したか」、OUTなら「ホストはデータを送り、デバイスはACKしたか」を確認します。

ディスクリプタ正しさは必要条件だが十分条件ではない

ディスクリプタがバルクINエンドポイントを正しく宣言していても、デバイスが有用なデータを送らないことはあります。CDCデバイスがシリアルポートとして列挙されても、ラインコーディングやコントロールライン状態を無視することはあります。ベンダー固有インターフェースがエンドポイントを公開していても、データ移動の前に初期化コマンドが必要なこともあります。

つまり、エンドポイントデバッグは次の情報を組み合わせる必要があります。

  • ディスクリプタの証拠
  • クラス/ベンダーセットアップリクエスト
  • 転送方向
  • ペイロード長
  • ステータス結果
  • タイミングと繰り返しの試行

キャプチャは、ホストが無理な要求をしているのか、ファームウェアが妥当な要求に応えていないのかを切り分けてくれます。

ファームウェアチームは「修正前」と「修正後」をキャプチャする

エンドポイントバグでは、修正前後のキャプチャが大きな価値を持ちます。最初のキャプチャが失敗を証明し、2回目のキャプチャが修正を証明します。良い比較は次を示します。

  • 同じデバイス、同じコンフィギュレーション
  • 同じエンドポイントアドレス
  • 同じホストリクエストパターン
  • 旧キャプチャはストールまたはタイムアウト
  • 新キャプチャは完了し、期待ペイロードを運ぶ

ファームウェアの回帰レビューが一気にやりやすくなりますし、顧客から「USBがランダムに固まる」と報告されたときの再現可能なアーティファクトにもなります。

Bus Scopeが活きる場面

Bus Scopeは「広範なプロトコル対応」ではなく「USBの証拠」に重心を置いています。エンドポイントSTALL/タイムアウトケースでは、パケット詳細・エンドポイントメタデータ・生バイト・転送種別・クラス解釈を近くに並べて扱うべきです。

価値ある出力は:

  • エンドポイントと方向
  • 転送種別
  • 失敗前のリクエスト/転送
  • ステータス証拠
  • 失敗周辺の生ペイロード
  • 問題が列挙後/クラスセットアップ後/アプリトラフィック後のどこで起きたか

これは、ファームウェアエンジニアがエンドポイントバッファロジックやホスト側のリトライ挙動に手を入れる前に必要な情報です。

「USB bulk transfer timeout」「USB endpoint stalled」で検索しているなら、デバイススタック全体を書き直すところから始めないでください。まずエンドポイントの証拠を取得しましょう。