[Blog翻訳] USB デバイスの Container ID の生成方法 (その 2)

みなさん、こんにちは。Windows 開発統括部の古内です。今週は USB 特集ということで、昨日お約束したように、トリを飾るのは 2 月 22 日に Microsoft Windows USB Core Team Blog に投稿された 「How to Generate a Container ID for a USB Device - Part 2」 の翻訳です。


USB デバイスの Container ID の生成方法 (その 2)

こんにちは。USB チームでプログラム マネージャーを務める Kristina Hotz です。 昨年の 12 月に 「How to Generate a Container ID for a USB Device」 (日本語翻訳版はこちら) というブログ記事を書きましたが、デバイス開発者の方々が次に知りたいのは、いつ、どのような方法で Container ID を指定すれば Windows でデバイスが正しく列挙されるようになるのかという点ではないかと思うので、この記事ではその点についてご説明します。

ではまず、簡単なおさらいから始めましょう。

Container ID とは、USB バス ドライバーが Windows に対して指定する識別文字列のことです。 バス ドライバーは通常、この ID をデバイスから取得します。Container ID は物理デバイスに対して一意に割り当てられ、他のデバイスが同じ ID を持つことはありません。複合デバイス (プリンター/スキャナー/FAX のマルチファンクション デバイスなど) の場合、各機能の devnode は同じ物理デバイスに属しているため、すべての devnode の Container ID は同一です。

マイクロソフトが提供する USB ドライバー スタックでは、次の方法で Container ID を取得します。
    -     Microsoft OS の ContainerID ディスクリプターからデバイスの Container ID を読み込む
    -     特定のデバイス情報からハッシュを作成し、Container ID を生成する
    -     ランダムな GUID を生成する
    -     親 devnode の Container ID を継承する

詳細な割り当てプロセスの概要については、「USB デバイスへの Container ID の割り当て方法 (英語)」のフローチャートを参照してください。

Container ID を指定すべき状況とは

デバイスがコンピューター内に統合されていない場合 (外付けデバイスなど)、Container ID を指定するには、Microsoft OS ディスクリプター の ContainerID を利用するのが最も良い方法です。 これは、マルチ転送デバイスを作成する場合には特に重要になります。 たとえば、対象のデバイスが Wi-Fi と USB を介して接続する場合、デバイスが単一のマシンであることを Windows が認識できるよう、どちらの転送方法でもデバイスから同じ Container ID が報告される必要があります。 このとき同じ Container ID が報告されないと、デバイス列挙の際、Windows は 2 つの異なる Container ID を生成します (USB 用と Wi-Fi 用に 1 つずつ)。 その結果、対象の物理デバイスが [デバイスとプリンター] に 2 つのデバイスとして表示されることになります。

USB のみを介して接続するデバイスを作成する場合にも Container ID を指定されることを推奨しますが、必須ではありません。Container ID を指定しない場合、USB バス ドライバーがデバイスの Container ID を生成します。 複合デバイスでは、その単一の Container ID が、Windows によってデバイスのすべての機能に対して使用されます。 コンパウンド デバイス (ハブを内蔵しているデバイス) の場合は、ハブ ディスクリプター内でリムーバブル ビットが正しく設定されている限り、Windows はそのコンパウンド デバイスを単一のデバイスと見なし、すべてのコンポーネントに対して同じ ID を使用します。 [デバイスとプリンター] では、Container ID を使用して情報を集約し、デバイス (単一、複合、またはコンパウンド) を単一のデバイス アイコンとして表示します。

デバイスが接続されるポートのスピードによって、1 台のデバイスが複数として列挙される場合があります。 この場合も、Windows がデバイスを認識するうえで、Container ID がいかに重要な役割を果たすかを理解しておく必要があります。

たとえば、USB 2.0 ポート用のドライバー セットと、USB 3.0 ポート用のドライバー セットを必要とするデバイスを開発するとします。 上記のシナリオをサポートするため、このデバイスは各速度のポートに対して別々の VID/PID を提供しますが、Container ID は指定しません。その場合、ユーザーがデバイスを USB 2.0 ポートにつないだ後で、プラグを USB 3.0 ポートに移動させると、Windows は対象のデバイスを 2 つの独立したデバイスとして認識します。 このとき Windows は、たとえポートのシリアル番号が同じであっても、対象のデバイスを速度の異なるポートごとに初めて列挙するデバイスとして扱います。

この状態を防ぐには、デバイスが Container ID を指定する必要があります。

Container ID を使用すれば、Windows はそのデバイスが既に列挙されていることを判断できます。これにより、Windows では、高解像度アイコンの再ダウンロードなどの不要な処理を行う必要がなくなります。

デバイスの Container ID の指定方法

Container ID は、GUID にする必要があります。 GUID を生成するためのツールは無数に存在します。 マイクロソフトでよく使用するのは、guidgen.exe です。

Container ID はシリアル番号以上に一意性が高いといえます。シリアル番号の場合は、ベンダー ID と製品 ID が同じ他のデバイスに対してのみ、一意性が求められます。一方 Container ID では、それぞれのデバイスにおいて "ユニバーサルな一意性" が必要になります。 2 つのデバイスから同じ Container ID が報告されると、Windows はそれらを単一のデバイスとして表示します。 フラッシュ ドライブが 2 台接続されているにもかかわらず、[デバイスとプリンター] にアイコンが 1 つしか表示されないとしたら、非常に困惑します。

Container ID の報告には、Microsoft OS ディスクリプターContainerID ディスクリプターを使用します。USB 3.0 では、別のメカニズムとして、Binary Device Object Store (BOS) ディスクリプターを使用して Container ID を報告することも可能です。 両方のメカニズムを使用する場合は、両メカニズムが同じ Container ID を報告していることを確認してください。

Windows 7 では、USB 3.0 が標準でサポートされません。 サードパーティに所属する USB ドライバー スタックの開発者の方々は、USB 3.0 BOS ディスクリプターと Microsoft OS ディスクリプターの Container ID を確認してください。 2 つの ID は完全に一致するはずですが、万一異なる場合は、スタックが Microsoft OS ディスクリプターから Container ID を取得するように設定することをお勧めします。

参考資料

多機能デバイス サポートとデバイス コンテナーのグループ化

Container IDs for USB Devices (英語)

Microsoft OS ディスクリプター