Bagikan melalui


EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE fungsi panggilan balik (wdfdmatransaction.h)

[Hanya berlaku untuk KMDF]

Fungsi panggilan balik peristiwa EvtDmaTransactionDmaTransferComplete driver dipanggil ketika pengontrol mode sistem telah menyelesaikan transfer DMA saat ini.

Sintaks

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE EvtWdfDmaTransactionDmaTransferComplete;

void EvtWdfDmaTransactionDmaTransferComplete(
  [in] WDFDMATRANSACTION Transaction,
  [in] WDFDEVICE Device,
  [in] WDFCONTEXT Context,
  [in] WDF_DMA_DIRECTION Direction,
  [in] DMA_COMPLETION_STATUS Status
)
{...}

Parameter

[in] Transaction

Handel ke objek transaksi DMA yang mewakili transfer DMA yang baru saja selesai.

[in] Device

Handel ke objek perangkat kerangka kerja yang ditentukan driver ketika disebut WdfDmaTransactionCreate.

[in] Context

Penunjuk konteks yang ditentukan driver dalam panggilan sebelumnya ke WdfDmaTransactionSetTransferCompleteCallback.

[in] Direction

Nilai WDF_DMA_DIRECTION-ketik yang menentukan arah operasi transfer DMA yang selesai.

[in] Status

Nilai DMA_COMPLETION_STATUS-typed yang menentukan status transfer.

Nilai kembali

Tidak ada

Keterangan

Perangkat keras untuk perangkat DMA master bus biasanya mengeluarkan gangguan ketika transfer DMA selesai. Driver kemudian menyelesaikan transfer DMA dalam fungsi panggilan balik EvtInterruptDpc .

Namun, perangkat keras untuk perangkat DMA mode sistem tidak selalu memberi sinyal penyelesaian transfer DMA dengan mengeluarkan gangguan. Untuk menerima pemberitahuan penyelesaian transfer DMA, driver untuk perangkat DMA mode sistem dapat mendaftarkan fungsi panggilan balik peristiwa EvtDmaTransactionDmaTransferComplete dengan memanggil WdfDmaTransactionSetTransferCompleteCallback.

Kerangka kerja memanggil EvtDmaTransactionDmaTransferComplete setelah pengontrol DMA sistem menyelesaikan transfer, sekali untuk setiap transfer dalam transaksi.

Dari dalam panggilan balik EvtDmaTransactionDmaTransferComplete , driver dapat memanggil metode berikut untuk memberi tahu kerangka kerja bahwa transfer telah selesai:

WdfDmaTransactionDmaCompletedWdfDmaTransactionDmaCompletedFinalWdfDmaTransactionDmaCompletedWithLength Driver mungkin tidak memanggil salah satu metode sebelumnya dari EvtDmaTransactionDmaTransferComplete, memilih untuk membuat objek timer atau menjadwalkan DPC untuk menyelesaikan transfer nanti, sesuai kebutuhan. Setelah WdfDmaTransactionDmaCompletedXxx mengembalikan TRUE, menunjukkan bahwa tidak ada lagi transfer yang diperlukan untuk menyelesaikan transaksi DMA, driver dapat secara opsional memanggil WdfDmaTransactionExecute untuk memulai transaksi berikutnya.

Jika driver memanggil WdfDmaTransactionStopSystemTransfer, kerangka kerja memanggil EvtDmaTransactionDmaTransferComplete dengan nilai StatusDmaCancelled. Dalam hal ini, driver harus memanggil WdfDmaTransactionDmaCompletedFinal dari dalam EvtDmaTransactionDmaTransferComplete, dan kemudian dapat melanjutkan pemrosesan permintaan.

Driver tidak boleh memanipulasi buffer data yang terkait dengan transaksi sampai setelah WdfDmaTransactionDmaCompletedXxx telah mengembalikan TRUE.

Driver dapat memanggil WdfDmaTransactionRelease dari dalam EvtDmaTransactionDmaTransferComplete jika perlu mengakhiri transaksi DMA.

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

Contoh

