对 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 回调函数必须:
调用 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);
}