Partager via


EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE fonction de rappel (wdfdmatransaction.h)

[S’applique uniquement à KMDF]

La fonction de rappel d’événement EvtDmaTransactionDmaTransferComplete d’un pilote est appelée lorsque le contrôleur en mode système a terminé le transfert DMA actuel.

Syntaxe

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE EvtWdfDmaTransactionDmaTransferComplete;

void EvtWdfDmaTransactionDmaTransferComplete(
  [in] WDFDMATRANSACTION Transaction,
  [in] WDFDEVICE Device,
  [in] WDFCONTEXT Context,
  [in] WDF_DMA_DIRECTION Direction,
  [in] DMA_COMPLETION_STATUS Status
)
{...}

Paramètres

[in] Transaction

Handle vers un objet de transaction DMA représentant le transfert DMA qui vient de se terminer.

[in] Device

Handle de l’objet de périphérique framework que le pilote a spécifié quand il a appelé WdfDmaTransactionCreate.

[in] Context

Pointeur de contexte que le pilote a spécifié dans un appel précédent à WdfDmaTransactionSetTransferCompleteCallback.

[in] Direction

Valeur de type WDF_DMA_DIRECTION qui spécifie le sens de la fin de l’opération de transfert DMA.

[in] Status

Valeur de type DMA_COMPLETION_STATUS qui spécifie la status du transfert.

Valeur de retour

None

Remarques

Le matériel d’un appareil DMA master bus émet généralement une interruption lorsqu’un transfert DMA est terminé. Le pilote termine ensuite le transfert DMA dans sa fonction de rappel EvtInterruptDpc .

Toutefois, le matériel d’un appareil DMA en mode système ne signale pas toujours l’achèvement du transfert DMA en émettant une interruption. Pour recevoir la notification de l’achèvement du transfert DMA, un pilote pour un appareil DMA en mode système peut plutôt inscrire une fonction de rappel d’événement EvtDmaTransactionDmaTransferComplete en appelant WdfDmaTransactionSetTransferCompleteCallback.

L’infrastructure appelle EvtDmaTransactionDmaTransferComplete une fois que le contrôleur DMA système a terminé le transfert, une fois pour chaque transfert dans une transaction.

À partir de son rappel EvtDmaTransactionDmaTransferComplete , le pilote peut appeler les méthodes suivantes pour notifier l’infrastructure que le transfert est terminé :

WdfDmaTransactionDmaCompletedWdfDmaTransactionDmaCompletedFinalWdfDmaTransactionDmaCompletedWithLength Le pilote peut ne pas appeler l’une des méthodes précédentes d’EvtDmaTransactionDmaTransferComplete, choisissant plutôt de créer un objet minuteur ou de planifier un DPC pour terminer le transfert ultérieurement, si nécessaire. Une fois que WdfDmaTransactionDmaCompletedXxx a retourné TRUE, indiquant qu’aucun autre transfert n’est nécessaire pour terminer la transaction DMA, le pilote peut éventuellement appeler WdfDmaTransactionExecute pour lancer une transaction suivante.

Si le pilote appelle WdfDmaTransactionStopSystemTransfer, l’infrastructure appelle EvtDmaTransactionDmaTransferComplete avec une valeur Statusde DmaCancelled. Dans ce cas, le pilote doit appeler WdfDmaTransactionDmaCompletedFinal à partir de EvtDmaTransactionDmaTransferComplete, puis peut continuer le traitement des demandes.

Le pilote ne doit pas manipuler les mémoires tampons de données associées à la transaction tant que WdfDmaTransactionDmaCompleted Xxx n’a pas retourné TRUE.

Le pilote peut appeler WdfDmaTransactionRelease à partir de EvtDmaTransactionDmaTransferComplete s’il doit arrêter la transaction DMA.

Pour plus d’informations sur la DMA en mode système, consultez Prise en charge System-Mode DMA.

Exemples

Pour définir une fonction de rappel EvtDmaTransactionDmaTransferComplete , vous devez d’abord fournir une déclaration de fonction qui identifie le type de fonction de rappel que vous définissez. Windows fournit un ensemble de types de fonctions de rappel pour les pilotes. La déclaration d’une fonction à l’aide des types de fonction de rappel aide l’analyse du code pour les pilotes, le vérificateur de pilotes statique (SDV) et d’autres outils de vérification à la recherche d’erreurs. Il s’agit d’une exigence pour l’écriture de pilotes pour le système d’exploitation Windows.

Par exemple, pour définir une fonction de rappel EvtDmaTransactionDmaTransferComplete nommée MyDmaTransactionDmaTransferComplete, utilisez le type EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE comme indiqué dans cet exemple de code :

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE  MyDmaTransactionDmaTransferComplete;

Ensuite, implémentez votre fonction de rappel comme suit.


