AllocateAdapterChannel がドライバーの AdapterControl ルーチンに制御を移すと、ドライバーはシステムDMAコントローラとマップレジスタのセットを「所有」します。 次に、ドライバーは、次の図に示すように、転送操作のためにDMAコントローラを設定する必要があります。
ドライバーに StartIo ルーチンがある場合、 AllocateAdapterChannel は DeviceObject->CurrentIrp へのポインターを PIrp パラメータで AdapterControl ルーチンに渡します。 ただし、ドライバーがIRPのキューを独自に管理する場合は、ドライバーは AdapterControlに渡すコンテキストの一部として、現在のIRPへのポインターを含める必要があります。
前の図が示すように、ドライバーの AdapterControl ルーチンは、以下のようにDMA転送を設定します:
AdapterControl ルーチンは、転送を開始するアドレスを取得します。 IRPを満たすために必要な最初の転送のために、 AdapterControl ルーチンは MmGetMdlVirtualAddressを呼び出し、このDMA転送用のバッファリングを記述する Irp->MdlAddressのMDLへのポインターを渡します。
MmGetMdlVirtualAddress は、ドライバーが転送を開始するシステム物理アドレスのインデックスとして使用できる仮想アドレスを返します。
IRPが複数の転送操作を必要とする場合、このセクションで後述するように、ドライバーは更新された開始アドレスを計算します。
AdapterControl ルーチンは、 MmGetMdlVirtualAddress によって返されたアドレス、またはステップ1で計算されたアドレスを保存します。 必須パラメータ (CurrentVa) が MapTransferへのアドレスです。
AdapterControl ルーチンは、 MapTransfer を呼び出してシステムDMAコントローラを設定し、以下のパラメータを供給します:
現在の IRP の Irp->MdlAddress にある MDL へのポインター(Mdl)
AllocateAdapterChannelによってドライバーの AdapterControl ルーチンに渡された MapRegisterBase ハンドル
IRP に対して MapTransfer を最初に呼び出した場合、 MmGetMdlVirtualAddress が返す値 (CurrentVa)
そうでない場合、ドライバーは更新された CurrentVa 値を供給し、次の転送操作をバッファのどこで開始すべきかを示します。
この転送のバイト数を示す変数 (Length) へのポインター
ドライバーが MapTransfer を1回呼び出すだけで要求されたデータをすべて転送でき、そのDMA操作にデバイス固有の制約がない場合、 Length は、IRPのドライバーのI/Oスタック位置にある Length の値に設定できます。 最大で、バイト長は (PAGE_SIZE * IoGetDmaAdapterが返す NumberOfMapRegisters )になります。 それ以外の場合、ドライバーは Splitting Transfer Requestsで説明されているように要求を分割しなければならず、現在の IRP に対する MapTransfer のその後の呼び出しで Length の値を更新しなければなりません。
転送操作の方向を示すブール値 (WriteToDevice)、 (システム・メモリからデバイスへデータを転送する場合はTRUE)
MapTransfer は論理アドレスを返します。 システムDMAを使用するドライバーは、この値を無視しなければなりません。
AdapterControl ルーチンは、DMA操作のためにデバイスを設定します。
AdapterControl ルーチンは KeepObjectを返します。
デバイスが現在のDMAオペレーションが完了したことを示すとき、ドライバーは FlushAdapterBuffersを呼び出す必要があります(通常はドライバーの DpcForIsr routineルーチンから)。
DpcForIsr ルーチンまたは DMA 操作を完了する他のドライバー ルーチンは、 FlushAdapterBuffers を呼び出し、システムDMAコントローラーにキャッシュされたデータがシステムメモリに読み込まれるか、デバイスに書き出されるようにします。 同じルーチンはまた、現在のIRPに対してより多くのデータを転送するためにシステムDMAコントローラを再プログラムする必要がある場合、 MapTransfer を再度呼び出す必要があります。 同様に、各転送操作の後に FlushAdapterBuffers を再度呼び出す必要があります。
ドライバーが現在の IRP に対して MapTransfer を複数回呼び出す必要がある場合、すべての呼び出しで同じアダプタオブジェクトポインター、 Mdl ポインタ、 MapRegisterBase ハンドル、および転送方向を供給します。 ただし、ドライバーは、2 回目以降の MapTransfer呼び出しの前に CurrentVa と Length パラメータを更新する必要があります。 これらの各パラメータの更新値を計算するには、以下の式を使用してください:
CurrentVa = CurrentVa + ( MapTransferへの直前の呼び出しで要求されたLength )
Length = 最小値 (転送される残りの Length 、(PAGE_SIZE * IoGetDmaAdapterが返す NumberOfMapRegisters ))
各ドライバーがDMA転送について保持すべきコンテキスト情報は、その特定のデバイスの必要性によって異なります。 典型的なコンテキストには、MDL内の現在の仮想アドレス (CurrentVa)、これまでに転送されたバイト数、転送の残りバイト数、場合によっては現在のIRPへのポインター、およびドライバー作成者が有益と考えるその他の情報が含まれます。
要求された転送が完了したとき、または、ドライバーがIRPに対してエラーステータスを返さなければならない場合、ドライバーは、他のドライバーとこのドライバが使用できるようにシステムDMAコントローラをリリースするために、速やかに FreeAdapterChannel を呼び出す必要があります。