次の方法で共有


DMA ハードウェアのプログラミング

[KMDF にのみ適用]

このトピックでは、バス マスター DMA デバイスの KMDF ドライバーが EvtProgramDma イベント コールバック関数で通常提供する機能について説明します。 ドライバーがフレームワークの DMA サポートを使用している場合は、このコールバックを指定する必要があります。 この情報は、ハードウェア割り込みを持つ システム モード DMA デバイス の KMDF ドライバーにも適用されます。

IRQL = DISPATCH_LEVEL で呼び出される EvtProgramDma コールバック関数は、 DMA 転送を開始するようにデバイスをプログラムします。 このコールバック関数の入力パラメーターは、転送の方向 (入力または出力) と散布図/収集リストを提供します。 転送が 1 つのパケットで構成されている場合、散布図/収集リストには 1 つの要素が含まれます。

EvtProgramDma コールバック関数は、ドライバーの EvtDevicePrepareHardware コールバック関数が受け取ったハードウェア リソースを使用して、デバイスをプログラムします。 EvtProgramDma コールバック関数がハードウェアを正常にプログラムすると、TRUE が返されます。

ハードウェアが DMA 転送を完了すると、通常は割り込みが発行され、システムはドライバーの EvtInterruptIsr コールバック関数を呼び出します。 通常、ドライバーの EvtInterruptIsr コールバック関数は次のとおりです。

  • ハードウェア割り込みをクリアします。

  • 必要に応じて、割り込みのコンテキスト情報を保存する。 この情報は、コールバック関数が戻り、システムが IRQL を下げた後に失われる可能性があります (IRQL を下げると、追加の割り込みが発生する可能性があるため)。

  • WdfInterruptQueueDpcForIsr を呼び出して、EvtInterruptDpc コールバック関数をスケジュールします。

EvtInterruptDpc コールバック関数は、EvtInterruptIsr コールバック関数が保存したコンテキスト情報を使用して DMA 転送を完了します。

EvtProgramDma コールバック関数がエラーを検出した場合、ドライバーはトランザクションを停止できます。

ドライバーがエラーを検出したときにトランザクションを停止するには、 EvtProgramDma コールバック関数は次の手順を実行する必要があります。

  1. WdfDmaTransactionDmaCompletedFinal を呼び出します。

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

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

}