Поделиться через


Завершение передачи DMA

[Применяется только к KMDF]

Как правило, функция обратного вызова EvtInterruptDpc драйвера завершает обработку каждой передачи DMA.

Во-первых, так как одновременно может выполняться несколько транзакций DMA, функция обратного вызова EvtInterruptDpc должна определить, с какой транзакцией DMA связана завершенная передача. Функция обратного вызова может сделать это, получив дескриптор транзакции, сохраненный драйвером при запуске транзакции DMA. Чтобы получить расширение устройства, в примере PLX9x5x определяется функция PLxGetDeviceContext в файле заголовка Private.h:

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 , равным нулю.