DMA ハードウェアのプログラミング
[KMDF のみに適用]
このトピックでは、バス マスター DMA デバイスの KMDF ドライバーがEvtProgramDmaイベント コールバック関数で通常提供する機能について説明します。 ドライバーがフレームワークの DMA サポートを使用している場合、ドライバーはこのコールバックを提供する必要があります。 この情報は、ハードウェア割り込みを持つ システム モード DMA デバイスのKMDF ドライバーにも適用されます。
IRQL = DISPATCH_LEVELで呼び出されるEvtProgramDmaコールバック関数は、DMA 転送を開始するようにデバイスをプログラムします。 このコールバック関数の入力パラメーターは、転送の方向 (入力または出力) とスキャッター/ギャザーリストを提供します。 転送が 単一のパケットで構成されている場合、スキャッター/ギャザーリストには 単一の要素が含まれます。
EvtProgramDmaコールバック関数は、ドライバーの EvtDevicePrepareHardware コールバック関数が受信したハードウェア リソースを使用して、デバイスをプログラムします。 EvtProgramDma コールバック関数がハードウェアを正常にプログラムすると、TRUEを返します。
ハードウェアが DMA 転送を完了すると、通常、ハードウェアは割り込みを発行し、システムはドライバーのEvtInterruptIsrコールバック関数を呼び出します。 ドライバーのEvtInterruptIsrコールバック関数は通常、次のとおりです:
ハードウェア割り込みをクリアします。
割り込みのコンテキスト情報が必要な場合は保存します。 この情報は、コールバック関数が戻り、システムが IRQL を下げた後に失われる可能性があります (IRQL を下げると、追加の割り込みが発生する可能性があるため)。
WdfInterruptQueueDpcForIsrを呼び出して、EvtInterruptDpc コールバック関数をスケジュールします。
EvtInterruptDpc コールバック関数は、EvtInterruptIsrコールバック関数が格納したコンテキスト情報を使用してDMA 転送を完了します。
EvtProgramDma コールバック関数がエラーを検出した場合、ドライバーはトランザクションを停止できます。
ドライバーがエラーを検出したときにトランザクションを停止するには、 EvtProgramDma コールバック関数は次を実行する必要があります:
WdfObjectDeleteを呼び出してDMA トランザクション オブジェクトを削除し、またはWdfDmaTransactionRelease を呼び出してDMA トランザクション オブジェクトを解放して再利用します。
トランザクションがフレームワークリクエストオブジェクトに関連付けられている場合は、I/O リクエストを再キューしまたはI/Oリクエストを完了します。 リクエストのハンドルを取得するために、ドライバーは WdfDmaTransactionGetRequestを呼び出すことができます。
FALSE を返します。
ステップ 1 と 4 は、Read.c ファイル内の読み取りリクエストに対する PLX9x5x サンプルのEvtProgramDmaコールバック関数から取得した次のコード例に示されています。
// If errors occur in the EvtProgramDma callback,
// release the DMA transaction object and complete the request.
if (errors) {
NTSTATUS status;
//
// Must abort the transaction before deleting.
//
(VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status);
ASSERT(NT_SUCCESS(status));
PLxReadRequestComplete( Transaction, STATUS_INVALID_DEVICE_STATE );
TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
"<-- PLxEvtProgramReadDma: errors ****");
return FALSE;
}
この例では、 PLxReadRequestComplete関数を呼び出して、ステップ 2 と 3 を実行します:
VOID
PLxReadRequestComplete(
IN WDFDMATRANSACTION DmaTransaction,
IN NTSTATUS Status
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
WDFREQUEST request;
size_t bytesTransferred;
//
// Get the associated request from the transaction.
//
request = WdfDmaTransactionGetRequest(DmaTransaction);
ASSERT(request);
//
// Get the final bytes transferred count.
//
bytesTransferred = WdfDmaTransactionGetBytesTransferred( DmaTransaction );
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
"PLxReadRequestComplete: Request %p, Status %!STATUS!, "
"bytes transferred %d\n",
request, Status, (int) bytesTransferred );
WdfDmaTransactionRelease(DmaTransaction);
//
// Complete this Request.
//
WdfRequestCompleteWithInformation( request, Status, bytesTransferred);
}