チェーンされた MDL 構造体を送信する方法
この記事では、USB ドライバー スタックのチェーンされた MDL 機能と、クライアント ドライバーが転送バッファーを MDL 構造体のチェーンとして送信する方法について説明します。
ほとんどの USB ホスト コントローラーでは、転送バッファーが実質的に連続している必要があります。 仮想的に連続しているとは、バッファーはページ内のどこでも開始および終了できますが、バッファーの残りの部分はページ境界で開始および終了する必要があることを意味します。 多くの USB クライアント ドライバーは、その要件を満たすことができます。 ただし、特定のクライアント ドライバー、特にバッファーにデータを追加またはバッファーから追加データを削除する必要があるクライアント ドライバーの場合、転送バッファーに仮想的に連続したメモリを割り当てることは好ましくありません。
たとえば、ネットワーク プロトコル ドライバー、中間ドライバー、およびミニポート ドライバーの 3 つのドライバーからなるネットワーク スタックについて考えてみましょう。 プロトコル ドライバーは転送を開始し、スタック内の次のドライバー (中間ドライバー) にパケットを送信します。 中間ドライバーは、(個別のメモリ ブロックに含まれている) カスタム ヘッダーをパケットに追加する必要があります。 中間ドライバーは、そのヘッダーと受信したパケットをスタック内の次のドライバー、つまりミニポート ドライバーに送信します。 ミニポート ドライバーは USB ドライバー スタックとインターフェイスするため、仮想的に連続した転送バッファーを準備する必要があります。 このようなバッファーを作成するには、ミニポート ドライバーは、大きなバッファーを割り当て、カスタム ヘッダーを追加し、ペイロードをコピーします。 通常ペイロードは大きいため、ペイロード全体をコピーするとパフォーマンスに大きな影響を与える可能性があります。
クライアント ドライバーは、メモリ記述子リスト (MDL) のチェーンとして転送バッファーを送信することで、そのパフォーマンスへの影響を克服できます。 Windows 8 の新しい USB ドライバー スタックは、クライアント ドライバーからチェーンされた MDL (MDL を参照) を受け入れることが可能です。 チェーンされた MDL を提供することにより、クライアント ドライバーは無関係なコピー操作を実行する代わりに、メモリ内の不連続なページを参照できます。 この機能により、バッファの数、サイズ、および配置に関する制限がなくなり、転送バッファを物理メモリ内でセグメント化できるようになります。
チェーンされた MDL を使用するには、クライアント ドライバーは、Windows によって読み込まれた基になる USB ドライバー スタックがその機能をサポートしているかどうかを検出し、適切な順序で MDL のチェーンを構築する必要があります。
開始する前に
チェーンされた MDL 機能は、一括転送、等時転送、割り込み転送でのみサポートされます。 チェーンされた MDL 機能を照会する前に、クライアント ドライバーに USB ドライバー スタックへのドライバーの登録用の USBD ハンドルがあることを確認します。 USBD ハンドルを作成するには、USBD_CreateHandle を呼び出します。通常、クライアント ドライバーは、その AddDevice ルーチンで USBD ハンドルを作成します。
クライアント ドライバーの IRP_MN_START_DEVICE ハンドラーで、または後でいつでも、チェーンされた MDL 機能のクエリを実行できます。 クライアント ドライバーは、その AddDevice ルーチンでこの機能のクエリを実行することはできません。
手順
USBD_QueryUsbCapability ルーチンを呼び出して、USB ドライバー スタックがチェーンされた MDL 機能をサポートしているかどうかを判断します。 その機能を照会するには、GUID として UsbCapabilityChainedMdls を指定します。 OutputBuffer パラメーターを NULL に設定し、OutputBufferSize パラメーターを 0 に設定します。
USBD_QueryUsbCapability によって返される NTSTATUS 値を確認し、結果を評価します。 ルーチンが正常に完了した場合は、チェーンされた MDL 機能がサポートされます。 その他の値は、機能がサポートされていないことを示します。
MDL のチェーンを作成します。 各 MDL には、別の MDL を指す Next ポインターがあります。
ドライバーは、Next ポインターを手動で設定することで、チェーン MDL を構築できます。
前の例では、プロトコル ドライバーは MDL としてパケットを送信します。 中間ドライバーは、ヘッダー データを使用してメモリ ブロックを参照する別の MDL を作成できます。 チェーンを作成するために、中間ドライバーは、プロトコル ドライバーから受信した MDL をヘッダー MDL の Next ポインターを指すことができます。 中間ドライバーは、2 つの MDLs のチェーンをミニポート ドライバーに転送できます。これにより、要求の URB でチェーンされた MDL への参照が提供され、USB ドライバー スタックに要求が送信されます。 詳細については、「MDL の使用」を参照してください。
チェーンされた MDL を使用する I/O 要求の URB を構築するときに、関連付けられている URB 構造体の TransferBufferMDL メンバー (_URB_BULK_OR_INTERRUPT_TRANSFER や _URB_ISOCH_TRANSFER など) をチェーン内の最初の MDL に設定し、TransferBufferLength を転送する合計バイト数に設定します。 データは、MDL チェーン内の複数の MDL エントリにまたがる場合があります。
Windows 8 では、クライアント ドライバーがデータ転送にチェーンされた MDL を使用できるようにする 2 種類の新しい URB 関数が追加されました。 この機能を使用する場合は、URB ヘッダーの Function メンバーが次のいずれかの URB 関数に設定されていることを確認します。
- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER_USING_CHAINED_MDL
- URB_FUNCTION_ISOCH_TRANSFER_USING_CHAINED_MDL
これらの URB 関数の詳細については、_URB_HEADER を参照してください。
解説
基になる USB ドライバー スタックを照会して、ドライバー スタックがチェーンされた MDL を受け入れられるかどうかを判断するコード例については、USBD_QueryUsbCapability を参照してください。