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

一个WDF_DMA_DIRECTION类型的值,该值指定完成 DMA 传输操作的方向。

[in] Status

指定传输状态 的DMA_COMPLETION_STATUS类型值。

返回值

备注

总线主 DMA 设备的硬件通常在 DMA 传输完成后发出中断。 然后,驱动程序在其 EvtInterruptDpc 回调函数中完成 DMA 传输。

但是,系统模式 DMA 设备的硬件并不总是通过发出中断来发出 DMA 传输完成信号。 若要接收 DMA 传输完成通知,系统模式 DMA 设备的驱动程序可以通过调用 WdfDmaTransactionSetTransferCompleteCallback 来注册 EvtDmaTransactionDmaTransferComplete 事件回调函数。

框架在系统 DMA 控制器完成传输后调用 EvtDmaTransactionDmaTransferComplete ,一次用于事务中的每个传输。

其 EvtDmaTransactionDmaTransferComplete 回调中,驱动程序可以调用以下方法来通知框架传输已完成:

WdfDmaTransactionDmaCompletedWdfDmaTransactionDmaCompletedFinalWdfDmaTransactionDmaCompletedWithLength 驱动程序可能无法从 EvtDmaTransactionDmaTransactionDmaTransferComplete 调用上述方法之一,而是选择 创建计时器对象 或计划 DPC 以根据需要稍后完成传输。 WdfDmaTransactionDmaCompletedXxx 返回 TRUE 后,指示无需更多传输才能完成 DMA 事务,驱动程序可以选择调用 WdfDmaTransactionExecute 来启动后续事务。

如果驱动程序调用 WdfDmaTransactionStopSystemTransfer,则框架将使用状态值为 DmaCancelled 调用 EvtDmaTransactionDmaTransferComplete。 在这种情况下,驱动程序应从 EvtDmaTransactionDmaTransactionDmaTransferComplete 中调用 WdfDmaTransactionDmaCompletedFinal,然后可以继续处理请求。

WdfDmaTransactionDmaCompletedXxx 返回 TRUE 之前,驱动程序不得操作与事务关联的数据缓冲区。

如果需要终止 DMA 事务,驱动程序可以从 EvtDmaTransactionDmaTransactionDmaTransferComplete 内部调用 WdfDmaTransactionRelease

有关系统模式 DMA 的详细信息,请参阅 支持System-Mode DMA

示例

若要定义 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 succesfully 
        // 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
目标平台 通用
最低 KMDF 版本 1.11
Header wdfdmatransaction.h (包括 Wdf.h)
IRQL DISPATCH_LEVEL

另请参阅

WdfDmaTransactionSetTransferCompleteCallback