Partager via


Fonction WdfDmaTransactionStopSystemTransfer (wdfdmatransaction.h)

[S’applique uniquement à KMDF]

La méthode WdfDmaTransactionStopSystemTransfer tente d’arrêter un transfert DMA en mode système après que l’infrastructure a appelé EvtProgramDma.

Syntaxe

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Paramètres

[in] DmaTransaction

Handle d’un objet de transaction DMA initialisé.

Valeur de retour

None

Remarques

Seul un pilote qui utilise DMA en mode système doit appeler WdfDmaTransactionStopSystemTransfer.

Un pilote utilisant le contrôle DMA de gestion de bus est responsable de la programmation de son propre contrôleur DMA dédié. En cas d’annulation de demande, de délai d’expiration ou d’erreur de périphérique, le pilote peut programmer le contrôleur DMA pour arrêter le transfert de données.

En revanche, un pilote utilisant DMA en mode système doit s’appuyer sur la couche d’abstraction matérielle (HAL) pour programmer le contrôleur DMA partagé. Lorsqu’un pilote appelle WdfDmaTransactionStopSystemTransfer, l’infrastructure avertit hal que le transfert doit être arrêté et retourne immédiatement.

L’infrastructure appelle ensuite la fonction de rappel EvtDmaTransactionDmaTransferComplete du pilote, si le pilote en a fourni une. Si ce n’est pas le cas, l’infrastructure retourne FALSE lorsque le pilote appelle ensuite WdfDmaTransactionDmaCompleted.

Si votre pilote appelle cette méthode sur un système d’exploitation antérieur à Windows 8, le vérificateur de l’infrastructure signale une erreur.

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

Pour plus d’informations sur l’annulation de transactions DMA, consultez Annulation de transactions DMA.

Exemples

L’exemple de code suivant montre comment un pilote peut appeler WdfDmaTransactionStopSystemTransfer à partir d’une fonction de rappel d’événement EvtTimerFunc qu’il inscrit pour être appelé si une demande d’E/S expire.

VOID
MyTimerFunc(
    __in WDFTIMER Timer
    )
{
    WDFREQUEST request = (WDFREQUEST) WdfTimerGetParentObject(Timer);
    PREQUEST_CONTEXT requestContext = GetRequestContext(request);

    //
    // Begin the completion process.  If we're the first to get here 
    // then stop the DMA transfer.  The dma completion routine will
    // take care of running down cancellation.
    //
    if (BeginCompletion(requestContext, STATUS_IO_TIMEOUT, false)) {
        WdfDmaTransactionStopSystemTransfer(requestContext->DmaTransaction);
    }
    
    AttemptRequestCompletion(requestContext, false);
}

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 won't ever 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);
    }
}

L’exemple de code suivant montre comment un pilote peut appeler WdfDmaTransactionStopSystemTransfer à partir d’une fonction de rappel EvtRequestCancel . Le pilote appelait précédemment WdfRequestMarkCancelableEx à partir de son gestionnaire de demandes d’E/S pour inscrire le rappel.

VOID
MyRequestCancel(
    __in WDFREQUEST Request
    )
{
    PREQUEST_CONTEXT requestContext = GetRequestContext(Request);
    LONG oldValue;

    //
    // Start completion
    //

    if (BeginCompletion(requestContext, STATUS_CANCELLED, false)) {
        
        //
        // Cancel the DMA transaction.
        //
        if (WdfDmaTransactionCancel(requestContext->DmaTransaction) == TRUE) {
            //
            // The transaction was stopped before EvtProgramDma could be 
            // called.  Drop the I/O reference.
            // 
            oldValue = InterlockedDecrement(&requestContext->CompletionRefCount);
            NT_ASSERTMSG("Completion reference count should not reach zero until "
                         L"this routine calls AttemptRequestCompletion",
                         oldValue > 0);
            NT_ASSERTMSG("Completion status should be cancelled", 
                         requestContext->CompletionStatus == STATUS_CANCELLED);
        }
        else {
            //
            // The transaction couldn't be stopped before EvtProgramDma.
            // Stop any running system DMA transfer.
            //
            WdfDmaTransactionStopSystemTransfer(requestContext->DmaTransaction);
        }
    }

    AttemptRequestCompletion(requestContext, false);
}

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)
Bibliothèque Wdf01000.sys (consultez Gestion de version de la bibliothèque d’infrastructure.)
IRQL <=DISPATCH_LEVEL
Règles de conformité DDI DriverCreate(kmdf)

Voir aussi

WdfDmaTransactionCancel

WdfDmaTransactionCreate