Raspberry Pi用ベアメタルUSBデバイスドライバ「csud」の調査(4)

ベアメタルRaspberry PiのUSBドライバの続きです。
csudで、Raspberry Pi Zero Wに直接接続したキーボードを取り外すと処理が正しく行えない問題を修正しました。
root hubからデバイスを取り外した際の「変更あり」フラグが設定できていなかったのが原因でした。

Raspberry Pi Zero WにUSBハブをつないで、そこに接続したキーボードを外したときは、正常に取り外し処理が行われます。
この処理は、概ね以下のような流れで行われています。

UsbCheckForChange
→HubCheckForChange
 →HubCheckConnection
  →HubPortGetStatus
   →UsbControlMessage
    →HcdSumbitControlMessage
     HcdChannelSendWait // Setup
     HcdChannelSendWait // Data
     HcdChannelSendWait // Status
   HubPortConnectionChanged
   →HubPortGetStatus
    HubChangePortFeature

HubPortGetStatusでデバイスの接続状況を確認しています。
この処理はデバイスへUSB経由でStatusコマンドを送ることで行われています。

一方、root hubからデバイスを取り外す場合はHcdSumbitControlMessageの内部で以下のように分岐しています。
この場合は、接続処理は正しく行われますが、取り外し処理が行われません。

    if (pipe.Device == RootHubDeviceNumber) {
return HcdProcessRootHubMessage(device, pipe, buffer, bufferLength, request);
}

この結果、HcdSumbitControlMessage以降の流れは以下のようになります。

    →HcdSumbitControlMessage //ここまでは同じ
     →HcdProcessRootHubMessage
      switch (request->Request) {
      case GetStatus:
       switch (request->Type) {
       case 0xa3:
        // Statusを取得
       }
      }

root hubのポート(Zero WではオンボードのUSBコネクタに相当)の接続状況のチェックはHcdProcessRootHubMessageで行っていますが、この処理はUSBでStatusメッセージを送る代わりに、USBコントローラのレジスタ(0x0440)の値を読み出しています。

詳しく見てみると、USBコントローラのレジスタには、USBポートの状況を表す2つのフラグ

・Port.Connect(bit 0; デバイスが接続されていればtrue)
・Port.ConnectDetected(bit 1; デバイスが新たに接続されたときにtrue)

があり、後者はデバイスが「なし→あり」のときはtrueになりますが「あり→なし」のときはtrueにならないようです。
しかし、csudの実装ではPort.ConnectDetectedのレジスタ値を「ポートの接続状況に変化があった」フラグとして用いているため、デバイスの取り外しが検出できていませんでした。

このあたり、ultiboのフォーラムの以下のやりとりが参考になりました。

usb keyboards not recognized on "Raspberry PI A+" – ultibo.org

この議論に対応する、ultiboのUSBドライバのパッチは以下のコミットと思われます。

Fixes for Raspberry Pi A/A+/Zero USB handling · ultibohub/Core@ba3c908

csudとはだいぶ構成が違うライブラリなので、csudへそのまま適用するのは無理そうですが、コメントを読むだけでもヒントになりそうです。

csudでの上記の不具合の解決方法ですが、HubPortGetStatusを呼ぶ前と呼んだ後とでPort.Connectの値の変化をチェックするようにしました。
パッチを当てたcsudは以下のリポジトリで公開しています。

boochow/csud: Chadderz's Simple USB Driver for Raspberry Pi

なお、時間がたつとハングアップする問題は、Pollループに少しウエイトを入れるようにしたら起こらなくなったので、デバイスへの過負荷が原因だったのかもしれません。

これで、Pi Zero WにUSBキーボードを直結しても問題なく動作するようになったと思われます。

コメント