URB の割り当てと構築

USB クライアント ドライバーは、Windows ドライバー モデル (WDM) ドライバー ルーチンを使用して、Microsoft 提供の USB ドライバー スタックに要求を送信する前に URB を割り当てて書式設定できます。

クライアント ドライバーは、URB を使用して、USB ドライバー スタックの下位ドライバーが要求を処理するために必要なすべての情報をパッケージ化します。 Windows オペレーティング システムでは、URB は URB 構造で記述されています。

Microsoft では、 USB クライアント ドライバー用のルーチンのライブラリを提供しています。 USB クライアント ドライバーは、これらのルーチンを使用して、特定の指定された操作の URB 要求をビルドし、USB スタックに転送できます。 必要に応じて、独自の URB 要求を構築するのではなく、サポートされている操作のライブラリ ルーチンを呼び出すようにクライアント ドライバーを設計できます。

Windows 7 以前の URB 割り当て

Windows 7 以前のバージョンの Windows 用 Windows Driver Kit (WDK) に含まれるルーチンを使用して USB 要求を送信するには、通常、クライアント ドライバーが URB 構造体を割り当てて入力し、 URB 構造体を新しい IRP に関連付け、IRP を USB ドライバー スタックに送信します。

特定の種類の要求に対して、Microsoft は URB 構造体を割り当てて書式設定するヘルパー ルーチン (Usbd.sysによってエクスポート) を提供します。 たとえば、 USBD_CreateConfigurationRequestEx ルーチンは URB 構造体のメモリを割り当て、選択構成要求の URB を書式設定し、 URB 構造体のアドレスをクライアント ドライバーに返します。 ただし、ヘルパー ルーチンをすべての種類の要求に使用することはできません。

また、一部の種類の要求の URB を書式設定するマクロも用意されています。 これらのマクロの場合、クライアント ドライバーは ExAllocatePoolWithTag を呼び出して URB 構造体を割り当てるか、スタックに構造体を割り当てる必要があります。 たとえば、クライアント ドライバーが URB を割り当てた後、ドライバーは UsbBuildSelectConfigurationRequest を呼び出して、選択構成要求の URB を書式設定したり、構成をクリアしたりできます。

その他の要求の場合、クライアント ドライバーは、要求の種類に応じて URB 構造体のさまざまなメンバーを設定することによって、 URB を手動で割り当てて書式設定する必要があります。

USB 要求が完了したら、クライアント ドライバーは URB 構造体を解放する必要があります。 URB がスタックに割り当てられている場合、URB はスコープ外になったときに解放されます。 URB が非ページ プールに割り当てられている場合、クライアント ドライバーは ExFreePool を呼び出して URB を解放する必要があります。

Windows 8での URB 割り当て

WDK for Windows 8には、割り当て、書式設定、および URB の解放のためのルーチンをエクスポートする新しい静的ライブラリ Usbdex.lib が用意されています。 さらに、URB を IRP に関連付ける新しい方法もあります。 新しいルーチンは、Windows Vista 以降のバージョンの Windows を対象とするクライアント ドライバーによって呼び出すことができます。

Windows Vista 以降で実行されているクライアント ドライバーは、基になる USB ドライバー スタックが特定のパフォーマンスと信頼性の向上を利用できるように、新しいルーチンを使用する必要があります。 これらの機能強化は、USB 3.0 デバイスとホスト コントローラーをサポートするために、Windows 8で導入された新しい USB ドライバー スタックに適用されます。 USB 2.0 ホスト コントローラーの場合、Windows は、機能強化をサポートしていない以前のバージョンのドライバー スタックを読み込みます。 基になるドライバー スタックのバージョン、またはホスト コントローラーでサポートされているプロトコルのバージョンに関係なく、常に新しい URB ルーチンを呼び出す必要があります。

新しいルーチンを呼び出す前に、USB ドライバー スタックを使用してクライアント ドライバーを登録するための USBD ハンドルがあることを確認します。 USBD ハンドルを取得するには、 USBD_CreateHandleを呼び出します。

WDK for Windows 8では、次のルーチンを使用できます。 これらのルーチンは Usbdlib.h で定義されています。