_Use_decl_annotations_
VOID
MyDmaTransactionDmaTransferComplete(
    WDFDMATRANSACTION Transaction,
    WDFDEVICE /* Device */,
    WDFCONTEXT Context,
    WDF_DMA_DIRECTION /* Direction */,
    DMA_COMPLETION_STATUS DmaStatus
    )
{
    PREQUEST_CONTEXT requestContext = (PREQUEST_CONTEXT) Context;
    NTSTATUS requestStatus;
    bool overrideStatus = true;
    size_t bytesTransferred;

    if (DmaStatus == DmaComplete) {
        //
        // Normal transfer completion.  Indicate this to the framework and see 
        // if there's more work to do.
        //
        if (WdfDmaTransactionDmaCompleted(Transaction, &requestStatus) == FALSE) {
            //
            // There are more DMA transfers to come.  The transaction 
            // may already have been completed on another processor.  
            // Return without touching it again.
            //
            goto exit;
        }

        requestStatus = STATUS_SUCCESS;
    }
    else {

        //
        // Complete the entire transaction.  But throw out the status and 
        // use one derived from the DmaStatus.
        //
        WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &requestStatus);        
        
        //
        // Error or cancellation.  Indicate that this was the final transfer to 
        // the framework.
        //
        if (DmaStatus == DmaError) {
            requestStatus = STATUS_DEVICE_DATA_ERROR;
        }
        else {

            //
            // Cancel status should only be triggered by timeout or cancel.  Rely on 
            // someone having already set the status, which means we should lose
            // the race for BeginCompletion below.
            //
            requestStatus = STATUS_PENDING;
            overrideStatus = false;
        }
    }

    //
    // Begin completion.  There's nothing special to do here if cancel or
    // timeout got there first.
    //
    BeginCompletion(requestContext, requestStatus, overrideStatus);

    //
    // Record the number of bytes we transferred.
    //
    bytesTransferred = WdfDmaTransactionGetBytesTransferred(
                        requestContext->DmaTransaction
                        );

    WdfRequestSetInformation(requestContext->Request, bytesTransferred);

    //
    // Success, error or cancel, this was the last transfer in the 
    // transaction.  Attempt to complete the request.
    //
    AttemptRequestCompletion(requestContext, true);

exit: 
    return;
}

bool
BeginCompletion(
    __in PREQUEST_CONTEXT  RequestContext,
    __in NTSTATUS          CompletionStatus,
    __in bool              ForceStatusUpdate
    )
{
    bool completionStarted;

    //
    // Grab the object lock and mark the beginning of 
    // completion.
    //
    WdfSpinLockAcquire(RequestContext->Lock);

    completionStarted = RequestContext->CompletionStarted;
    RequestContext->CompletionStarted = true;

    if ((completionStarted == false) || 
        (ForceStatusUpdate == true)) {
        RequestContext->CompletionStatus = CompletionStatus;
    }

    WdfSpinLockRelease(RequestContext->Lock);

    return !completionStarted;
}

VOID
AttemptRequestCompletion(
    __in PREQUEST_CONTEXT RequestContext,
    __in bool TransferComplete
    )
{
    LONG refCount;

    NT_ASSERTMSG("No thread has begun completion", 
                 RequestContext->CompletionStarted == true);

    if (TransferComplete) {
        //
        // Unmark the request cancelable.  If that succeeds then drop the cancel reference
        //
        if (WdfRequestUnmarkCancelable(RequestContext->Request) == STATUS_SUCCESS) {
            refCount = InterlockedDecrement(&(RequestContext->CompletionRefCount));
            NT_ASSERTMSGW(L"Reference count should not have gone to zero yet",
                          refCount != 0);
        }
                
        //
        // Stop the timer if it's been started.
        //
        if (RequestContext->TimerStarted == true) {
            if (WdfTimerStop(RequestContext->Timer, FALSE) == TRUE) {
                //
                // The timer was queued but will never run.  Drop its 
                // reference count.
                //
                refCount = InterlockedDecrement(&RequestContext->CompletionRefCount);
                NT_ASSERTMSG("Completion reference count should not reach zero until "
                             L"this routine calls AttemptRequestCompletion",
                             refCount > 0);
            }
        }
    }

    //
    // Drop this caller's reference.  If that was the last one then 
    // complete the request.
    //
    refCount = InterlockedDecrement(&(RequestContext->CompletionRefCount));

    if (refCount == 0) {
        NT_ASSERTMSGW(L"Execution reference was released, but execution "
                      L"path did not set a completion status for the "
                      L"request",
                      RequestContext->CompletionStatus != STATUS_PENDING);
        
        
        //
        // Timers are disposed of at passive level.  If we leave it attached to 
        // the request then we can hit a verifier issue, since the request 
        // needs to be immediately disposable at dispatch-level.
        //
        // Delete the timer now so that we can complete the request safely.
        // At this point the timer has either expired or been successfully 
        // cancelled so there's no race with the timer routine.
        //
        if (RequestContext->Timer != NULL) {
            WdfObjectDelete(RequestContext->Timer);
            RequestContext->Timer = NULL;
        }

        WdfRequestComplete(RequestContext->Request, 
                           RequestContext->CompletionStatus);
    }
}

Le type de fonction EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE est défini dans le fichier d’en-tête WdfDmaTransaction.h. Pour identifier plus précisément les erreurs lors de l’exécution des outils d’analyse du code, veillez à ajouter l’annotation Use_decl_annotations à votre définition de fonction. L’annotation Use_decl_annotations garantit que les annotations appliquées au type de fonction EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE dans le fichier d’en-tête sont utilisées. Pour plus d’informations sur la configuration requise pour les déclarations de fonction, consultez Déclaration de fonctions à l’aide de types de rôles de fonction pour les pilotes KMDF. Pour plus d’informations sur Use_decl_annotations, consultez Annotating Function Behavior.

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows 8
Plateforme cible Universal
Version KMDF minimale 1.11
En-tête wdfdmatransaction.h (inclure Wdf.h)
IRQL DISPATCH_LEVEL

Voir aussi

WdfDmaTransactionSetTransferCompleteCallback