ベスト プラクティス:URB の使用

このトピックでは、クライアント ドライバーのベスト プラクティスについて説明します。URB を割り当て、構築し、WINDOWS 8 に含まれている USB ドライバー スタックに送信します。

Windows 8ユニバーサル シリアル バス (USB) 3.0 デバイスをサポートする新しい USB ドライバー スタックが含まれています。 新しい USB 3.0 ドライバー スタックには、USB 3.0 仕様に基くいくつかの新機能が実装されています。 さらに、ドライバー スタックには、クライアント ドライバーが一般的なタスクを効率的に実行できるその他の機能が含まれています。 たとえば、新しいドライバー スタックはチェーン MDL を受け入れ、クライアント ドライバーが物理メモリ内の不一体のページで転送バッファーを送信できます。

クライアント ドライバーが Windows 8 の USB ドライバー スタックの新機能を使用するには、その前に、Windows によってデバイスに読み込まれる基になる USB ドライバー スタックにドライバー自体を登録する必要があります。 クライアント ドライバーを登録するには、 を呼び出 USBD_CreateHandle コントラクト のバージョンを 指定します。 クライアント ドライバーが Windows 8 の機能強化と新機能をビルド、実行、使用することを目的としている場合、クライアント コントラクトのバージョンはUSBD_CLIENT_CONTRACT_VERSION_602。

新しいUSBD_CLIENT_CONTRACT_VERSION_602クライアント ドライバーの場合、USB ドライバー スタックでは、クライアント ドライバーが次の一連の規則に準拠している必要があります。

USB ドライバー スタックは、受信した要求に対して検証を実行し、可能な限り違反を処理します。 そうしない場合、未定義の動作が発生する可能性があります。

古いパイプ ハンドルまたは無効なパイプ ハンドルを使用して I/O 要求を送信しない

クライアント ドライバーは、 古い パイプ ハンドルを使用して、USB ドライバー スタックに I/O 要求を送信することはできません。 古 いパイプ ハンドルは、デバイスで選択されなくなった構成、インターフェイス、または代替設定を選択する要求で取得されたパイプ ハンドルを指します。 古いパイプ ハンドルを回避するには、クライアント ドライバーが構成またはインターフェイスを選択するたび、ドライバーはパイプ ハンドルのキャッシュを更新する必要があります (通常はデバイス コンテキストに格納されます)。 一部の競争状態では、古いパイプ ハンドルが発生する可能性があります。 たとえば、クライアント ドライバーは、選択したインターフェイスのパイプ ハンドルを使用して I/O 要求を送信します。 要求が完了する前に、クライアント ドライバーは、使用されているパイプ ハンドルに関連付けられている同じエンドポイントを使用しない代替設定を選択します。 これらの保留中の要求はどちらも、パイプ ハンドルを無効にし、競争状態を引き起こす可能性があります。

の割り当てルーチンを呼び出して URB を割り当Windows 8

Windows 8 USB 要求ブロック (URB) の割り当て、構築、および解放のための新しいルーチンが提供されます。 URB を割り当てるには、Windows Driver Model (WDM) クライアント ドライバーで、次の一覧に示す新しいルーチンを常に使用する必要があります。

前の一覧のルーチンは、追跡と処理を改善するために、割り当てられた URB に不透明な URB コンテキストをアタッチする場合があります。 クライアント ドライバーは、URB コンテキストの内容を表示または変更できません。 の URB 割り当ての詳細については、「Windows 8と構築」を参照してください

登録時にバージョンを USBD_CLIENT_CONTRACT_VERSION_602 として識別する Windows Driver Framework (WDF) クライアント ドライバー (「WdfUsbTargetDeviceCreateWithParameters」を参照) の場合、USB ドライバー スタックでは、新しい WdfUsbTargetDeviceCreateUrb を呼び出すことによって、クライアント ドライバーが URB のメモリを割り当てる必要があります。

保留中の要求に関連付けられているアクティブな URB を再利用しない

USB ドライバー スタックは、URB に関連付けられた要求の前に再送信されたアクティブな URB が検出されると、意図的にバグチェックを行います。 URB は、要求が保留中で、クライアント ドライバーの IRP 完了ルーチンが呼び出されていない限りアクティブです。 アクティブな URB で次のタスクを実行しない。

  • の要求 に対してアクティブな URB を再送信しないでください (URB を別の IRP に関連付けます)。
  • アクティブ URB の内容を変更しない。
  • アクティブ URB を解放しない。

