Hardware de DMA de programação

[Aplica-se somente ao KMDF]

Este tópico descreve a funcionalidade que um driver KMDF para um dispositivo DMA master de barramento normalmente fornece em sua função de retorno de chamada de evento EvtProgramDma. Se o driver usar o suporte de DMA da estrutura, o driver deverá fornecer esse retorno de chamada. Essas informações também se aplicam a um driver KMDF para um dispositivo DMA no modo de sistema que tem uma interrupção de hardware.

A função de retorno de chamada EvtProgramDma , que é chamada em IRQL = DISPATCH_LEVEL, programa o dispositivo para iniciar uma transferência de DMA. Os parâmetros de entrada para essa função de retorno de chamada fornecem a direção da transferência (entrada ou saída) e uma lista de dispersão/coleta. Se a transferência consistir em um único pacote, a lista de dispersão/coleta conterá um único elemento.

A função de retorno de chamada EvtProgramDma programa o dispositivo usando os recursos de hardware que a função de retorno de chamada EvtDevicePrepareHardware do driver recebeu. Se a função de retorno de chamada EvtProgramDma programar com êxito o hardware, ela retornará TRUE.

Depois que o hardware concluir a transferência de DMA, normalmente o hardware emite uma interrupção e o sistema chama a função de retorno de chamada EvtInterruptIsr do driver. A função de retorno de chamada EvtInterruptIsr do driver geralmente:

  • Limpa a interrupção de hardware.

  • Salva as informações de contexto da interrupção se elas forem necessárias. Essas informações podem ser perdidas depois que a função de retorno de chamada retorna e o sistema reduz o IRQL (porque a redução do IRQL permite que interrupções adicionais ocorram).

  • Chama WdfInterruptQueueDpcForIsr para agendar uma função de retorno de chamada EvtInterruptDpc .

A função de retorno de chamada EvtInterruptDpcconclui a transferência de DMA usando informações de contexto que a função de retorno de chamada EvtInterruptIsr salvou.

Se a função de retorno de chamada EvtProgramDma detectar um erro, o driver poderá interromper a transação.

Para interromper uma transação quando o driver detectar um erro, a função de retorno de chamada EvtProgramDma deve:

  1. Chame WdfDmaTransactionDmaCompletedFinal.

  2. Chame WdfObjectDelete para excluir o objeto de transação DMA ou chame WdfDmaTransactionRelease para liberar e reutilizar o objeto de transação DMA.

  3. Requeira a solicitação de E/S ou conclua a solicitação de E/S, se a transação estiver associada a um objeto de solicitação de estrutura. Para recuperar um identificador para a solicitação, o driver pode chamar WdfDmaTransactionGetRequest.

  4. Retornar FALSE.

As etapas 1 e 4 são ilustradas no exemplo de código a seguir, obtido da função de retorno de chamada EvtProgramDma da amostra PLX9x5x para solicitações de leitura no arquivo 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;
    }

O exemplo chama a função PLxReadRequestComplete para executar as etapas 2 e 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);

}