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 EvtProgramDma.

Sintaxis

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Parámetros

[in] DmaTransaction

Identificador de un objeto de transacción DMA inicializado.

Valor devuelto

None

Observaciones

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

Un controlador que usa DMA bus-mastering 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 basarse en la capa de abstracción de hardware (HAL) para programar el controlador DMA compartido. Cuando un controlador llama a WdfDmaTransactionStopSystemTransfer, el marco notifica al HAL que la transferencia se debe detener y devolver inmediatamente.

A continuación, el marco llama a la función de devolución de llamada EvtDmaTransactionDmaTransferComplete del controlador, 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, consulte Compatibilidad con DMA System-Mode.

Para obtener más información sobre cómo cancelar transacciones de DMA, consulte Cancelación de transacciones DMA.

Ejemplos

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 de evento EvtTimerFunc 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 solicitud 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 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)
Library 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