Funzione WdfDmaTransactionStopSystemTransfer (wdfdmatransaction.h)

[Si applica solo a KMDF]

Il metodo WdfDmaTransactionStopSystemTransfer tenta di arrestare un trasferimento DMA in modalità sistema dopo che il framework ha chiamato EvtProgramDma.

Sintassi

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Parametri

[in] DmaTransaction

Handle per un oggetto transazione DMA inizializzato.

Valore restituito

nessuno

Osservazioni

Solo un driver che usa DMA in modalità sistema deve chiamare WdfDmaTransactionStopSystemTransfer.

Un driver che usa il mastering del bus DMA è responsabile della programmazione del proprio controller DMA dedicato. In caso di annullamento della richiesta, timeout o errore del dispositivo, il driver può programmare il controller DMA per interrompere il trasferimento dei dati.

Al contrario, un driver che usa DMA in modalità sistema deve basarsi sul livello di astrazione hardware (HAL) per programmare il controller DMA condiviso. Quando un driver chiama WdfDmaTransactionStopSystemTransfer, il framework notifica all'HAL che il trasferimento deve essere arrestato e restituisce immediatamente.

Il framework chiama quindi la funzione di callback EvtDmaTransactionDmaTransferComplete del driver, se il driver ne ha fornito uno. In caso contrario, il framework restituisce FALSE quando il driver chiama successivamente WdfDmaTransactionDmaCompleted.

Se il driver chiama questo metodo in un sistema operativo precedente a Windows 8, il verificatore del framework segnala un errore.

Per altre informazioni su DMA in modalità sistema, vedere Supporto System-Mode DMA.

Per altre informazioni sull'annullamento delle transazioni DMA, vedere Annullamento delle transazioni DMA.

Esempio

L'esempio di codice seguente illustra come un driver potrebbe chiamare WdfDmaTransactionStopSystemTransfer da una funzione di callback di eventi EvtTimerFunc che registra per essere chiamata se si verifica un timeout di una richiesta di I/O.

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'esempio di codice seguente illustra come un driver potrebbe chiamare WdfDmaTransactionStopSystemTransfer da una funzione di callback EvtRequestCancel . Il driver precedentemente denominato WdfRequestMarkCancelableEx dal gestore di richieste di I/O per registrare il callback.

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);
}

Requisiti

Requisito Valore
Client minimo supportato Windows 8
Piattaforma di destinazione Universale
Versione KMDF minima 1.11
Intestazione wdfdmatransaction.h (include Wdf.h)
Libreria Wdf01000.sys (vedere Controllo delle versioni della libreria framework).
IRQL <=DISPATCH_LEVEL
Regole di conformità DDI DriverCreate(kmdf)

Vedi anche

WdfDmaTransactionCancel

WdfDmaTransactionCreate