[仅适用于 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来注册 EvtDmaTransactionDmaTransactionDmaTransferCompleteCallback 事件回调函数。
框架在系统 DMA 控制器完成传输后调用 EvtDmaTransactionDmaTransferComplete,每次传输事务。
从其 EvtDmaTransactionDmaTransferComplete 回调中,驱动程序可以调用以下方法来通知框架传输已完成:
WdfDmaTransactionDmaCompletedWdfDmaTransactionDmaCompletedFinalWdfDmaTransactionDmaCompletedWithLength 驱动程序可能无法调用 EvtDmaTransactionDmaTransferComplete中的上述方法之一,选择改为 创建计时器对象 或计划 DPC 以根据需要完成传输。 WdfDmaTransactionDmaCompletedXxx 返回 TRUE 后,指示无需更多传输来完成 DMA 事务,驱动程序可以选择调用 WdfDmaTransactionExecute 启动后续事务。
如果驱动程序调用 WdfDmaTransactionStopSystemTransfer,则框架将调用 EvtDmaTransactionDmaTransferComplete,其状态 值为 DmaCancelled。 在这种情况下,驱动程序应从 EvtDmaTransactionDmaTransactionDmaTransferComplete中调用 WdfDmaTransactionDmaCompletedFinal,然后可以继续处理请求。
在 WdfDmaTransactionDmaCompletedXxx 返回 TRUE 之前,驱动程序不得作与事务关联的数据缓冲区。
驱动程序可以从 EvtDmaTransactionDmaTransferComplet e 中调用 WdfDmaTransactionRelease(如果需要终止 DMA 事务)。
有关系统模式 DMA 的详细信息,请参阅 支持 System-Mode DMA。
例子
若要定义 EvtDmaTransactionDmaTransferComplete 回调函数,必须首先提供一个函数声明来标识要定义的回调函数的类型。 Windows 为驱动程序提供一组回调函数类型。 使用回调函数类型声明函数有助于 驱动程序代码分析、静态驱动程序验证程序(SDV)和其他验证工具查找错误,这是为 Windows作系统编写驱动程序的要求。
例如,若要定义 EvtDmaTransactionDmaTransferComplete回调函数,该函数名为 myDmaTransactionDmaTransactionDmaTransferComplete,请使用 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 |
目标平台 | 普遍 |
最低 KMDF 版本 | 1.11 |
标头 | wdfdmatransaction.h (包括 Wdf.h) |
IRQL | DISPATCH_LEVEL |