Bagikan melalui


Pemrograman Perangkat Keras DMA

[Berlaku untuk KMDF saja]

Topik ini menjelaskan fungsionalitas yang biasanya disediakan driver KMDF untuk perangkat DMA master bus dalam fungsi panggilan balik peristiwa EvtProgramDma . Jika driver Anda menggunakan dukungan DMA kerangka kerja, driver harus memberikan panggilan balik ini. Informasi ini juga berlaku untuk driver KMDF untuk perangkat DMA mode sistem yang mengalami gangguan perangkat keras.

Fungsi panggilan balik EvtProgramDma , yang disebut di IRQL = DISPATCH_LEVEL, memprogram perangkat untuk memulai transfer DMA. Parameter input untuk fungsi panggilan balik ini menyediakan arah transfer (input atau output) dan daftar sebar/kumpulkan. Jika transfer terdiri dari satu paket, daftar sebar/kumpulkan berisi satu elemen.

Fungsi panggilan balik EvtProgramDma memprogram perangkat dengan menggunakan sumber daya perangkat keras yang diterima fungsi panggilan balik EvtDevicePrepareHardware driver. Jika fungsi panggilan balik EvtProgramDma berhasil memprogram perangkat keras, fungsi tersebut mengembalikan TRUE.

Setelah perangkat keras menyelesaikan transfer DMA, biasanya perangkat keras mengeluarkan gangguan dan sistem memanggil fungsi panggilan balik EvtInterruptIsr driver. Fungsi panggilan balik EvtInterruptIsr driver biasanya:

  • Menghapus gangguan perangkat keras.

  • Menyimpan informasi konteks interupsi jika diperlukan. Informasi ini mungkin hilang setelah fungsi panggilan balik kembali dan sistem menurunkan IRQL (karena menurunkan IRQL memungkinkan gangguan tambahan terjadi).

  • Memanggil WdfInterruptQueueDpcForIsr untuk menjadwalkan fungsi panggilan balik EvtInterruptDpc .

Fungsi panggilan balik EvtInterruptDpcmenyelesaikan transfer DMA dengan menggunakan informasi konteks yang disimpan fungsi panggilan balik EvtInterruptIsr .

Jika fungsi panggilan balik EvtProgramDma mendeteksi kesalahan, driver dapat menghentikan transaksi.

Untuk menghentikan transaksi ketika driver mendeteksi kesalahan, fungsi panggilan balik EvtProgramDma harus:

  1. Panggil WdfDmaTransactionDmaCompletedFinal.

  2. Panggil WdfObjectDelete untuk menghapus objek transaksi DMA, atau panggil WdfDmaTransactionRelease untuk merilis dan menggunakan kembali objek transaksi DMA.

  3. Antre ulang permintaan I/O atau selesaikan permintaan I/O, jika transaksi dikaitkan dengan objek permintaan kerangka kerja. Untuk mengambil handel ke permintaan, driver dapat memanggil WdfDmaTransactionGetRequest.

  4. Mengembalikan FALSE.

Langkah 1 dan 4 diilustrasikan dalam contoh kode berikut, diambil dari fungsi panggilan balik EvtProgramDma sampel PLX9x5x untuk permintaan baca dalam file Read.c.

    // If errors occur in the EvtProgramDma callback,
    // release the DMA transaction object and complete the request.

    if (errors) {
        NTSTATUS status;

        //
        // Must abort the transaction before deleting.
        //
        (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status);
        ASSERT(NT_SUCCESS(status));

        PLxReadRequestComplete( Transaction, STATUS_INVALID_DEVICE_STATE );
        TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
                    "<-- PLxEvtProgramReadDma: errors ****");
        return FALSE;
    }

Contoh memanggil fungsi PLxReadRequestComplete untuk melakukan langkah 2 dan 3:

VOID
PLxReadRequestComplete(
    IN WDFDMATRANSACTION  DmaTransaction,
    IN NTSTATUS           Status
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/
{
    WDFREQUEST         request;
    size_t             bytesTransferred;

    //
    // Get the associated request from the transaction.
    //
    request = WdfDmaTransactionGetRequest(DmaTransaction);

    ASSERT(request);

    //
    // Get the final bytes transferred count.
    //
    bytesTransferred =  WdfDmaTransactionGetBytesTransferred( DmaTransaction );

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
                "PLxReadRequestComplete:  Request %p, Status %!STATUS!, "
                "bytes transferred %d\n",
                 request, Status, (int) bytesTransferred );

    WdfDmaTransactionRelease(DmaTransaction);

    //
    // Complete this Request.
    //
    WdfRequestCompleteWithInformation( request, Status, bytesTransferred);

}