Função WdfDmaTransactionStopSystemTransfer (wdfdmatransaction.h)

[Aplica-se somente ao KMDF]

O método WdfDmaTransactionStopSystemTransfer tenta interromper uma transferência de DMA no modo sistema depois que a estrutura tiver chamado EvtProgramDma.

Sintaxe

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Parâmetros

[in] DmaTransaction

Um identificador para um objeto de transação DMA inicializado.

Retornar valor

Nenhum

Comentários

Somente um driver que usa o DMA do modo de sistema deve chamar WdfDmaTransactionStopSystemTransfer.

Um driver que usa o DMA de domínio de barramento é responsável por programar seu próprio controlador de DMA dedicado. No caso de um cancelamento de solicitação, tempo limite ou erro de dispositivo, o driver pode programar o controlador de DMA para interromper a transferência de dados.

Por outro lado, um driver que usa o DMA no modo de sistema deve contar com a HAL (camada de abstração de hardware) para programar o controlador de DMA compartilhado. Quando um driver chama WdfDmaTransactionStopSystemTransfer, a estrutura notifica o HAL de que a transferência deve ser interrompida e retorna imediatamente.

A estrutura em seguida chama a função de retorno de chamada EvtDmaTransactionDmaTransferComplete do driver, se o driver tiver fornecido um. Caso contrário, a estrutura retornará FALSE quando o driver chamar WdfDmaTransactionDmaCompleted.

Se o driver chamar esse método em um sistema operacional anterior a Windows 8, o verificador da estrutura relatará um erro.

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

Para obter mais informações sobre como cancelar transações de DMA, consulte Cancelando transações de DMA.

Exemplos

O exemplo de código a seguir mostra como um driver pode chamar WdfDmaTransactionStopSystemTransfer de uma função de retorno de chamada de evento EvtTimerFunc que ele registra para ser chamado se uma solicitação de E/S atingir o tempo limite.

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

O exemplo de código a seguir mostra como um driver pode chamar WdfDmaTransactionStopSystemTransfer de uma função de retorno de chamada EvtRequestCancel . O driver anteriormente chamado WdfRequestMarkCancelableEx de seu manipulador de solicitação de E/S para registrar o retorno de chamada.

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

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)
Biblioteca Wdf01000.sys (consulte Controle de versão da biblioteca de estrutura.)
IRQL <=DISPATCH_LEVEL
Regras de conformidade de DDI DriverCreate(kmdf)

Confira também

WdfDmaTransactionCancel

WdfDmaTransactionCreate