次の方法で共有


WdfDmaTransactionStopSystemTransfer 関数 (wdfdmatransaction.h)

[KMDF にのみ適用]

WdfDmaTransactionStopSystemTransfer メソッドは、フレームワークが EvtProgramDma 呼び出した後、システム モード DMA 転送を停止しようとします。

構文

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

パラメーター

[in] DmaTransaction

初期化された DMA トランザクション オブジェクトへのハンドル。

戻り値

なし

注釈

システム モード DMA を使用するドライバーのみが WdfDmaTransactionStopSystemTransfer 呼び出す必要があります。

バス マスタリング DMA を使用するドライバーは、独自の専用 DMA コントローラーのプログラミングを担当します。 要求の取り消し、タイムアウト、またはデバイス エラーが発生した場合、ドライバーは DMA コントローラーをプログラミングしてデータの転送を停止できます。

これに対し、システム モード DMA を使用するドライバーは、共有 DMA コントローラーをプログラムするためにハードウェア抽象化レイヤー (HAL) に依存する必要があります。 ドライバーが WdfDmaTransactionStopSystemTransfer 呼び出すと、フレームワークは、転送を停止する必要があることを HAL に通知し、すぐに戻ります。

フレームワークは次に、ドライバーの EvtDmaTransactionDmaTransferComplete コールバック関数を呼び出します (ドライバーがコールバック関数を提供している場合)。 そうでない場合、ドライバーが次に WdfDmaTransactionDmaCompleted 呼び出すと、フレームワークは FALSE を返します。

ドライバーが Windows 8 より前のオペレーティング システムでこのメソッドを呼び出す場合は、フレームワークの検証ツールを エラーが報告されます。

システム モード DMA の詳細については、「System-Mode DMAのサポート」を参照してください。

DMA トランザクションの取り消しの詳細については、「DMA トランザクションの取り消し」を参照してください。

例示

次のコード例は、ドライバーが、EvtTimerFunc イベント コールバック関数から WdfDmaTransactionStopSystemTransfer を呼び 出し、I/O 要求がタイムアウトした場合に呼び出されるように登録する方法を示しています。

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

WdfDmaTransactionCreate