EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE Rückruffunktion (wdfdmatransaction.h)

[Gilt nur für KMDF]

Die EvtDmaTransactionDmaTransferComplete-Ereignisrückruffunktion eines Treibers wird aufgerufen, wenn der Systemmoduscontroller die aktuelle DMA-Übertragung abgeschlossen hat.

Syntax

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
)
{...}

Parameter

[in] Transaction

Ein Handle für ein DMA-Transaktionsobjekt, das die soeben abgeschlossene DMA-Übertragung darstellt.

[in] Device

Ein Handle für das Framework-Geräteobjekt, das der Treiber beim Aufrufen von WdfDmaTransactionCreate angegeben hat.

[in] Context

Der Kontextzeiger, den der Treiber in einem vorherigen Aufruf von WdfDmaTransactionSetTransferCompleteCallback angegeben hat.

[in] Direction

Ein WDF_DMA_DIRECTION typisierter Wert, der die Richtung des abgeschlossenen DMA-Übertragungsvorgangs angibt.

[in] Status

Ein DMA_COMPLETION_STATUS typisierter Wert, der die status der Übertragung angibt.

Rückgabewert

Keine

Bemerkungen

Die Hardware für ein Bus-master DMA-Gerät gibt in der Regel einen Interrupt aus, wenn eine DMA-Übertragung abgeschlossen ist. Der Treiber schließt dann die DMA-Übertragung in seiner EvtInterruptDpc-Rückruffunktion ab.

Die Hardware für ein DMA-Gerät im Systemmodus signalisiert jedoch nicht immer den Abschluss der DMA-Übertragung, indem ein Interrupt ausgegeben wird. Um eine Benachrichtigung über den Abschluss der DMA-Übertragung zu erhalten, kann ein Treiber für ein DMA-Gerät im Systemmodus stattdessen eine EvtDmaTransactionDmaTransferComplete-Ereignisrückruffunktion registrieren, indem er WdfDmaTransactionSetTransferCompleteCallback aufruft.

Das Framework ruft EvtDmaTransactionDmaTransferComplete auf, nachdem der System-DMA-Controller die Übertragung abgeschlossen hat, einmal für jede Übertragung in einer Transaktion.

Aus seinem EvtDmaTransactionDmaTransferComplete-Rückruf kann der Treiber die folgenden Methoden aufrufen, um das Framework darüber zu informieren, dass die Übertragung abgeschlossen wurde:

WdfDmaTransactionDmaCompletedWdfDmaTransactionDmaCompletedFinalWdfDmaTransactionDmaCompletedWithLength Der Treiber ruft möglicherweise keine der vorherigen Methoden von EvtDmaTransactionDmaTransferComplete auf. Stattdessen wird ein Timerobjekt erstellt oder ein DPC für den späteren Abschluss der Übertragung nach Bedarf geplant. Nachdem WdfDmaTransactionDmaCompletedXxx TRUE zurückgegeben hat, was angibt, dass keine weiteren Übertragungen erforderlich sind, um die DMA-Transaktion abzuschließen, kann der Treiber optional WdfDmaTransactionExecute aufrufen, um eine nachfolgende Transaktion zu initiieren.

Wenn der Treiber WdfDmaTransactionStopSystemTransfer aufruft, ruft das Framework EvtDmaTransactionDmaTransferComplete mit dem StatuswertDmaCancelled auf. In diesem Fall sollte der Treiber WdfDmaTransactionDmaCompletedFinal innerhalb von EvtDmaTransactionDmaTransferComplete aufrufen und dann mit der Anforderungsverarbeitung fortfahren.

Der Treiber darf die der Transaktion zugeordneten Datenpuffer erst bearbeiten, nachdem WdfDmaTransactionDmaCompletedXxx TRUE zurückgegeben hat.

Der Treiber kann WdfDmaTransactionRelease innerhalb von EvtDmaTransactionDmaTransferComplete aufrufen, wenn die DMA-Transaktion beendet werden muss.

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

Beispiele

Um eine EvtDmaTransactionDmaTransferComplete-Rückruffunktion zu definieren, müssen Sie zuerst eine Funktionsdeklaration bereitstellen, die den Typ der von Ihnen definierten Rückruffunktion identifiziert. Windows bietet eine Reihe von Rückruffunktionstypen für Treiber. Das Deklarieren einer Funktion mithilfe der Rückruffunktionstypen hilft der Codeanalyse für Treiber, der statischen Treiberüberprüfung (Static Driver Verifier , SDV) und anderen Überprüfungstools, Fehler zu finden, und es ist eine Anforderung zum Schreiben von Treibern für das Windows-Betriebssystem.

Um beispielsweise eine EvtDmaTransactionDmaTransferComplete-Rückruffunktion namens MyDmaTransactionDmaTransferComplete zu definieren, verwenden Sie den typ EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE , wie in diesem Codebeispiel gezeigt:

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE  MyDmaTransactionDmaTransferComplete;

Implementieren Sie dann Ihre Rückruffunktion wie folgt.


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

Der EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE Funktionstyp ist in der Headerdatei WdfDmaTransaction.h definiert. Um Fehler beim Ausführen der Codeanalysetools genauer zu identifizieren, fügen Sie der Funktionsdefinition die Use_decl_annotations Anmerkung hinzu. Die Use_decl_annotations Anmerkung stellt sicher, dass die Anmerkungen verwendet werden, die auf den EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE Funktionstyp in der Headerdatei angewendet werden. Weitere Informationen zu den Anforderungen für Funktionsdeklarationen finden Sie unter Deklarieren von Funktionen mithilfe von Funktionsrollentypen für KMDF-Treiber. Informationen zu Use_decl_annotations finden Sie unter Verhalten von Funktionen mit Anmerkungen.

Anforderungen

Anforderung Wert
Unterstützte Mindestversion (Client) Windows 8
Zielplattform Universell
KMDF-Mindestversion 1.11
Kopfzeile wdfdmatransaction.h (einschließen von Wdf.h)
IRQL DISPATCH_LEVEL

Weitere Informationen

WdfDmaTransactionSetTransferCompleteCallback