DMA 하드웨어 프로그래밍

[KMDF에만 적용]

이 항목에서는 버스 master DMA 디바이스의 KMDF 드라이버가 일반적으로 EvtProgramDma 이벤트 콜백 함수에서 제공하는 기능에 대해 설명합니다. 드라이버가 프레임워크의 DMA 지원을 사용하는 경우 드라이버는 이 콜백을 제공해야 합니다. 이 정보는 하드웨어 인터럽트(interrupt)가 있는 시스템 모드 DMA 디바이스 의 KMDF 드라이버에도 적용됩니다.

IRQL = DISPATCH_LEVEL 호출되는 EvtProgramDma 콜백 함수는 디바이스에서 DMA 전송을 시작하도록 프로그래밍합니다. 이 콜백 함수의 입력 매개 변수는 전송 방향(입력 또는 출력) 및 분산/수집 목록을 제공합니다. 전송이 단일 패킷으로 구성된 경우 분산/수집 목록에는 단일 요소가 포함됩니다.

EvtProgramDma 콜백 함수는 드라이버의 EvtDevicePrepareHardware 콜백 함수가 수신한 하드웨어 리소스를 사용하여 디바이스를 프로그래밍합니다. EvtProgramDma 콜백 함수가 하드웨어를 성공적으로 프로그래밍하면 TRUE가 반환됩니다.

하드웨어가 DMA 전송을 완료한 후 일반적으로 하드웨어는 인터럽트를 실행하고 시스템에서 드라이버의 EvtInterruptIsr 콜백 함수를 호출합니다. 드라이버의 EvtInterruptIsr 콜백 함수는 일반적으로 다음과 같습니다.

  • 하드웨어 인터럽트 지우기

  • 필요한 경우 인터럽트의 컨텍스트 정보를 저장합니다. 콜백 함수가 반환되고 시스템이 IRQL을 낮추면 이 정보가 손실될 수 있습니다(IRQL을 낮추면 추가 인터럽트 발생이 허용되기 때문).

  • WdfInterruptQueueDpcForIsr를 호출하여 EvtInterruptDpc 콜백 함수를 예약합니다.

EvtInterruptDpc 콜백 함수는 EvtInterruptIsr 콜백 함수가 저장한 컨텍스트 정보를 사용하여 DMA 전송을 완료합니다.

EvtProgramDma 콜백 함수가 오류를 감지하면 드라이버가 트랜잭션을 중지할 수 있습니다.

드라이버가 오류를 감지할 때 트랜잭션을 중지하려면 EvtProgramDma 콜백 함수는 다음을 수행해야 합니다.

  1. WdfDmaTransactionDmaCompletedFinal을 호출합니다.

  2. WdfObjectDelete를 호출하여 DMA 트랜잭션 개체를 삭제하거나 WdfDmaTransactionRelease를 호출하여 DMA 트랜잭션 개체를 해제하고 다시 사용합니다.

  3. 트랜잭션이 프레임워크 요청 개체와 연결된 경우 I/O 요청을 다시 큐에 넣기하거나 I/O 요청을 완료합니다. 요청에 대한 핸들을 검색하기 위해 드라이버는 WdfDmaTransactionGetRequest를 호출할 수 있습니다.

  4. FALSE를 반환 합니다.

1단계와 4단계는 Read.c 파일의 읽기 요청에 대한 PLX9x5x 샘플의 EvtProgramDma 콜백 함수에서 가져온 다음 코드 예제에 나와 있습니다.

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

이 예제에서는 PLxReadRequestComplete 함수를 호출하여 2단계와 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);

}