Freigeben über


WdfDmaTransactionStopSystemTransfer-Funktion (wdfdmatransaction.h)

[Gilt nur für KMDF]

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

Syntax

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Die Parameter

[in] DmaTransaction

Ein Handle für ein initialisiertes DMA-Transaktionsobjekt.

Rückgabewert

Nichts

Bemerkungen

Nur ein Treiber, der systemmodus-DMA verwendet, sollte WdfDmaTransactionStopSystemTransferaufrufen.

Ein Fahrer mit Busmaster-DMA ist für die Programmierung eines eigenen dedizierten DMA-Controllers verantwortlich. Im Falle eines Anforderungsabbruchs, timeouts oder Gerätefehlers kann der Treiber den DMA-Controller programmieren, um die Übertragung von Daten zu beenden.

Im Gegensatz dazu muss ein Treiber, der systemmodus-DMA verwendet, auf die Hardwarestraktionsebene (HAL) angewiesen sein, um den freigegebenen DMA-Controller zu programmieren. Wenn ein Treiber WdfDmaTransactionStopSystemTransferaufruft, benachrichtigt das Framework die HAL, dass die Übertragung beendet und sofort zurückgegeben werden muss.

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

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

Weitere Informationen zum Systemmodus-DMA finden Sie unter Unterstützen von 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 registriert wird, wenn eine E/A-Anforderung ein Timeout auftritt.

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 zuvor WdfRequestMarkCancelableEx vom 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ützter Client (Mindestversion) Windows 8
Zielplattform universell
Minimale KMDF-Version 1.11
Kopfzeile wdfdmatransaction.h (include Wdf.h)
Bibliothek Wdf01000.sys (siehe Framework-Bibliotheksversionsverwaltung.)
IRQL <=DISPATCH_LEVEL
DDI-Complianceregeln DriverCreate(kmdf)

Siehe auch

WdfDmaTransactionCancel

WdfDmaTransactionCreate