EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE função de retorno de chamada (wdfdmatransaction.h)

[Aplica-se somente ao KMDF]

A função de retorno de chamada de evento EvtDmaTransactionDmaTransferComplete de um driver é chamada quando o controlador do modo de sistema conclui a transferência de DMA atual.

Sintaxe

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

Um identificador para um objeto de transação DMA que representa a transferência de DMA que acabou de ser concluída.

[in] Device

Um identificador para o objeto de dispositivo de estrutura especificado pelo driver quando ele chamou WdfDmaTransactionCreate.

[in] Context

O ponteiro de contexto especificado pelo driver em uma chamada anterior para WdfDmaTransactionSetTransferCompleteCallback.

[in] Direction

Um valor de tipo WDF_DMA_DIRECTION que especifica a direção da operação de transferência de DMA de conclusão.

[in] Status

Um valor do tipo DMA_COMPLETION_STATUS que especifica o status da transferência.

Retornar valor

Nenhum

Comentários

O hardware de um dispositivo DMA master barramento normalmente emite uma interrupção quando uma transferência de DMA é concluída. Em seguida, o driver conclui a transferência de DMA em sua função de retorno de chamada EvtInterruptDpc .

No entanto, o hardware de um dispositivo DMA no modo de sistema nem sempre sinaliza a conclusão da transferência de DMA emitindo uma interrupção. Para receber a notificação da conclusão da transferência de DMA, um driver para um dispositivo DMA no modo sistema pode, em vez disso, registrar uma função de retorno de chamada de evento EvtDmaTransactionDmaTransferComplete chamando WdfDmaTransactionSetTransferCompleteCallback.

A estrutura chama EvtDmaTransactionDmaTransferComplete depois que o controlador de DMA do sistema concluir a transferência, uma vez para cada transferência em uma transação.

De dentro de seu retorno de chamada EvtDmaTransactionDmaTransferComplete , o driver pode chamar os seguintes métodos para notificar a estrutura que a transferência concluiu:

WdfDmaTransactionDmaCompletedWdfDmaTransactionDmaCompletedFinalWdfDmaTransactionDmaCompletedWithLength O driver pode não chamar um dos métodos anteriores de EvtDmaTransactionDmaTransferComplete, optando por criar um objeto de temporizador ou agendar um DPC para concluir a transferência mais tarde, conforme necessário. Depois que WdfDmaTransactionDmaCompletedXxx retornar TRUE, indicando que não são necessárias mais transferências para concluir a transação de DMA, o driver pode, opcionalmente, chamar WdfDmaTransactionExecute para iniciar uma transação subsequente.

Se o driver chamar WdfDmaTransactionStopSystemTransfer, a estrutura chamará EvtDmaTransactionDmaTransferComplete com um valor statusde DmaCancelled. Nesse caso, o driver deve chamar WdfDmaTransactionDmaCompletedFinal de dentro de EvtDmaTransactionDmaTransferComplete e, em seguida, pode continuar com o processamento da solicitação.

O driver não deve manipular os buffers de dados associados à transação até que WdfDmaTransactionDmaCompletedXxx tenha retornado TRUE.

O driver pode chamar WdfDmaTransactionRelease de dentro de EvtDmaTransactionDmaTransferComplete se precisar encerrar a transação de DMA.

Para obter mais informações sobre o DMA no modo de sistema, consulte Suporte System-Mode DMA.

Exemplos

Para definir uma função de retorno de chamada EvtDmaTransactionDmaTransferComplete , primeiro você deve fornecer uma declaração de função que identifique o tipo de função de retorno de chamada que você está definindo. O Windows fornece um conjunto de tipos de função de retorno de chamada para drivers. Declarar uma função usando os tipos de função de retorno de chamada ajuda a Análise de Código para Drivers, SDV ( Verificador de Driver Estático ) e outras ferramentas de verificação a encontrar erros e é um requisito para gravar drivers para o sistema operacional Windows.

Por exemplo, para definir uma função de retorno de chamada EvtDmaTransactionDmaTransferComplete chamada MyDmaTransactionDmaTransferComplete, use o tipo EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE conforme mostrado neste exemplo de código:

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE  MyDmaTransactionDmaTransferComplete;

Em seguida, implemente a função de retorno de chamada da seguinte maneira.


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

O tipo de função EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE é definido no arquivo de cabeçalho WdfDmaTransaction.h. Para identificar erros com mais precisão ao executar as ferramentas de análise de código, adicione a anotação Use_decl_annotations à sua definição de função. A anotação Use_decl_annotations garante que as anotações aplicadas ao tipo de função EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE no arquivo de cabeçalho sejam usadas. Para obter mais informações sobre os requisitos para declarações de função, consulte Declarando funções usando tipos de função de função para drivers KMDF. Para obter informações sobre Use_decl_annotations, consulte Anotando o comportamento da função.

Requisitos

Requisito Valor
Cliente mínimo com suporte Windows 8
Plataforma de Destino Universal
Versão mínima do KMDF 1.11
Cabeçalho wdfdmatransaction.h (inclua Wdf.h)
IRQL DISPATCH_LEVEL

Confira também

WdfDmaTransactionSetTransferCompleteCallback