[仅适用于 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 回调函数必须:
调用 WdfObjectDelete 以删除 DMA 事务对象,或调用 WdfDmaTransactionRelease 释放并重复使用 DMA 事务对象。
如果事务与框架请求对象关联,请重新排队 I/O 请求或完成 I/O 请求。 若要检索请求的句柄,驱动程序可以调用 WdfDmaTransactionGetRequest。
返回 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);
}