EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE回呼函式 (wdfdmatransaction.h)

[僅適用於 KMDF]

當系統模式控制器已完成目前的 DMA 傳輸時,會呼叫驅動程式的 EvtDmaTransactionDmaTransferComplete 事件回呼函式。

語法

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE EvtWdfDmaTransactionDmaTransferComplete;

void EvtWdfDmaTransactionDmaTransferComplete(
  [in] WDFDMATRANSACTION Transaction,
  [in] WDFDEVICE Device,
  [in] WDFCONTEXT Context,
  [in] WDF_DMA_DIRECTION Direction,
  [in] DMA_COMPLETION_STATUS Status
)
{...}

參數

[in] Transaction

DMA 交易物件的句柄,表示剛完成的 DMA 傳輸

[in] Device

架構裝置物件的句柄,驅動程式在呼叫 WdfDmaTransactionCreate 時所指定的。

[in] Context

在先前呼叫 WdfDmaTransactionSetTransferCompleteCallback 中指定的驅動程式所指定的內容指標。

[in] Direction

指定完成 DMA 傳輸作業方向 的WDF_DMA_DIRECTION型別值。

[in] Status

指定傳輸狀態 的DMA_COMPLETION_STATUS型別值。

傳回值

備註

總線主要 DMA 裝置的硬體通常會在 DMA 傳輸完成時發出中斷。 驅動程式接著會在其 EvtInterruptDpc 回呼函式中完成 DMA 傳輸。

不過,系統模式 DMA 裝置的硬體不一定會發出中斷來發出 DMA 傳輸完成訊號。 若要接收 DMA 傳輸完成的通知,系統模式 DMA 裝置的驅動程式可以藉由呼叫 WdfDmaTransactionSetTransferCompleteCallback 來註冊 EvtDmaTransactionDmaTransferComplete 事件回呼函式。

架構會在系統 DMA 控制器完成傳輸之後呼叫 EvtDmaTransactionDmaTransferComplete ,一次用於交易中的每個傳輸。

從其 EvtDmaTransactionDmaTransferComplete 回呼內,驅動程式可以呼叫下列方法來通知架構傳輸已完成:

WdfDmaTransactionDmaCompletedWdfDmaTransactionDmaCompletedFinalWdfDmaTransactionDmaCompletedWithLength 驅動程式可能不會視需要從 EvtDmaTransactionDmaTransactionDmaTransactionDmaTransferComplete 呼叫上述其中一種方法,改為 改為建立定時器物件 或排程 DPC 以稍後完成傳輸。 在 WdfDmaTransactionDmaCompletedXxx 傳回 TRUE 之後,表示不再需要傳輸才能完成 DMA 交易,驅動程式可以選擇性地呼叫 WdfDmaTransactionExecute 來起始後續的交易。

如果驅動程式呼叫 WdfDmaTransactionStopSystemTransfer,架構會呼叫 EvtDmaTransactionDmaTransferComplete ,其 Status 值為 DmaCancelled。 在此情況下,驅動程式應該從 EvtDmaTransactionDmaTransactionDmaTransferComplete 內呼叫 WdfDmaTransactionDmaCompletedFinal,然後繼續處理要求。

WdfDmaTransactionDmaCompletedXxx 傳回 TRUE 之前,驅動程式不得操作與交易相關聯的數據緩衝區。

如果驅動程式需要終止 DMA 交易,則驅動程式可以從 EvtDmaTransactionDmaTransferComplete 內呼叫 WdfDmaTransactionRelease

如需系統模式 DMA 的詳細資訊,請參閱 支援 DMA System-Mode

範例

若要定義 EvtDmaTransactionDmaTransferComplete 回呼函式,您必須先提供函式宣告,以識別您要定義的回呼函式類型。 Windows 提供一組驅動程式的回呼函式類型。 使用回呼函式類型宣告函式有助於 驅動程式的程式代碼分析靜態驅動程式驗證器 (SDV) ,以及其他驗證工具尋找錯誤,而且這是撰寫 Windows 操作系統驅動程式的需求。

例如,若要定義名為 MyDmaTransactionDmaTransferComplete 的 EvtDmaTransactionDmaTransferComplete 回呼函式,請使用EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE類型,如下列程式代碼範例所示:

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE  MyDmaTransactionDmaTransferComplete;

然後,實作回呼函式,如下所示。