Untuk menentukan fungsi panggilan balik EvtDmaTransactionDmaTransferComplete , Anda harus terlebih dahulu memberikan deklarasi fungsi yang mengidentifikasi jenis fungsi panggilan balik yang Anda tentukan. Windows menyediakan sekumpulan tipe fungsi panggilan balik untuk driver. Mendeklarasikan fungsi menggunakan jenis fungsi panggilan balik membantu Analisis Kode untuk Driver, Pemverifikasi Driver Statis (SDV), dan alat verifikasi lainnya menemukan kesalahan, dan itu adalah persyaratan untuk menulis driver untuk sistem operasi Windows.

Misalnya, untuk menentukan fungsi panggilan balik EvtDmaTransactionDmaTransferComplete yang bernama MyDmaTransactionDmaTransferComplete, gunakan jenis EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE seperti yang ditunjukkan dalam contoh kode ini:

EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE  MyDmaTransactionDmaTransferComplete;

Kemudian, terapkan fungsi panggilan balik Anda sebagai berikut.


_Use_decl_annotations_
VOID
MyDmaTransactionDmaTransferComplete(
    WDFDMATRANSACTION Transaction,
    WDFDEVICE /* Device */,
    WDFCONTEXT Context,
    WDF_DMA_DIRECTION /* Direction */,
    DMA_COMPLETION_STATUS DmaStatus
    )
{
    PREQUEST_CONTEXT requestContext = (PREQUEST_CONTEXT) Context;
    NTSTATUS requestStatus;
    bool overrideStatus = true;
    size_t bytesTransferred;

    if (DmaStatus == DmaComplete) {
        //
        // Normal transfer completion.  Indicate this to the framework and see 
        // if there's more work to do.
        //
        if (WdfDmaTransactionDmaCompleted(Transaction, &requestStatus) == FALSE) {
            //
            // There are more DMA transfers to come.  The transaction 
            // may already have been completed on another processor.  
            // Return without touching it again.
            //
            goto exit;
        }

        requestStatus = STATUS_SUCCESS;
    }
    else {

        //
        // Complete the entire transaction.  But throw out the status and 
        // use one derived from the DmaStatus.
        //
        WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &requestStatus);        
        
        //
        // Error or cancellation.  Indicate that this was the final transfer to 
        // the framework.
        //
        if (DmaStatus == DmaError) {
            requestStatus = STATUS_DEVICE_DATA_ERROR;
        }
        else {

            //
            // Cancel status should only be triggered by timeout or cancel.  Rely on 
            // someone having already set the status, which means we should lose
            // the race for BeginCompletion below.
            //
            requestStatus = STATUS_PENDING;
            overrideStatus = false;
        }
    }

    //
    // Begin completion.  There's nothing special to do here if cancel or
    // timeout got there first.
    //
    BeginCompletion(requestContext, requestStatus, overrideStatus);

    //
    // Record the number of bytes we transferred.
    //
    bytesTransferred = WdfDmaTransactionGetBytesTransferred(
                        requestContext->DmaTransaction
                        );

    WdfRequestSetInformation(requestContext->Request, bytesTransferred);

    //
    // Success, error or cancel, this was the last transfer in the 
    // transaction.  Attempt to complete the request.
    //
    AttemptRequestCompletion(requestContext, true);

exit: 
    return;
}

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

Jenis fungsi EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE didefinisikan dalam file header WdfDmaTransaction.h. Untuk mengidentifikasi kesalahan secara lebih akurat saat Anda menjalankan alat analisis kode, pastikan untuk menambahkan anotasi Use_decl_annotations ke definisi fungsi Anda. Anotasi Use_decl_annotations memastikan bahwa anotasi yang diterapkan ke jenis fungsi EVT_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE dalam file header digunakan. Untuk informasi selengkapnya tentang persyaratan untuk deklarasi fungsi, lihat Mendeklarasikan Fungsi dengan Menggunakan Jenis Peran Fungsi untuk Driver KMDF. Untuk informasi tentang Use_decl_annotations, lihat Perilaku Fungsi Anotasi.

Persyaratan

Persyaratan Nilai
Klien minimum yang didukung Windows 8
Target Platform Universal
Versi KMDF minimum 1.11
Header wdfdmatransaction.h (termasuk Wdf.h)
IRQL DISPATCH_LEVEL

Lihat juga

WdfDmaTransactionSetTransferCompleteCallback