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 コールバック関数は次を実行する必要があります:

  1. WdfDmaTransactionDmaCompletedFinalを呼び出します。

  2. WdfObjectDeleteを呼び出してDMA トランザクション オブジェクトを削除し、またはWdfDmaTransactionRelease を呼び出してDMA トランザクション オブジェクトを解放して再利用します。

  3. トランザクションがフレームワークリクエストオブジェクトに関連付けられている場合は、I/O リクエストを再キューしまたはI/Oリクエストを完了します。 リクエストのハンドルを取得するために、ドライバーは WdfDmaTransactionGetRequestを呼び出すことができます。

  4. 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);

}