Canceling DMA Transactions
[Applies to KMDF only]
If your driver has been built with version 1.11 or a later version of KMDF and is running on Windows 8 or later using direct memory access (DMA) version 3, the driver can attempt to cancel a pending DMA transaction by calling the WdfDmaTransactionCancel method.
When calling WdfDmaTransactionCancel, the driver must ensure that the specified DMA transaction is not completed during the call. The driver can use the following technique to safely cancel a transaction, either before DMA channel allocation or after some number of transfer operations have already completed:
In one of the driver's request handlers, the driver calls WdfRequestMarkCancelableEx and provides an EvtRequestCancel callback function for the I/O request. The request handler then calls WdfDmaTransactionExecute.
The driver's EvtRequestCancel callback function (which may begin running in a separate thread immediately after the call to WdfRequestMarkCancelableEx) calls WdfDmaTransactionCancel.
If the call to WdfDmaTransactionCancel occurs after the call to WdfDmaTransactionExecute, but before the WdfDmaTransactionExecute method has started DMA allocation, transaction cancellation succeeds and WdfDmaTransactionCancel returns TRUE. In this case, the driver's EvtRequestCancel callback function must complete the DMA transaction. WdfDmaTransactionExecute returns an error value.
If the driver calls WdfDmaTransactionCancel after the WdfDmaTransactionExecute method has started DMA allocation, the attempt to cancel the transaction fails and WdfDmaTransactionCancel returns FALSE. In this case, WdfDmaTransactionExecute returns STATUS_SUCCESS and the driver's request handler must complete the DMA transaction.
At this point, if the driver is using system-mode DMA, the EvtRequestCancel callback function might call WdfDmaTransactionStopSystemTransfer to attempt to stop the in-progress system-mode DMA transfer. For a code example that shows how to do this, see WdfDmaTransactionStopSystemTransfer.
After the WdfDmaTransactionExecute method finishes DMA allocation, the framework calls the driver's EvtProgramDma callback function (which may begin running in a separate thread immediately after the call to WdfDmaTransactionExecute). At this point, a call to the WdfDmaTransactionCancel method would return FALSE.
In EvtProgramDma, the driver can call WdfRequestUnmarkCancelable to end the possibility of request cancellation. If WdfRequestUnmarkCancelable returns STATUS_SUCCESS, the callback function must program the hardware to start the transfer. If WdfRequestUnmarkCancelable returns STATUS_CANCELLED, the request has been canceled. In this case, EvtProgramDma must call WdfDmaTransactionDmaCompletedFinal to complete the DMA transaction.
The driver can use the same technique to cancel a DMA transaction after some number of transfer operations have already completed. In this case, the driver calls WdfDmaTransactionCancel after it calls WdfDmaTransactionDmaCompleted, but before the framework calls EvtProgramDma to program the next transfer operation. If the driver happens to call WdfDmaTransactionCancel before it calls WdfDmaTransactionDmaCompleted, WdfDmaTransactionDmaCompleted returns TRUE, indicating that the DMA transaction has been completed.