WdfDmaTransactionStopSystemTransfer-Funktion (wdfdmatransaction.h)

[Gilt nur für KMDF]

Die WdfDmaTransactionStopSystemTransfer-Methode versucht, eine DMA-Übertragung im Systemmodus zu beenden, nachdem das Framework EvtProgramDma aufgerufen hat.

Syntax

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Parameter

[in] DmaTransaction

Ein Handle für ein initialisiertes DMA-Transaktionsobjekt.

Rückgabewert

Keine

Bemerkungen

Nur ein Treiber, der DMA im Systemmodus verwendet, sollte WdfDmaTransactionStopSystemTransfer aufrufen.

Ein Treiber mit Busmastering-DMA ist für die Programmierung seines eigenen dedizierten DMA-Controllers verantwortlich. Im Falle eines Anforderungsabbruchs, eines Timeouts oder eines Gerätefehlers kann der Treiber den DMA-Controller so programmieren, dass die Datenübertragung beendet wird.

Im Gegensatz dazu muss ein Treiber, der DMA im Systemmodus verwendet, die Hardware abstraction Layer (HAL) verwenden, um den freigegebenen DMA-Controller zu programmieren. Wenn ein Treiber WdfDmaTransactionStopSystemTransfer aufruft, benachrichtigt das Framework die HAL, dass die Übertragung beendet werden muss, und gibt sofort zurück.

Das Framework ruft als Nächstes die Rückruffunktion EvtDmaTransactionDmaTransferComplete des Treibers auf, sofern der Treiber eine bereitgestellt hat. Andernfalls gibt das Framework FALSE zurück, wenn der Treiber WdfDmaTransactionDmaCompleted als Nächstes aufruft.

Wenn Ihr Treiber diese Methode auf einem früheren Betriebssystem als Windows 8 aufruft, meldet die Überprüfung des Frameworks einen Fehler.

Weitere Informationen zu DMA im Systemmodus finden Sie unter Unterstützen System-Mode DMA.

Weitere Informationen zum Abbrechen von DMA-Transaktionen finden Sie unter Abbrechen von DMA-Transaktionen.

Beispiele

Das folgende Codebeispiel zeigt, wie ein Treiber WdfDmaTransactionStopSystemTransfer von einer EvtTimerFunc-Ereignisrückruffunktion aufrufen kann, die er registriert, um aufgerufen zu werden, wenn ein E/A-Anforderungstimeout ausfällt.

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

Das folgende Codebeispiel zeigt, wie ein Treiber WdfDmaTransactionStopSystemTransfer von einer EvtRequestCancel-Rückruffunktion aufrufen kann. Der Treiber hat zuvor WdfRequestMarkCancelableEx aus seinem E/A-Anforderungshandler aufgerufen, um den Rückruf zu registrieren.

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

Anforderungen

Anforderung Wert
Unterstützte Mindestversion (Client) Windows 8
Zielplattform Universell
KMDF-Mindestversion 1.11
Kopfzeile wdfdmatransaction.h (include Wdf.h)
Bibliothek Wdf01000.sys (siehe Versionsverwaltung der Frameworkbibliothek).)
IRQL <=DISPATCH_LEVEL
DDI-Complianceregeln DriverCreate(kmdf)

Weitere Informationen

WdfDmaTransactionCancel

WdfDmaTransactionCreate