WdfDmaTransactionStopSystemTransfer 함수(wdfdmatransaction.h)

[KMDF에만 적용]

WdfDmaTransactionStopSystemTransfer 메서드는 프레임워크가 EvtProgramDma를 호출한 후 시스템 모드 DMA 전송을 중지하려고 시도합니다.

구문

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

매개 변수

[in] DmaTransaction

초기화된 DMA 트랜잭션 개체에 대한 핸들입니다.

반환 값

없음

설명

시스템 모드 DMA를 사용하는 드라이버만 WdfDmaTransactionStopSystemTransfer를 호출해야 합니다.

버스 마스터링 DMA를 사용하는 드라이버는 자체 전용 DMA 컨트롤러를 프로그래밍합니다. 요청 취소, 시간 제한 또는 디바이스 오류가 발생하는 경우 드라이버는 DMA 컨트롤러를 프로그래밍하여 데이터 전송을 중지할 수 있습니다.

반면, 시스템 모드 DMA를 사용하는 드라이버는 HAL(하드웨어 추상화 계층)을 사용하여 공유 DMA 컨트롤러를 프로그래밍해야 합니다. 드라이버가 WdfDmaTransactionStopSystemTransfer를 호출할 때 프레임워크는 HAL에 전송을 중지하고 즉시 반환해야 한다고 알릴 수 있습니다.

프레임워크는 드라이버가 제공한 경우 드라이버의 EvtDmaTransactionDmaTransferComplete 콜백 함수를 호출합니다. 그렇지 않은 경우 프레임워크는 드라이버가 다음에 WdfDmaTransactionDmaCompleted를 호출할 때 FALSE를 반환합니다.

드라이버가 Windows 8 이전 운영 체제에서 이 메서드를 호출하는 경우 프레임워크의 검증 도구에서 오류를 보고합니다.

시스템 모드 DMA에 대한 자세한 내용은 지원 System-Mode DMA를 참조하세요.

DMA 트랜잭션 취소에 대한 자세한 내용은 DMA 트랜잭션 취소를 참조하세요.

예제

다음 코드 예제에서는 드라이버가 I/O 요청 시간이 초과될 경우 호출되도록 등록하는 EvtTimerFunc 이벤트 콜백 함수에서 WdfDmaTransactionStopSystemTransfer를 호출하는 방법을 보여 줍니다.

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

다음 코드 예제에서는 드라이버가 EvtRequestCancel 콜백 함수에서 WdfDmaTransactionStopSystemTransfer를 호출하는 방법을 보여 줍니다. 콜백을 등록하기 위해 I/O 요청 처리기에서 이전에 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

WdfDmaTransaction만들기