Compartir a través de


Función WdfDmaTransactionStopSystemTransfer (wdfdmatransaction.h)

[Solo se aplica a KMDF]

El método WdfDmaTransactionStopSystemTransfer intenta detener una transferencia DMA en modo sistema después de que el marco haya llamado a EvtProgramDma.

Sintaxis

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Parámetros

[in] DmaTransaction

Identificador de un objeto de transacción DMA inicializado.

Valor devuelto

Ninguno

Observaciones

Solo un controlador que use el modo del sistema DMA debe llamar a WdfDmaTransactionStopSystemTransfer.

Un controlador que usa la DMA de maestro de bus es responsable de programar su propio controlador DMA dedicado. En caso de que se produzca un error de cancelación, tiempo de espera o dispositivo de solicitud, el controlador puede programar el controlador DMA para detener la transferencia de datos.

Por el contrario, un controlador que use DMA en modo sistema debe confiar en la capa de abstracción de hardware (HAL) para programar el controlador DMA compartido. Cuando un controlador llama a WdfDmaTransactionStopSystemTransfer, el marco notifica a HAL que la transferencia se debe detener y devuelve inmediatamente.

A continuación, el marco llama a la evtDmaTransactionDmaTransferComplete del controlador función de devolución de llamada, si el controlador ha proporcionado uno. Si no es así, el marco devuelve FALSE cuando el controlador llama a WdfDmaTransactionDmaCompleted.

Si el controlador llama a este método en un sistema operativo anterior a Windows 8, el comprobador del marco notifica un error.

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

Para obtener más información sobre cómo cancelar transacciones DMA, vea Cancelar transacciones DMA.

Ejemplos

En el ejemplo de código siguiente se muestra cómo un controlador podría llamar a WdfDmaTransactionStopSystemTransfer desde un EvtTimerFunc función de devolución de llamada de eventos a la que se registra si se agota el tiempo de espera de una solicitud de E/S.

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

En el ejemplo de código siguiente se muestra cómo un controlador podría llamar a WdfDmaTransactionStopSystemTransfer desde una función de devolución de llamada EvtRequestCancel. El controlador anteriormente llamado WdfRequestMarkCancelableEx desde su controlador de solicitudes de E/S para registrar la devolución de llamada.

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 admitido Windows 8
de la plataforma de destino de Universal
versión mínima de KMDF 1.11
encabezado wdfdmatransaction.h (incluya Wdf.h)
Biblioteca Wdf01000.sys (consulte Control de versiones de la biblioteca de marcos).
irQL <=DISPATCH_LEVEL
reglas de cumplimiento de DDI DriverCreate(kmdf)

Consulte también

WdfDmaTransactionCancel

WdfDmaTransactionCreate