完成 DMA 传输
[仅适用于 KMDF]
通常,驱动程序的 EvtInterruptDpc 回调函数完成每个 DMA 传输的处理。
首先,由于多个 DMA 事务可以同时进行, 因此 EvtInterruptDpc 回调函数必须确定与已完成的传输关联的 DMA 事务。 回调函数可以通过检索驱动程序 在启动 DMA 事务时存储的事务句柄来执行此操作。 为了检索设备扩展, PLX9x5x 示例在其 Private.h 头文件中定义了一个名为 PLxGetDeviceContext 的函数:
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, PLxGetDeviceContext)
然后,在驱动程序的 EvtInterruptDpc 回调中,它会执行以下操作:
WDFDMATRANSACTION dmaTransaction;
PDEVICE_EXTENSION devExt;
...
devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));
...
dmaTransaction = devExt->WriteDmaTransaction;
接下来, EvtInterruptDpc 回调函数必须通过调用以下传输完成方法之一来通知框架传输已完成:
WdfDmaTransactionDmaCompleted,如果传输成功完成,并且硬件未报告传输的字节计数。
WdfDmaTransactionDmaCompletedWithLength,如果传输成功完成,并且硬件报告 (传输字节计数或未) 传输的字节计数,或者驱动程序检测到错误并将传输计数指定为零以重试传输。 如果驱动程序将传输计数指定为零,则框架将从剩余字节数中减去零,从而将相同的传输发送到 EvtProgramDma 回调函数。
WdfDmaTransactionDmaCompletedFinal(如果硬件报告运行不足或故障条件)。
驱动程序可以调用 WdfDmaTransactionGetCurrentDmaTransferLength 来获取已完成传输的原始长度。 如果设备报告未传输的字节数,此调用非常有用,因为驱动程序可以从原始传输长度中减去未传输的字节数,然后调用 WdfDmaTransactionGetCurrentDmaTransferLength 来报告实际传输大小。
上述每个传输完成方法都会通知框架单个 DMA 传输 (不是整个 DMA 事务) 完成。 驱动程序调用以下方法之一后,驱动程序会检查方法的返回值,以查看事务是否需要更多传输:
如果完成方法的返回值为 FALSE,则框架已确定需要额外的 DMA 传输才能完成 DMA 事务的处理。
通常,驱动程序的 EvtInterruptDpc 回调函数仅返回。 框架再次调用驱动程序的 EvtProgramDma 回调函数,回调函数可以对硬件进行编程,以便进行下一次传输。
传输完成方法提供状态值,在本例中始终STATUS_MORE_PROCESSING_REQUIRED。
如果返回值为 TRUE,则 DMA 事务不会再发生传输。
传输完成方法提供状态值。 如果状态值为STATUS_SUCCESS,则 DMA 事务的所有传输都已完成,驱动程序必须 完成 DMA 事务。 如果状态值为任何其他值,则会发生错误,并且 DMA 事务可能尚未完成。
如果 EvtInterruptDpc 回调函数检测到错误(通常是由于计时器过期或硬件中断指示传输错误),驱动程序可以重启事务的当前传输。
若要重启事务的当前传输,驱动程序的 EvtInterruptDpc 回调函数可以调用 WdfDmaTransactionDmaCompletedWithLength ,并将 TransferedLength 参数设置为零。