다음을 통해 공유


Common-Buffer 시스템 DMA 사용

시스템 DMA 컨트롤러의 자동 초기화 모드를 사용하는 드라이버는 DMA 전송을 수행할 수 있는 버퍼에 대한 메모리를 할당해야 합니다. 드라이버는 AllocateCommonBuffer를 호출하여 일반적으로 IRP_MN_START_DEVICE 요청을 처리하는 DispatchPnP 루틴에서 이 버퍼를 가져옵니다. 다음 그림에서는 드라이버가 버퍼를 할당하고 가상 주소 범위를 시스템 실제 메모리에 매핑하는 방법을 보여 줍니다.

드라이버가 시스템 dma에 대한 공통 버퍼를 할당하는 방법을 보여 주는 다이어그램

이전 그림과 같이 드라이버는 시스템 DMA에 대한 버퍼를 할당하기 위해 다음 단계를 수행합니다.

  1. 드라이버는 AllocateCommonBuffer를 호출하여 IoGetDmaAdapter에서 반환된 어댑터 개체에 대한 포인터와 버퍼에 대해 요청된 길이(바이트)를 전달합니다. 메모리를 경제적으로 사용하려면 버퍼의 입력 길이 값이 PAGE_SIZE 작거나 같거나 PAGE_SIZE 정수 배수여야 합니다.

  2. AllocateCommonBufferNULL 포인터를 반환하는 경우 드라이버는 이미 요청한 시스템 리소스를 해제하고 IRP_MN_START_DEVICE 요청에 대한 응답으로 STATUS_INSUFFICIENT_RESOURCES 반환해야 합니다.

    그렇지 않으면 AllocateCommonBuffer 는 시스템 가상 주소 공간에서 요청된 메모리 양을 할당하고 해당 버퍼에 두 가지 유형의 포인터를 반환합니다.

    • 버퍼의 LogicalAddress (이전 그림의 BufferLogicalAddress)이며, 드라이버가 스토리지를 제공해야 하지만 그 이후에는 무시해야 합니다.

    • DMA 작업에 대한 버퍼를 설명하는 MDL을 빌드할 수 있도록 드라이버가 저장해야 하는 버퍼의 가상 주소(이전 그림의 BufferVirtualAddress)입니다.

    드라이버는 이러한 포인터를 디바이스 확장 또는 다른 드라이버 할당 상주 메모리에 저장해야 합니다.

  3. 드라이버는 IoAllocateMdl 을 호출하여 버퍼에 대한 MDL을 할당합니다. 드라이버는 AllocateCommonBuffer에서 반환된 버퍼의 VirtualAddress와 해당 버퍼의 길이를 전달하여 MDL을 할당합니다.

  4. 드라이버는 IoAllocateMdl에서 반환된 포인터를 사용하여 MmBuildMdlForNonPagedPool을 호출하여 상주 버퍼의 가상 주소 범위를 시스템 실제 메모리에 매핑합니다.

공통 버퍼를 할당하고 가상 주소 범위를 매핑한 후 하위 디바이스의 드라이버는 DMA 전송을 요청하는 IRP 처리를 시작할 수 있습니다. 이를 위해 드라이버는 다음과 같은 일반적인 지원 루틴 시퀀스를 호출합니다.

  1. 드라이버 작성자의 재량에 따라 RtlMoveMemory 는 잠긴 사용자 버퍼에서 디바이스로 전송하기 위해 드라이버 할당 공통 버퍼로 데이터를 복사합니다.

  2. 드라이버가 DMA용 디바이스를 프로그래밍할 준비가 되었으며 시스템 DMA 컨트롤러가 필요한 경우 AllocateAdapterChannel

  3. MapTransfer는 드라이버 할당 공통 버퍼를 설명하는 MDL을 사용하여 전송 작업에 대한 시스템 DMA 컨트롤러를 설정합니다.

    드라이버는 MapTransfer를 한 번만 호출하여 공통 버퍼를 사용하도록 시스템 DMA 컨트롤러를 설정합니다. 전송하는 동안 드라이버는 ReadDmaCounter 를 호출하여 전송할 남은 바이트 수를 확인하고 필요한 경우 RtlMoveMemory 를 호출하여 사용자 버퍼와 더 많은 데이터를 복사할 수 있습니다.

  4. 드라이버가 종속 디바이스에 대한 DMA 전송을 완료한 경우 FlushAdapterBuffers

  5. 요청된 모든 데이터가 전송되는 즉시 또는 디바이스 I/O 오류로 인해 드라이버가 IRP에 실패해야 하는 경우 FreeAdapterChannel

IoGetDmaAdapter에서 반환된 어댑터 개체 포인터는 RtlMoveMemory를 제외한 이러한 각 지원 루틴에 필요한 매개 변수입니다.

개별 드라이버는 각 드라이버가 디바이스를 서비스하기 위해 구현되는 방법에 따라 서로 다른 지점에서 이 일련의 지원 루틴을 호출합니다. 예를 들어 한 드라이버의 StartIo 루틴이 AllocateAdapterChannel을 호출할 수 있고, 다른 드라이버는 드라이버에서 만든 연동 큐에서 IRP를 제거하는 루틴에서 이 호출을 수행할 수 있으며, 다른 드라이버는 하위 DMA 디바이스가 데이터를 전송할 준비가 되었음을 나타낼 때 이 호출을 수행할 수 있습니다.