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 トランザクションの取り消し」を参照してください。
例
次のコード例は、ドライバーが、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 |
Header | wdfdmatransaction.h (Wdf.h を含む) |
Library | Wdf01000.sys (「Framework ライブラリのバージョン管理」を参照)。 |
IRQL | <=DISPATCH_LEVEL |
DDI コンプライアンス規則 | DriverCreate(kmdf) |