クライアント ドライバーの完了ルーチンが呼び出された後、ドライバーは完了ルーチン内の特定の種類の要求に対して URB を再送信できます。 再送信には、次の規則が適用されます。

  • クライアント ドライバーは、USBD_SelectConfigUrbAllocateAndBuild によって割り当てられた URB を、同じ構成を選択する select-configuration 要求以外の種類の要求に再利用しないでください。

  • クライアント ドライバーは、 USBD_SelectInterfaceUrbAllocateAndBuild によって割り当てられた URB を、インターフェイスで同じ代替設定を選択する select-interface 要求以外の任意の種類の要求に再利用しないでください。 例については、次のページの「解説」 をUSBD_SelectInterfaceUrbAllocateAndBuild

  • 要求によって割り当てられた URB USBD_IsochUrbAllocate 、同一時転送要求に対してだけ再利用する必要があります。 逆に、他の種類の I/O 要求 (制御、一括、または割り込み) に割り当てられた URB は、同種の要求には使用できません。

    たとえば、クライアント ドライバーは、一括転送要求の URB 構造を割り当て、構築します。 また、クライアント ドライバーは、デバイス内の同一時エンドポイントにデータを送信する必要があります。 一括転送要求が完了した後、クライアント ドライバーは、ISOCHRONOUS 要求の URB を再フォーマットして送信する必要があります。 これは、isochronous 要求に関連付けられた URB は、パケットの数に応じて可変長を持つためです。 さらに、パケットはフレーム境界で開始および終了するために必要です。 割り当てられた URB (一括転送の場合) が、同一時転送に必要なバッファー レイアウトに適合しない可能性があります。また、要求が失敗する可能性があります。

  • USBD_UrbAllocate によって割り当てられた URB は、同一性、選択構成、または選択インターフェイス要求に対して再利用する必要があります。 URB を再利用して NULL 構成を選択し、デバイスで選択した構成を無効にできます。 URB をアクティブにすることはできません。また、クライアント ドライバーは 、UsbBuildSelectConfigurationRequest マクロを呼び出し、 ConfigurationDescriptor パラメーターで NULL を渡すことによって URB を再フォーマットする必要があります。

  • URB を再送信する前に、クライアント ドライバーは、要求の種類に定義されている適切な UsbBuildXxx マクロを使用して URB を再フォーマットする必要があります。 USB スタックによってその内容の一部が変更された可能性があるため、ドライバーで URB をフォーマットすることが重要です。

    たとえば、ドライバーが UsbBuildInterruptOrBulkTransferRequest を呼び出して、一括転送要求の URB を初期化するとします (「_URB_BULK_OR_INTERRUPT_TRANSFER」 を参照)。 ドライバーが URB 構造体の TransferBufferMDL メンバーを NULL に初期化する場合、USB ドライバー スタックは、転送バッファー (指定された TransferBuffer) を 使用して、MDL ではなくデバイスとデータを交換します。 ただし、内部的には、USB ドライバー スタックによって MDL が作成され、 TransferBufferMDL に MDL へのポインターが格納され、MDL を使用してスタックにデータが渡される場合があります。 USB ドライバー スタックは MDL メモリを解放しますが、クライアント ドライバーが完了ルーチンで URB を処理している場合、 TransferBufferMDL が NULL ではない可能性があります。 URB のメンバーが正しく書式設定されていることを確認するには、ドライバーが UsbBuildInterruptOrBulkTransferRequest を再度呼び出して、要求を送信する前に URB を再フォーマットする必要があります。

高速転送と SuperSpeed 等時性転送に 8 を超えるポーリング期間を使用しない

USB ドライバー スタックは、ポーリング期間番号が 1、2、4、または 8 の高速および SuperSpeed 等時性パイプをサポートします。 クライアント ドライバーは、期間が 8 を超えるエンドポイントに IO を送信できません。 そうすると、バグチェックが発生する可能性があります。

フレームあたりのパケット数の倍数である同一時パケットの数を確認します

高速転送と SuperSpeed 等時性転送の場合、フレームあたりの等時性パケットの数は 8 / ポーリング期間として計算されます。 クライアント ドライバーは、URB で指定された NumberOfPackets 値 ( _URB_ISOCH_TRANSFER を参照) がフレームあたりのパケット数の倍数である必要があります。

USB ドライバー スタックは、 NumberOfPackets がフレームあたりのパケット数の倍数ではない、同一時転送 URB をサポートしません。

ドキュメント化された IRQL レベルでルーチンを呼び出す

クライアント ドライバーをコントラクト バージョンとして USBD_CLIENT_CONTRACT_VERSION_602 に登録した場合、USB ドライバー スタックは、クライアント ドライバーが適切な IRQL レベルで要求を送信したと見なします。 クライアント ドライバーがクライアント 側で要求を送信DISPATCH_LEVEL場合は、クライアント ドライバーで送信PASSIVE_LEVEL。 要求を受信すると、USB ドライバー スタックによって IRQL 値が検証され、要求が失敗することがあります。 ただし、それ以外の場合は、USB ドライバー スタックによってバグチェックが生成される場合があります。

USB デバイスへの要求の送信