EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE función de devolución de llamada (wdfdmatransaction.h)

[Solo se aplica a KMDF]

Se llama a la función de devolución de llamada de eventos EvtDmaTransactionDmaTransferComplete de un controlador cuando el controlador del modo del sistema ha completado la transferencia DMA actual.

Sintaxis

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

Parámetros

[in] Transaction

Identificador de un objeto de transacción DMA que representa la transferencia DMA que acaba de completarse.

[in] Device

Identificador del objeto de dispositivo de marco que especificó el controlador cuando llamó a WdfDmaTransactionCreate.

[in] Context

Puntero de contexto que el controlador especificó en una llamada anterior a WdfDmaTransactionSetTransferCompleteCallback.

[in] Direction

Valor de tipo WDF_DMA_DIRECTION que especifica la dirección de la operación de transferencia de DMA completa.

[in] Status

Valor de tipo DMA_COMPLETION_STATUS que especifica el estado de la transferencia.

Valor devuelto

None

Observaciones

El hardware de un dispositivo DMA maestro de bus normalmente emite una interrupción cuando se completa una transferencia DMA. A continuación, el controlador completa la transferencia de DMA en su función de devolución de llamada EvtInterruptDpc .

Sin embargo, el hardware de un dispositivo DMA en modo sistema no siempre señala la finalización de la transferencia DMA mediante la emisión de una interrupción. Para recibir una notificación de finalización de transferencia de DMA, un controlador para un dispositivo DMA en modo sistema puede registrar en su lugar una función de devolución de llamada de evento EvtDmaTransactionDmaTransferComplete llamando a WdfDmaTransactionSetTransferCompleteCallback.

El marco llama a EvtDmaTransactionDmaTransferComplete después de que el controlador DMA del sistema haya completado la transferencia, una vez para cada transferencia en una transacción.

Desde su devolución de llamada EvtDmaTransactionDmaTransferComplete , el controlador puede llamar a los métodos siguientes para notificar al marco que la transferencia se ha completado:

WdfDmaTransactionDmaCompletedWdfDmaTransactionDmaCompletedFinalWdfDmaTransactionDmaCompletedWithLength Es posible que el controlador no llame a uno de los métodos anteriores de EvtDmaTransactionDmaTransferComplete, optando por crear un objeto de temporizador o programar un DPC para completar la transferencia más adelante, según sea necesario. Después de que WdfDmaTransactionDmaCompletedXxx devuelva TRUE, lo que indica que no se necesitan más transferencias para completar la transacción DMA, el controlador puede llamar opcionalmente a WdfDmaTransactionExecute para iniciar una transacción posterior.

Si el controlador llama a WdfDmaTransactionStopSystemTransfer, el marco llama a EvtDmaTransactionDmaTransferComplete con un valor status de DmaCancelled. En este caso, el controlador debe llamar a WdfDmaTransactionDmaCompletedFinal desde evtDmaTransactionDmaTransferComplete y, a continuación, puede continuar con el procesamiento de solicitudes.

El controlador no debe manipular los búferes de datos asociados a la transacción hasta que WdfDmaTransactionDmaCompletedXxx haya devuelto TRUE.

El controlador puede llamar a WdfDmaTransactionRelease desde EvtDmaTransactionDmaTransferComplete si necesita finalizar la transacción DMA.

Para obtener más información sobre DMA en modo sistema, consulte Compatibilidad con DMA System-Mode.

Ejemplos

Para definir una función de devolución de llamada EvtDmaTransactionDmaTransferComplete , primero debe proporcionar una declaración de función que identifique el tipo de función de devolución de llamada que está definiendo. Windows proporciona un conjunto de tipos de función de devolución de llamada para controladores. Declarar una función mediante los tipos de función de devolución de llamada ayuda a Análisis de código para controladores, Comprobador de controladores estáticos (SDV) y otras herramientas de comprobación encuentran errores y es un requisito para escribir controladores para el sistema operativo Windows.

Por ejemplo, para definir una función de devolución de llamada EvtDmaTransactionDmaTransferComplete denominada MyDmaTransactionDmaTransferComplete, use el tipo de EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE como se muestra en este ejemplo de código:

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE  MyDmaTransactionDmaTransferComplete;

A continuación, implemente la función de devolución de llamada como se indica a continuación.


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

El tipo de función EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE se define en el archivo de encabezado WdfDmaTransaction.h. Para identificar con más precisión los errores al ejecutar las herramientas de análisis de código, asegúrese de agregar la anotación Use_decl_annotations a la definición de función. La anotación Use_decl_annotations garantiza que se usen las anotaciones que se aplican al tipo de función EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE en el archivo de encabezado. Para obtener más información sobre los requisitos de las declaraciones de función, consulte Declaración de funciones mediante tipos de rol de función para controladores KMDF. Para obtener información sobre Use_decl_annotations, consulte Anotación del comportamiento de la función.

Requisitos

Requisito Value
Cliente mínimo compatible Windows 8
Plataforma de destino Universal
Versión mínima de KMDF 1.11
Encabezado wdfdmatransaction.h (incluya Wdf.h)
IRQL DISPATCH_LEVEL

Consulte también

WdfDmaTransactionSetTransferCompleteCallback