PIC32MX220F032B USB MIDI ホスト (11)

USB ハブの最も重要な機能は、ホストに接続できる USB デバイスの数を増やすことです。
その意味では、USB ハブには 2 ポート以上が必要で、ホスト側のソフトウェアとしては、2 個以上の USB デバイスと USB ハブ自体との合計 3 個以上の USB デバイスを管理できる能力が求められます。
Microchip 社の USB ホスト・スタックでは、同時に扱える USB デバイスの数はひとつに限られています。
これを 3 個以上の USB デバイスを扱えるように改造するのは大掛かりになります。
USB ハブに対する対応を、「接続できるデバイス数を増やす」のではなく、「ハブ経由のひとつのデバイスだけを扱えるようにする」ことに限れば、扱うべきデバイス数は 2 (対象の USB デバイスと USB ハブ) となります。
前回の記事で述べたように、ハブ経由でのデバイスの接続は、初期状態ではホストからはハブしか見えず、対象の USB デバイスは全く見えません。
ハブに対して設定を行い、ポートに接続した USB デバイスがホストから見えるようになった後、

  • ポートの状態を変化させない
  • USB デバイスの抜き差しによる (外部的な) ポート状態の変化を検出しない

ことを条件とすれば、それ以降はハブに対して何の操作も必要なくなります。
「リピータ・ハブ」としての機能については、何の設定も必要せず、自動的に動作します。
コンパウンド・デバイス (compound device)、つまり、ハブが一体化されていて、そのポートに USB デバイスが接続されている機器 (KORG microKEY-37 など) では、ハブと USB デバイスの接続は固定されているので、それが変化することはなく、上の条件に当てはまります。
ひとつのデバイスしか扱えない Microchip 社のホスト・スタックでも、「2 階に上げてハシゴを外す」方式を使えば、事実上ふたつのデバイスに対する操作を実現できます。
つまり、まず、USB ハブを普通のデバイスとして「クラス・ドライバ」で扱い、必要な設定を行います。 「fake_hub.c」がその (いんちき) ハブ・クラス・ドライバです。
設定が完了すれば、まだエニュメレーションされてない目的の USB デバイスがデフォルト・アドレスの「0」でホストから見えるようになります。
その状態になれば、以降はハブに対する操作は必要なくなるので、それまでハブに対してエニュメレーションしてきた結果のデータをすべて「ご破算」にして、ハブのポートから覗いているデフォルト・アドレス「0」の USB デバイスの「デバイスディスクリプタ読み込み」からエニュメレーションを再スタートさせます。
ここで、エニュメレーションを本来のスタートの「デタッチ・ステート」まで戻すと、USB ハードウェア上での「切り離し」が行われて、ハブのエニュメレーションからやり直すことになってしまい、無限ループになってしまいます。
問題は、そんなに都合よく「途中」から再スタートできるのかどうかです。
ホスト・スタックでは、ディスクリプタなどの読み込みでバッファが必要になると、ヒープからメモリを切り出して使用しています。
切り出したヒープを完全に元に戻した場合にうまく行く設定を見つけられていないので、現状では、妥協して一部のメモリを残したままで再スタートを行っています。
そのため、ハブの着脱を繰り返すとヒープが足りなくなって動作しなくなる可能性があります。
エニュメレーションの途中からの再スタートのためには、ホスト・ドライバの内部変数をいじる必要があり、「usb_host.c」ファイルに (ライブラリのフォルダからプロジェクトのフォルダにコピーした上で) 変更を加えています。
まず、もともとホスト・スタックでは USB ハブをサポートしていないので、デフォルトでは、エニュメレーションの途中でハブであることが判明すると、強制的に「ホールド」ステートに移行します。
この状態では、ハブをデタッチする以外には状態が変化せず、クライアント・ドライバや、アプリケーションではどうすることもできません。
幸い、「USB_HUB_SUPPORT_INCLUDED」というシンボルを定義すると、ハブを普通のデバイスとして扱ってくれます。
これについては「usb_host.c」ファイルをいじる必要はありません。
「HardwareProfile_32MX220F032B.h」ファイルの中で上記にシンボルを定義しています。
Microchip 社のホスト・ドライバでは、ひとつのデバイスしか扱えないので、エニュメレーションの過程で「SET_ADDRESS」するデバイス・アドレスは「1」に決め打ちになっています。
これでは、ハブと、目的の USB デバイスとが同じアドレス「1」になってしまいますから、「usb_host.c」をいじって、ハブの場合には、アドレス「127」(から順次デクリメントした値) を割り当てています。
ハブを多段に接続した場合には、ホストに近い側から順に 127、126、... というアドレスが割り当てられます。
有効にするポート番号については、プログラム中に「マジック・ナンバー」として埋め込むのを避け、「usb_config.c」ファイル中の CDT (Client Driver Table) の「flags」エントリの値を参照するようにしています。
KORG microKEY-37 の場合にはポート 4 にデバイスがぶら下がっているので、「4」を指定しています。
これは TPL (Targeted Peripheral List) に登録してあるハブ・クラスのドライバ呼び出しで共通に使われるので、多段接続されたハブの全てで同じ番号のポートがイネーブルされます。
個々のハブで違う番号のポートを有効にしたい場合には、 TPL にその VID/PID 指定のエントリを設け、CDT にも違うポート番号のエントリを設ければ実現できます。