DMA 操作インターフェイスのバージョン 3 のルーチンを使用する DMA 転送を実行するには、ドライバーは、次の一覧で説明されている手順に従う必要があります。 これらの手順は、下位デバイスとバス マスター デバイスの両方に共通です。 このインターフェイスのバージョン 3 は、Windows 8 以降で使用できます。 このインターフェイスのルーチンの詳細については、 DMA_OPERATIONSを参照してください。
手順 1: DMA アダプター オブジェクトを取得する
DMA 転送の準備として、ドライバーは IoGetDmaAdapter ルーチンを呼び出して DMA アダプター オブジェクトを取得します。 DMA アダプター オブジェクトは、バス マスター デバイスまたはシステム DMA コントローラーの要求行を表すソフトウェア オブジェクトです。 このオブジェクトには、デバイスとの間でデータを転送するために使用されるバスの DMA 操作インターフェイスが含まれています。 さらに、このオブジェクトは、転送を実行するために必要な共有リソースへのドライバーのアクセスを同期します。 詳細については、「 アダプター オブジェクトの概要」を参照してください。
手順 2: 必要な DMA リソースの説明を取得する
ドライバーは、転送を実行する必要がある DMA リソースの説明を取得する GetDmaTransferInfo ルーチンを呼び出します。
この呼び出しの入力パラメーターは、転送に使用するメモリ バッファーと、転送の方向 (読み取りまたは書き込み) を記述します。
この呼び出しから取得されるリソース要件には、マップ レジスタの数と、転送のデータ バッファーを記述するために必要な散布図/収集リストのサイズが含まれます。 AllocateAdapterChannelEx ルーチンの後続の呼び出し (手順 3 を参照) では、ドライバーは入力パラメーターとしてマップ レジスタ数を指定します。
手順 3: 必要な DMA リソースを要求する
ドライバーは、DMA アダプター オブジェクトに割り当てるリソースを割り当てるために AllocateAdapterChannelEx ルーチンを呼び出します。 これらのリソースには、DMA チャネルとマップ レジスタが含まれます。
AllocateAdapterChannelEx 呼び出しは、非同期または同期にすることができます。
DMA_SYNCHRONOUS_CALLBACK フラグが設定されていない場合、呼び出しは非同期です。 この場合、 ExecutionRoutine パラメーターは、要求されたリソースが使用可能になったときに呼び出される呼び出し元が指定した実行ルーチンを指します。 成功した場合、非同期 AllocateAdapterChannelEx 呼び出しは、実行ルーチンの実行を待たずにSTATUS_SUCCESSを返します。
DMA_SYNCHRONOUS_CALLBACK フラグが設定されている場合、 AllocateAdapterChannelEx 呼び出しは同期です。 この場合、呼び出しの ExecutionRoutine パラメーターは省略可能であり、 AllocateAdapterChannelEx は次のように動作します。
ExecutionRoutine が NULL 以外で、DMA リソースをすぐに割り当てることができる場合、AllocateAdapterChannelEx は呼び出し元のスレッドのコンテキストで実行ルーチンを呼び出します。 実行ルーチンの実行が完了すると、 AllocateAdapterChannelEx はSTATUS_SUCCESSを返します。 リソースがすぐに使用できない場合、 AllocateAdapterChannelEx は失敗し、エラー状態コードSTATUS_INSUFFICIENT_RESOURCES返します。
ExecutionRoutine が NULL で、AllocateAdapterChannelEx が DMA リソースをすぐに割り当てることができる場合、AllocateAdapterChannelEx はSTATUS_SUCCESSを返します。 すべてのリソースがすぐに使用できない場合、呼び出しはエラー状態コードSTATUS_INSUFFICIENT_RESOURCESで失敗します。
STATUS_SUCCESSを返す同期呼び出しの場合、AllocateAdapterChannelEx への MapRegisterBase パラメーターが NULL 以外の場合、AllocateAdapterChannelEx は割り当てられたマップ レジスタのベース アドレスを MapRegisterBase パラメーターが指すアドレスに書き込みます。 ExecutionRoutine が NULL の場合、MapRegisterBase は NULL 以外である必要があります。 ExecutionRoutine が NULL 以外の場合、AllocateAdapterChannelEx への MapRegisterBase パラメーターは省略可能であり、実行ルーチンは入力パラメーターとしてマップ レジスタのベース アドレスを受け取ります。
非同期 AllocateAdapterChannelEx 呼び出しの場合、 ExecutionRoutine は NULL 以外である必要があり、実行ルーチンは入力パラメーターとしてマップ レジスタのベース アドレスを受け取ります。
以降の MapTransferEx ルーチンの呼び出し ( 手順 5 を参照) では、ドライバーは、マップ レジスタのベース アドレスを入力パラメーターとして提供します。
ExecutionRoutine が NULL 以外の場合、実行ルーチンは、割り当てられたリソースの処理を示す状態値を返します。 システム DMA 転送の場合、この戻り値は KeepObject である必要があります。 この値は、アダプター オブジェクト (およびその割り当てられているすべてのリソース) が使用中であり、解放できないことをオペレーティング システムに通知します。 実行ルーチンが指定されていない場合、ドライバーは代わりに FreeAdapterObject ルーチンを呼び出し、AllocationOption パラメーターとして KeepObject を指定する必要があります。
手順 4: 必要に応じて、保留中のリソース要求を取り消します
AllocateAdapterChannelEx 呼び出しが DMA アダプターをキューに登録して DMA リソースを待機した後、ドライバーは必要に応じて CancelAdapterChannel ルーチンを呼び出して保留中のリソース要求を取り消すことができます。
CancelAdapterChannel が TRUE を返した場合、リソース要求は正常に取り消されます。 AllocateAdapterChannelEx 呼び出しで実行ルーチンが指定された場合、このルーチンは実行されません。
CancelAdapterChannel から FALSE が返された場合、リソース要求は既に許可されているためキャンセルできません。 AllocateAdapterChannelEx 呼び出しで実行ルーチンが指定された場合、このルーチンが呼び出されます。
手順 5: DMA リソースを初期化し、DMA 転送を開始する
ドライバーは、DMA リソースを初期化し、DMA 転送を開始する MapTransferEx を呼び出します。 この呼び出しは、 AllocateAdapterChannelEx を呼び出すのと同じドライバー スレッドで発生する可能性があります。または、ドライバーが AllocateAdapterChannelEx に提供する実行ルーチンで発生する可能性があります。 DMA データ バッファー全体を転送するために複数の MapTransferEx 呼び出しが必要な場合は、前の MapTransferEx 呼び出しの完了ルーチンで後の MapTransferEx 呼び出しが発生する可能性があります。
MapTransferEx では、入力パラメーターとしてチェーンされた MDL がサポートされています。 各 MDL は、仮想メモリ内で連続する DMA バッファーの領域を記述します。 MapTransferEx は、散布図/収集リストを構築するときに、ドライバーの介入なしに、仮想的に連続するバッファー領域から次のバッファー領域への遷移を自動的に処理します。 詳細については、「 MapTransferEx ルーチンの使用」を参照してください。
システム DMA 転送の場合、DMA 完了ルーチンへのポインターは、オプションの DmaCompletionRoutine パラメーターで MapTransferEx に渡すことができます。 このルーチンは、DMA 転送が完了したことを示すシステム DMA コントローラーからの割り込みに応答してディスパッチ レベルで実行するようにスケジュールされています。
MapTransferEx は、要求された転送サイズ全体をマップできない場合、*Length 出力パラメーターをマップされた長さに設定し、STATUS_SUCCESS返します。
手順 6: 必要に応じて、ハードウェア固有の操作を実行する
MapTransferEx は、DMA 転送が正常に開始されたことを示すSTATUS_SUCCESSを返します。 一部のプラットフォームでは、転送を開始するために MapTransferEx 呼び出しの外部でドライバーが追加のアクションを実行する必要がある場合がありますが、この種類の遅延開始はすべてのプラットフォームで必要ありません。 ドライバーは、割り当てられたリソースの使用と解放に関する決定のために、このような遅延に依存してはなりません。
DMA 操作インターフェイスのルーチンは、これらのルーチンを使用するドライバーに透過的な方法で DMA 転送のキャッシュの一貫性を維持します。 ハードウェアでキャッシュの一貫性を強制しないプラットフォームでは、 MapTransferEx により、書き込み (メモリからデバイスへの) 転送の前にプロセッサ データ キャッシュがフラッシュされます。 読み取り (デバイスからメモリへの) 転送では、すべての MapTransferEx 呼び出しに続く FlushAdapterBuffersEx ルーチン (手順 8 を参照) の呼び出し中にキャッシュが無効になります。
手順 7: DMA 転送が完了したときに通知を受信する
DMA 転送が完了すると、次の 2 つの方法のいずれかでドライバーに通知されます。
- デバイス ドライバーへのバス マスター デバイスによる割り込み
- システム DMA コントローラーを使用する下位デバイスに対するドライバー提供の完了ルーチンの実行
システム DMA 転送の場合、ドライバーは入力パラメーターとして MapTransferEx に完了ルーチンを提供できます。
手順 8: キャッシュに残っているデータをフラッシュする
DMA 転送が完了した後、ドライバーは、キャッシュに残っているデータをフラッシュする FlushAdapterBuffersEx ルーチンを呼び出す必要があります。 ドライバーは、MapTransferEx 呼び出しのたびに FlushAdapterBuffersEx を呼び出す必要があります。
MapTransferEx 呼び出しが DMA データ バッファーの一部のみをマップする場合、ドライバーは MapTransferEx をもう一度呼び出して残りのデータをマップする必要があります。 複雑な転送には、 複数の MapTransferEx 呼び出しが必要な場合があります。 追加の MapTransferEx 呼び出しごとに、手順 5 から 8 を繰り返します。
手順 9: DMA チャネルとマップ レジスタを解放する
DMA データ バッファー全体が正常にマップされ、最終的な転送が完了したら、ドライバーは FreeAdapterChannel ルーチンを呼び出して、DMA チャネルと以前に割り当てられたマップ レジスタを解放する必要があります。
手順 10: DMA アダプター オブジェクトを解放する
すべての DMA 転送が完了し、以前に割り当てられたマップ レジスタが解放されると、ドライバーは PutDmaAdapter ルーチンを呼び出してアダプター オブジェクトを解放します。