Fungsi WdfDmaTransactionStopSystemTransfer (wdfdmatransaction.h)

[Hanya berlaku untuk KMDF]

Metode WdfDmaTransactionStopSystemTransfer mencoba menghentikan transfer DMA mode sistem setelah kerangka kerja disebut EvtProgramDma.

Sintaks

void WdfDmaTransactionStopSystemTransfer(
  [in] WDFDMATRANSACTION DmaTransaction
);

Parameter

[in] DmaTransaction

Handel ke objek transaksi DMA yang diinisialisasi.

Nilai kembali

Tidak ada

Keterangan

Hanya driver yang menggunakan DMA mode sistem yang harus memanggil WdfDmaTransactionStopSystemTransfer.

Pengemudi yang menggunakan DMA yang menguasai bus bertanggung jawab untuk memprogram pengontrol DMA khususnya sendiri. Jika terjadi pembatalan permintaan, waktu habis, atau kesalahan perangkat, driver dapat memprogram pengontrol DMA untuk berhenti mentransfer data.

Sebaliknya, driver yang menggunakan DMA mode sistem harus mengandalkan lapisan abstraksi perangkat keras (HAL) untuk memprogram pengontrol DMA bersama. Ketika driver memanggil WdfDmaTransactionStopSystemTransfer, kerangka kerja memberi tahu HAL bahwa transfer harus segera dihentikan dan dikembalikan.

Kerangka kerja berikutnya memanggil fungsi panggilan balik EvtDmaTransactionDmaTransferComplete driver, jika driver telah menyediakannya. Jika tidak, kerangka kerja mengembalikan FALSE saat driver berikutnya memanggil WdfDmaTransactionDmaCompleted.

Jika driver Anda memanggil metode ini pada sistem operasi yang lebih awal dari Windows 8, pemverifikasi kerangka kerja melaporkan kesalahan.

Untuk informasi selengkapnya tentang DMA mode sistem, lihat Mendukung System-Mode DMA.

Untuk informasi selengkapnya tentang membatalkan transaksi DMA, lihat Membatalkan Transaksi DMA.

Contoh

Contoh kode berikut menunjukkan bagaimana driver mungkin memanggil WdfDmaTransactionStopSystemTransfer dari fungsi panggilan balik peristiwa EvtTimerFunc yang terdaftar untuk dipanggil jika waktu permintaan I/O habis.

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

Contoh kode berikut menunjukkan bagaimana driver mungkin memanggil WdfDmaTransactionStopSystemTransfer dari fungsi panggilan balik EvtRequestCancel . Driver yang sebelumnya disebut WdfRequestMarkCancelableEx dari handler permintaan I/O-nya untuk mendaftarkan panggilan balik.

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

Persyaratan

Persyaratan Nilai
Klien minimum yang didukung Windows 8
Target Platform Universal
Versi KMDF minimum 1.11
Header wdfdmatransaction.h (termasuk Wdf.h)
Pustaka Wdf01000.sys (lihat Penerapan Versi Pustaka Kerangka Kerja.)
IRQL <=DISPATCH_LEVEL
Aturan kepatuhan DDI DriverCreate(kmdf)

Lihat juga

WdfDmaTransactionCancel

WdfDmaTransactionCreate