共用方式為


程式設計 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,取自 PLX9x5x 範例的 EvtProgramDma 回呼函式,以取得 Read.c 檔案中的讀取要求。

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

}