取消 DMA 事务
[仅适用于 KMDF]
如果驱动程序是使用 1.11 版或更高版本的 KMDF 构建的,并且使用 DMA) 版本 3 的直接内存访问 (在 Windows 8 或更高版本上运行,则驱动程序可以通过调用 WdfDmaTransactionCancel 方法尝试取消挂起的 DMA 事务。
调用 WdfDmaTransactionCancel 时,驱动程序必须确保在调用期间未完成指定的 DMA 事务。 驱动程序可以使用以下方法安全地取消事务,无论是在 DMA 通道分配之前,还是在完成一些传输操作之后:
在驱动程序 的请求处理程序之一中,驱动程序调用 WdfRequestMarkCancelableEx ,并为 I/O 请求提供 EvtRequestCancel 回调函数。 然后,请求处理程序调用 WdfDmaTransactionExecute。
驱动程序的 EvtRequestCancel 回调函数 (,该函数可能会在调用 WdfRequestMarkCancelEx) 调用 WdfDmaTransactionCancel 后立即开始在单独的线程中运行。
如果对 WdfDmaTransactionCancel 的调用发生在对 WdfDmaTransactionExecute 的调用之后,但在 WdfDmaTransactionExecute 方法已启动 DMA 分配之前发生,则事务取消成功, WdfDmaTransactionCancel 返回 TRUE。 在这种情况下,驱动程序的 EvtRequestCancel 回调函数必须 完成 DMA 事务。 WdfDmaTransactionExecute 返回错误值。
如果在 WdfDmaTransactionExecute 方法启动 DMA 分配后驱动程序调用 WdfDmaTransactionCancel ,则取消事务的尝试将失败, 并且 WdfDmaTransactionCancel 返回 FALSE。 在这种情况下, WdfDmaTransactionExecute 返回STATUS_SUCCESS,驱动程序的请求处理程序必须 完成 DMA 事务。
此时,如果驱动程序使用的是系统模式 DMA, 则 EvtRequestCancel 回调函数可能会调用 WdfDmaTransactionStopSystemTransfer 来尝试停止正在进行的系统模式 DMA 传输。 有关演示如何执行此操作的代码示例,请参阅 WdfDmaTransactionStopSystemTransfer。
WdfDmaTransactionExecute 方法完成 DMA 分配后,框架调用驱动程序的 EvtProgramDma 回调函数 (该函数可能会在调用 WdfDmaTransactionExecute) 后立即开始在单独的线程中运行。 此时,对 WdfDmaTransactionCancel 方法的 调用将返回 FALSE。
在 EvtProgramDma 中,驱动程序可以调用 WdfRequestUnmarkCancelable 以结束请求取消的可能性。 如果 WdfRequestUnmarkCancelable 返回STATUS_SUCCESS,则回调函数必须对硬件进行编程才能启动传输。 如果 WdfRequestUnmarkCancelable 返回STATUS_CANCELLED,则表示请求已取消。 在这种情况下, EvtProgramDma 必须调用 WdfDmaTransactionDmaCompletedFinal 才能 完成 DMA 事务。
在完成一些传输操作后,驱动程序可以使用同一技术取消 DMA 事务。 在这种情况下,驱动程序在调用 WdfDmaTransactionDmaCompleted 之后,但在框架调用 EvtProgramDma 之前调用 WdfDmaTransactionCancel,以便对下一个传输操作进行编程。 如果驱动程序在调用 WdfDmaTransactionDmaCompleted 之前调用 WdfDmaTransactionCancel, 则 WdfDmaTransactionDmaCompleted 返回 TRUE,表示 DMA 事务已完成。