Функция WdfDmaTransactionStopSystemTransfer (wdfdmatransaction.h)

[Относится только к KMDF]

Метод WdfDmaTransactionStopSystemTransfer пытается остановить передачу DMA в системном режиме после того, как платформа вызвала EvtProgramDma.

Синтаксис

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Параметры

[in] DmaTransaction

Дескриптор инициализированного объекта транзакции DMA.

Возвращаемое значение

None

Remarks

Только драйвер, использующий системный режим DMA, должен вызывать WdfDmaTransactionStopSystemTransfer.

Драйвер, использующий DMA для шины, отвечает за программирование собственного выделенного контроллера DMA. В случае отмены запроса, истечения времени ожидания или ошибки устройства драйвер может запрограммировать контроллер DMA, чтобы остановить передачу данных.

В отличие от этого, драйвер, использующий DMA в системном режиме, должен полагаться на уровень аппаратной абстракции (HAL) для программирования общего контроллера DMA. Когда драйвер вызывает WdfDmaTransactionStopSystemTransfer, платформа уведомляет HAL о том, что передача должна быть остановлена и немедленно возвращается.

Затем платформа вызывает функцию обратного вызова EvtDmaTransactionDmaTransferComplete драйвера, если драйвер предоставил ее. В противном случае платформа возвращает значение FALSE, когда драйвер вызывает WdfDmaTransactionDmaCompleted.

Если драйвер вызывает этот метод в операционной системе до Windows 8, средство проверки платформы сообщает об ошибке.

Дополнительные сведения о системном режиме DMA см. в разделе Поддержка System-Mode DMA.

Дополнительные сведения об отмене транзакций DMA см. в разделе Отмена транзакций DMA.

Примеры

В следующем примере кода показано, как драйвер может вызывать WdfDmaTransactionStopSystemTransfer из функции обратного вызова события EvtTimerFunc , которую он регистрирует для вызова, если истекает время ожидания запроса ввода-вывода.

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

В следующем примере кода показано, как драйвер может вызывать WdfDmaTransactionStopSystemTransfer из функции обратного вызова EvtRequestCancel . Драйвер ранее вызывал WdfRequestMarkCancelableEx из обработчика запросов ввода-вывода для регистрации обратного вызова.

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

Требования

Требование Значение
Минимальная версия клиента Windows 8
Целевая платформа Универсальное
Минимальная версия KMDF 1.11
Верхняя часть wdfdmatransaction.h (включая Wdf.h)
Библиотека Wdf01000.sys (см. раздел Управление версиями библиотеки Платформы).
IRQL <=DISPATCH_LEVEL
Правила соответствия DDI DriverCreate(kmdf)

См. также раздел

WdfDmaTransactionCancel

WdfDmaTransactionCreate