URB の割り当てと構築
USB クライアント ドライバーは、Windows ドライバー モデル (WDM) ドライバー ルーチンを使用して、マイクロソフトが提供する USB ドライバー スタックに要求を送信する前に、URB を割り当てて書式設定できます。
クライアント ドライバーは URB を使用して、要求を処理するために USB ドライバー スタックの下位ドライバーに必要なすべての情報をパッケージ化します。 Windows オペレーティング システムでは、URB は URB 構造で記述されます。
マイクロソフトは、 USB クライアント ドライバーのルーチンのライブラリを提供しています。 これらのルーチンを使用することにより、USB クライアント ドライバーは、特定の指定された操作に対する URB 要求を構築し、USB スタックに転送できます。 必要に応じて、独自の URB リクエストを作成するのではなく、サポートされている操作のライブラリ ルーチンを呼び出すようにクライアント ドライバーを設計できます。
Windows 7 以前の URB 割り当て
Windows 7 以前のバージョンの Windows Driver Kit (WDK) に含まれるルーチンを使用して USB 要求を送信するには、通常、クライアント ドライバーは URB 構造体を割り当てて塗りつぶし、 URB 構造体を新しい IRP に関連付け、IRP を USB ドライバー スタックに送信します。
特定の種類の要求に対して、マイクロソフトは URB 構造体を割り当てて書式設定するヘルパー ルーチン (Usbd.sys によってエクスポート) を提供しています。 たとえば、 USBD_CreateConfigurationRequestEx ルーチンは URB 構造体のメモリを割り当て、選択構成要求の URB を書式設定し、 URB 構造体のアドレスをクライアント ドライバーに返します。 ただし、ヘルパー ルーチンをすべての種類の要求に使用することはできません。
また、一部の種類の要求の URL を書式設定するマクロも用意されています。 これらのマクロの場合、クライアント ドライバーは 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 で定義されています。
- USBD_UrbAllocate
- USBD_IsochUrbAllocate
- (USBD_SelectConfigUrbAllocateAndBuild)
- (USBD_SelectInterfaceUrbAllocateAndBuild)
- USBD_UrbFree
- USBD_AssignUrbToIoStackLocation
前の一覧の割り当てルーチンは、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 ドライバー スタックは、URB とそれに関連付けられた URB コンテキストを非ページ プールに割り当てるため、将来的により大きな URB コンテキストが必要になった場合に必要な調整は、プール割り当てのサイズだけになります。
URB ルーチンの移行
次の表は、URB ルーチンの変更をまとめたものです。
ユース ケース | WDK for Windows 7 以前で使用可能 | WDK は Windows 8 以降で利用可能 |
---|---|---|
Windows 7 以前のバージョンのオペレーティング システムが対象 | Windows 8 以降のバージョンのオペレーティング システムが対象 | |
URB を作成するには... | クライアント ドライバーは URB 構造体を割り当て、要求に応じて構造体を書式設定します。 クライアント ドライバーは、スタック上の URB 構造体を割り当てるか、 ExAllocatePoolWithTagを呼び出すことによって、ページ以外のプール内の構造体を割り当てます。 |
クライアント ドライバーは USBD_UrbAllocate を呼び出し、USB ドライバー スタックによって割り当てられる新しい URB 構造体へのポインターを受け取ります。 基になる USB ドライバー スタックの USBD インターフェイス バージョンに応じて、URB が URB コンテキストに関連付けられる場合があります。 |
選択構成要求の URB を作成するには... | クライアント ドライバーは、USB ドライバー スタックによって作成および書式設定された新しい URB へのポインターを返す USBD_CreateConfigurationRequestEx ルーチンを呼び出します。 | クライアント ドライバーは USBD_SelectConfigUrbAllocateAndBuild を呼び出し、新しい URB 構造体へのポインターを受け取ります。これは、USB ドライバー スタックによって割り当てられ、(select-configuration 要求用に) 書式設定されます。 基になる USB ドライバー スタックの USBD インターフェイス バージョンに応じて、URB が URB コンテキストに関連付けられる場合があります。 |
選択インターフェイス要求の URB を作成するには... | クライアント ドライバーは URB 構造体を割り当て、 _URB_SELECT_INTERFACE 構造体を使用して、USB デバイスのインターフェイス選択コマンドの形式を定義します。 | クライアント ドライバーは USBD_SelectInterfaceUrbAllocateAndBuild を呼び出し、新しい URB 構造体へのポインターを受け取ります。これは、USB ドライバー スタックによって割り当てられ、(select-interface 要求用に) 書式設定されます。 基になる USB ドライバー スタックの USBD インターフェイス バージョンに応じて、URB が URB コンテキストに関連付けられる場合があります。 |
URB を IRP に関連付けるには... | クライアント ドライバーは、 IoGetNextIrpStackLocationを呼び出すことによって、次の IRP スタックの場所へのポインターを取得します。 次に、クライアント ドライバーは、スタックの場所の Parameters.Others.Argument1 メンバーを URB 構造体のアドレスに手動で設定します。 | クライアント ドライバーは、 IoGetNextIrpStackLocation を呼び出すことによって、次の IRP スタックの場所へのポインターを取得します。 次に、クライアント ドライバーは USBD_AssignUrbToIoStackLocation を呼び出して、URB をスタックの場所に関連付けます。 |
URB を解放するには... | クライアント ドライバーがスタックに URB を割り当てると、要求が完了した後、変数はスコープ外になります。 クライアント ドライバーまたは USB ドライバー スタックが非ページ プールに割り当てられている URB 構造体を解放するために、クライアント ドライバーは ExFreePool を呼び出します。 |
クライアント ドライバーは USBD_UrbFree を呼び出します。 |