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


Программирование оборудования DMA

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

В этом разделе описаны функциональные возможности, которые драйвер KMDF для устройства DMA, master шины, обычно предоставляет в функции обратного вызова события EvtProgramDma. Если драйвер использует поддержку DMA платформы, драйвер должен предоставить этот обратный вызов. Эти сведения также относятся к драйверу KMDF для устройства DMA в системном режиме с аппаратным прерыванием.

Функция обратного вызова EvtProgramDma , которая вызывается в irQL = DISPATCH_LEVEL, программируют устройство для запуска передачи DMA. Входные параметры для этой функции обратного вызова предоставляют направление передачи (входные или выходные данные) и список точечной/сборной. Если передача состоит из одного пакета, то точечный список содержит один элемент.

Функция обратного вызова EvtProgramDma программируют устройство, используя аппаратные ресурсы, полученные функцией обратного вызова EvtDevicePrepareHardware драйвера. Если функция обратного вызова EvtProgramDma успешно программируют оборудование, она возвращает значение TRUE.

После завершения передачи DMA оборудование обычно прерывает работу, и система вызывает функцию обратного вызова EvtInterruptIsr драйвера. Функция обратного вызова EvtInterruptIsr драйвера обычно:

  • Очищает аппаратное прерывание.

  • При необходимости сохраняет сведения о контексте прерывания. Эти сведения могут быть потеряны после возврата функции обратного вызова и снижения значения IRQL системой (так как понижение irQL позволяет выполнять дополнительные прерывания).

  • Вызывает WdfInterruptQueueDpcForIsr для планирования функции обратного вызова EvtInterruptDpc .

Функция обратного вызова EvtInterruptDpcзавершает передачу DMA с использованием контекстных сведений, сохраненных функцией обратного вызова EvtInterruptIsr .

Если функция обратного вызова EvtProgramDma обнаруживает ошибку, драйвер может остановить транзакцию.

Чтобы остановить транзакцию, когда драйвер обнаруживает ошибку, функция обратного вызова EvtProgramDma должна:

  1. Вызовите WdfDmaTransactionDmaCompletedFinal.

  2. Вызовите WdfObjectDelete , чтобы удалить объект транзакции DMA, или вызовите WdfDmaTransactionRelease , чтобы освободить и повторно использовать объект транзакции DMA.

  3. Повторно введите запрос ввода-вывода или завершите запрос ввода-вывода, если транзакция связана с объектом запроса платформы. Чтобы получить дескриптор запроса, драйвер может вызвать WdfDmaTransactionGetRequest.

  4. Возвращает значение FALSE.

Шаги 1 и 4 показаны в следующем примере кода, взятом из функции обратного вызова EvtProgramDma примера PLX9x5x для запросов на чтение в файле 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);

}