前の一覧の割り当てルーチンは、USB ドライバー スタックによって割り当てられる新しい URB 構造体へのポインターを返します。 Windows によって読み込まれた USB ドライバー スタックのバージョンに応じて、 URB 構造体を不透明な URB コンテキストとペアにすることができます。 URB コンテキストは、URB に関する情報のブロックです。 URB ヘッダーの内容を表示することはできません。この情報は、URB の追跡と処理を改善するために、USB ドライバー スタックによって内部的に使用されることを意図しています。 URB コンテキストは、WINDOWS 8の USB ドライバー スタックでのみ使用されます。 URB コンテキストが使用可能な場合、USB ドライバー スタックはそれを使用して URB 処理をより安全かつ効率的にします。 たとえば、USB ドライバー スタックでは、クライアント ドライバーが URB を送信しないことを確認し、最初の要求が完了する前に同じ URB を再利用する必要があります。 この種のエラーを検出するために、USB ドライバー スタックは URB コンテキストに状態情報を格納します。 状態情報がない場合、USB ドライバー スタックでは、受信 URB と現在進行中のすべての URB を比較する必要があります。 状態情報は、クライアント ドライバーが URB を解放しようとしたときに、USB ドライバー スタックによっても使用されます。 URB を解放する前に、USB ドライバー スタックによって状態が検証され、URB が保留中でないことを確認します。

URB コンテキストは、追加の URB 情報を格納するための公式のメカニズムを提供します。 URB コンテキストを使用することは、必要に応じて余分なメモリを割り当てるか、 URB 構造体の予約メンバーに追加情報を格納する場合に推奨されます。 USB ドライバー スタックは、URL とそれに関連付けられている URB コンテキストを非ページ プールに割り当てます。そのため、将来、より大きな URB コンテキストが必要な場合、必要な調整はプール割り当てのサイズのみです。

URB ルーチンの移行

次の表は、URB ルーチンの変更をまとめたものです。

使用事例 WDK for Windows 7 以前で使用可能 WINDOWS 8 以降の WDK で使用できます
  Windows 7 以前のバージョンのオペレーティング システムを対象とする オペレーティング システムWindows 8以降のバージョンを対象とする
URB を作成するには... クライアント ドライバーは URB 構造体を割り当て、要求に応じて構造体を書式設定します。

クライアント ドライバーは、スタックに URB 構造体を割り当てます。または、 ExAllocatePoolWithTag を呼び出して、非ページ プールに構造体を割り当てます。
クライアント ドライバーは USBD_UrbAllocate を呼び出し、USB ドライバー スタックによって割り当てられる新しい URB 構造体へのポインターを受け取ります。 基になる USB ドライバー スタックの USBD インターフェイスバージョンによっては、URB が URB コンテキストに関連付けられている場合があります。
select-configuration 要求の URB を作成するには... クライアント ドライバーは、USB ドライバー スタックによって作成および書式設定された新しい URB へのポインターを返す USBD_CreateConfigurationRequestEx ルーチンを呼び出します。 クライアント ドライバーは 、USBD_SelectConfigUrbAllocateAndBuild を呼び出し、USB ドライバー スタックによって (選択構成要求用に) 割り当てられ、書式設定された新しい URB 構造体へのポインターを受け取ります。 基になる USB ドライバー スタックの USBD インターフェイスバージョンによっては、URB が URB コンテキストに関連付けられている場合があります。
select-interface 要求の URB を作成するには... クライアント ドライバーは URB 構造体を割り当て、 usb デバイスの選択インターフェイス コマンドの形式を定義する_URB_SELECT_INTERFACE構造体を使用します。 クライアント ドライバーは 、USBD_SelectInterfaceUrbAllocateAndBuild を呼び出し、USB ドライバー スタックによって (選択インターフェイス要求用に) 割り当てられ、書式設定された新しい URB 構造体へのポインターを受け取ります。 基になる USB ドライバー スタックの USBD インターフェイスバージョンによっては、URB が URB コンテキストに関連付けられている場合があります。
URB を IRP に関連付けるには... クライアント ドライバーは、 IoGetNextIrpStackLocation を呼び出すことによって、次の IRP スタックの場所へのポインターを取得します。 次に、クライアント ドライバーは、スタックの場所の Parameters.Others.Argument1 メンバーを URB 構造体のアドレスに手動で設定します。 クライアント ドライバーは、 IoGetNextIrpStackLocation を呼び出すことによって、次の IRP スタックの場所へのポインターを取得します。 次に、クライアント ドライバーは USBD_AssignUrbToIoStackLocation を呼び出して、URB をスタックの場所に関連付けます。
URB をリリースするには... クライアント ドライバーがスタックに URB を割り当てると、要求が完了した後、変数はスコープ外になります。

クライアント ドライバーまたは USB ドライバー スタックが非ページ プールに割り当てられた URB 構造体を解放するために、クライアント ドライバーは ExFreePool を呼び出します。
クライアント ドライバーは 、USBD_UrbFreeを呼び出します。