Partager via


Programmation du matériel DMA

[S’applique uniquement à KMDF]

Cette rubrique décrit les fonctionnalités qu’un pilote KMDF pour un périphérique DMA maître bus fournit généralement dans sa fonction de rappel d’événement EvtProgramDma . Si votre pilote utilise la prise en charge DMA du framework, vous devez fournir ce rappel. Ces informations s’appliquent également à un pilote KMDF pour un périphérique DMA en mode système qui a une interruption matérielle.

La fonction de rappel EvtProgramDma , appelée à IRQL = DISPATCH_LEVEL, programme l’appareil pour démarrer un transfert DMA. Les paramètres d'entrée de cette fonction de rappel fournissent la direction du transfert (entrée ou sortie) et une liste scatter/gather. Si le transfert se compose d’un seul paquet, la liste d'ordonnancement/ramassage contient un seul élément.

La fonction de rappel EvtProgramDma programme l’appareil à l’aide des ressources matérielles reçues par la fonction de rappel EvtDevicePrepareHardware du pilote. Si la fonction de rappel EvtProgramDma programme correctement le matériel, elle retourne TRUE.

Une fois le matériel terminé le transfert DMA, il émet généralement une interruption et le système appelle la fonction de rappel EvtInterruptIsr du pilote. La fonction de rappel EvtInterruptIsr du pilote est généralement :

  • Efface l’interruption matérielle.

  • Enregistre les informations de contexte de l’interruption si nécessaire. Ces informations peuvent être perdues après le retour de la fonction de rappel lorsque le système abaisse le niveau de IRQL (car abaisser le niveau d'IRQL permet aux interruptions supplémentaires de se produire).

  • Appelle WdfInterruptQueueDpcForIsr pour planifier l'exécution de la fonction de rappel EvtInterruptDpc.

La fonction de rappel EvtInterruptDpctermine le transfert DMA à l’aide d’informations contextuelles enregistrées par la fonction de rappel EvtInterruptIsr .

Si la fonction de rappel EvtProgramDma détecte une erreur, le pilote peut arrêter la transaction.

Pour arrêter une transaction lorsque le pilote détecte une erreur, la fonction de rappel EvtProgramDma doit :

  1. Appelez WdfDmaTransactionDmaCompletedFinal.

  2. Appelez WdfObjectDelete pour supprimer l’objet de transaction DMA, ou appelez WdfDmaTransactionRelease pour libérer et réutiliser l’objet de transaction DMA.

  3. Réinitialisation de la demande d’E/S ou complétez la requête d’E/S si la transaction est associée à un objet de demande d’infrastructure. Pour récupérer un handle à la demande, le pilote peut appeler WdfDmaTransactionGetRequest.

  4. Retourne FALSE.

Les étapes 1 et 4 sont illustrées dans l’exemple de code suivant, extraites de la fonction de rappel EvtProgramDma de l’exemple PLX9x5x pour les demandes de lecture dans le fichier 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’exemple appelle la fonction PLxReadRequestComplete pour effectuer les étapes 2 et 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);

}