Programmazione dell'hardware DMA

[Si applica solo a KMDF]

In questo argomento vengono descritte le funzionalità fornite in genere da un driver KMDF per un dispositivo DMA master del bus nella relativa funzione di callback degli eventi EvtProgramDma . Se il driver usa il supporto DMA del framework, il driver deve fornire questo callback. Queste informazioni si applicano anche a un driver KMDF per un dispositivo DMA in modalità sistema con interruzione hardware.

La funzione di callback EvtProgramDma , chiamata in IRQL = DISPATCH_LEVEL, programma il dispositivo per avviare un trasferimento DMA. I parametri di input per questa funzione di callback forniscono la direzione del trasferimento (input o output) e un elenco a dispersione/raccolta. Se il trasferimento è costituito da un singolo pacchetto, l'elenco di dispersione/raccolta contiene un singolo elemento.

La funzione di callback EvtProgramDma programma il dispositivo usando le risorse hardware ricevute dalla funzione di callback EvtDevicePrepareHardware del driver. Se la funzione di callback EvtProgramDma programma correttamente l'hardware, restituisce TRUE.

Dopo che l'hardware ha completato il trasferimento DMA, in genere l'hardware genera un interrupt e il sistema chiama la funzione di callback evtInterruptIsr del driver. La funzione di callback EvtInterruptIsr del driver in genere:

  • Cancella l'interruzione hardware.

  • Salva le informazioni di contesto dell'interrupt, se necessario. Queste informazioni potrebbero andare perse dopo la restituzione della funzione di callback e il sistema riduce l'IRQL (poiché l'abbassamento del runtime di integrazione consente l'esecuzione di interruzioni aggiuntive).

  • Chiama WdfInterruptQueueDpcForIsr per pianificare una funzione di callback EvtInterruptDpc .

La funzione di callback EvtInterruptDpccompleta il trasferimento DMA usando le informazioni di contesto salvate dalla funzione di callback EvtInterruptIsr .

Se la funzione di callback EvtProgramDma rileva un errore, il driver può arrestare la transazione.

Per arrestare una transazione quando il driver rileva un errore, la funzione di callback EvtProgramDma deve:

  1. Chiamare WdfDmaTransactionDmaCompletedFinal.

  2. Chiamare WdfObjectDelete per eliminare l'oggetto transazione DMA oppure chiamare WdfDmaTransactionRelease per rilasciare e riutilizzare l'oggetto transazione DMA.

  3. Accodare nuovamente la richiesta di I/O o completare la richiesta di I/O, se la transazione è associata a un oggetto richiesta framework. Per recuperare un handle alla richiesta, il driver può chiamare WdfDmaTransactionGetRequest.

  4. Restituisce FALSE.

I passaggi 1 e 4 sono illustrati nell'esempio di codice seguente, tratto dalla funzione di callback EvtProgramDma dell'esempio PLX9x5x per le richieste di lettura nel file 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;
    }

L'esempio chiama la funzione PLxReadRequestComplete per eseguire i passaggi 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);

}