_Use_decl_annotations_
VOID
MyDmaTransactionDmaTransferComplete(
    WDFDMATRANSACTION Transaction,
    WDFDEVICE /* Device */,
    WDFCONTEXT Context,
    WDF_DMA_DIRECTION /* Direction */,
    DMA_COMPLETION_STATUS DmaStatus
    )
{
    PREQUEST_CONTEXT requestContext = (PREQUEST_CONTEXT) Context;
    NTSTATUS requestStatus;
    bool overrideStatus = true;
    size_t bytesTransferred;

    if (DmaStatus == DmaComplete) {
        //
        // Normal transfer completion.  Indicate this to the framework and see 
        // if there's more work to do.
        //
        if (WdfDmaTransactionDmaCompleted(Transaction, &requestStatus) == FALSE) {
            //
            // There are more DMA transfers to come.  The transaction 
            // may already have been completed on another processor.  
            // Return without touching it again.
            //
            goto exit;
        }

        requestStatus = STATUS_SUCCESS;
    }
    else {

        //
        // Complete the entire transaction.  But throw out the status and 
        // use one derived from the DmaStatus.
        //
        WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &requestStatus);        
        
        //
        // Error or cancellation.  Indicate that this was the final transfer to 
        // the framework.
        //
        if (DmaStatus == DmaError) {
            requestStatus = STATUS_DEVICE_DATA_ERROR;
        }
        else {

            //
            // Cancel status should only be triggered by timeout or cancel.  Rely on 
            // someone having already set the status, which means we should lose
            // the race for BeginCompletion below.
            //
            requestStatus = STATUS_PENDING;
            overrideStatus = false;
        }
    }

    //
    // Begin completion.  There's nothing special to do here if cancel or
    // timeout got there first.
    //
    BeginCompletion(requestContext, requestStatus, overrideStatus);

    //
    // Record the number of bytes we transferred.
    //
    bytesTransferred = WdfDmaTransactionGetBytesTransferred(
                        requestContext->DmaTransaction
                        );

    WdfRequestSetInformation(requestContext->Request, bytesTransferred);

    //
    // Success, error or cancel, this was the last transfer in the 
    // transaction.  Attempt to complete the request.
    //
    AttemptRequestCompletion(requestContext, true);

exit: 
    return;
}

bool
BeginCompletion(
    __in PREQUEST_CONTEXT  RequestContext,
    __in NTSTATUS          CompletionStatus,
    __in bool              ForceStatusUpdate
    )
{
    bool completionStarted;

    //
    // Grab the object lock and mark the beginning of 
    // completion.
    //
    WdfSpinLockAcquire(RequestContext->Lock);

    completionStarted = RequestContext->CompletionStarted;
    RequestContext->CompletionStarted = true;

    if ((completionStarted == false) || 
        (ForceStatusUpdate == true)) {
        RequestContext->CompletionStatus = CompletionStatus;
    }

    WdfSpinLockRelease(RequestContext->Lock);

    return !completionStarted;
}

VOID
AttemptRequestCompletion(
    __in PREQUEST_CONTEXT RequestContext,
    __in bool TransferComplete
    )
{
    LONG refCount;

    NT_ASSERTMSG("No thread has begun completion", 
                 RequestContext->CompletionStarted == true);

    if (TransferComplete) {
        //
        // Unmark the request cancelable.  If that succeeds then drop the cancel reference
        //
        if (WdfRequestUnmarkCancelable(RequestContext->Request) == STATUS_SUCCESS) {
            refCount = InterlockedDecrement(&(RequestContext->CompletionRefCount));
            NT_ASSERTMSGW(L"Reference count should not have gone to zero yet",
                          refCount != 0);
        }
                
        //
        // Stop the timer if it's been started.
        //
        if (RequestContext->TimerStarted == true) {
            if (WdfTimerStop(RequestContext->Timer, FALSE) == TRUE) {
                //
                // The timer was queued but will never run.  Drop its 
                // reference count.
                //
                refCount = InterlockedDecrement(&RequestContext->CompletionRefCount);
                NT_ASSERTMSG("Completion reference count should not reach zero until "
                             L"this routine calls AttemptRequestCompletion",
                             refCount > 0);
            }
        }
    }

    //
    // Drop this caller's reference.  If that was the last one then 
    // complete the request.
    //
    refCount = InterlockedDecrement(&(RequestContext->CompletionRefCount));

    if (refCount == 0) {
        NT_ASSERTMSGW(L"Execution reference was released, but execution "
                      L"path did not set a completion status for the "
                      L"request",
                      RequestContext->CompletionStatus != STATUS_PENDING);
        
        
        //
        // Timers are disposed of at passive level.  If we leave it attached to 
        // the request then we can hit a verifier issue, since the request 
        // needs to be immediately disposable at dispatch-level.
        //
        // Delete the timer now so that we can complete the request safely.
        // At this point the timer has either expired or been successfully 
        // cancelled so there's no race with the timer routine.
        //
        if (RequestContext->Timer != NULL) {
            WdfObjectDelete(RequestContext->Timer);
            RequestContext->Timer = NULL;
        }

        WdfRequestComplete(RequestContext->Request, 
                           RequestContext->CompletionStatus);
    }
}

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE函式類型定義於 WdfDmaTransaction.h 頭檔中。 若要在執行程式代碼分析工具時更精確地識別錯誤,請務必將 Use_decl_annotations 批註新增至函式定義。 Use_decl_annotations批註可確保使用頭檔中套用至EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE函式類型的註釋。 如需函數宣告需求的詳細資訊,請參閱 使用 KMDF 驅動程式的函式角色類型來宣告函式。 如需 Use_decl_annotations的詳細資訊,請參閱 標註函式行為

規格需求

需求
最低支援的用戶端 Windows 8
目標平台 Universal
最低 KMDF 版本 1.11
標頭 wdfdmatransaction.h (包含 Wdf.h)
IRQL DISPATCH_LEVEL

另請參閱

WdfDmaTransactionSetTransferCompleteCallback