Packet-Based DMA용 시스템 DMA 컨트롤러 설정

AllocateAdapterChannel이 제어를 드라이버의 AdapterControl 루틴으로 전송하는 경우 드라이버는 시스템 DMA 컨트롤러와 맵 레지스터 집합을 "소유"합니다. 그런 다음, 드라이버는 다음 그림과 같이 전송 작업을 위해 DMA 컨트롤러를 설정해야 합니다.

diagram illustrating programming the system dma controller.

드라이버에 StartIo 루틴이 있는 경우 AllocateAdapterChannelPIrp 매개 변수의 DeviceObject-CurrentIrp>에 대한 포인터를 AdapterControl 루틴에 전달합니다. 그러나 드라이버가 자체 IRP 큐를 관리하는 경우 드라이버는 AdapterControl에 전달하는 컨텍스트의 일부로 현재 IRP에 대한 포인터를 포함해야 합니다.

이전 그림과 같이 드라이버의 AdapterControl 루틴은 다음과 같이 DMA 전송을 설정합니다.

  1. AdapterControl 루틴은 전송을 시작할 주소를 가져옵니다. IRP를 충족하는 데 필요한 초기 전송의 경우 AdapterControl 루틴은 MmGetMdlVirtualAddress를 호출하여 이 DMA 전송에 대한 버퍼를 설명하는 Irp-MdlAddress>의 MDL에 대한 포인터를 전달합니다.

    MmGetMdlVirtualAddress 는 드라이버가 전송을 시작해야 하는 시스템 실제 주소의 인덱스로 사용할 수 있는 가상 주소를 반환합니다.

    IRP에 둘 이상의 전송 작업이 필요한 경우 드라이버는 이 섹션의 뒷부분에 설명된 대로 업데이트된 시작 주소를 계산합니다.

  2. AdapterControl 루틴은 MmGetMdlVirtualAddress에서 반환되거나 1단계에서 계산된 주소를 저장합니다. 이 주소는 MapTransfer에 필요한 매개 변수(CurrentVa)입니다.

  3. AdapterControl 루틴은 MapTransfer를 호출하여 시스템 DMA 컨트롤러를 설정하고 다음 매개 변수를 제공합니다.

    • IoGetDmaAdapter에서 반환된 어댑터 개체 포인터

    • 현재 IRP의 Irp-MdlAddress>에서 MDL에 대한 포인터(Mdl)

    • AllocateAdapterChannel에 의해 드라이버의 AdapterControl 루틴에 전달된 MapRegisterBase 핸들

    • IRP에 대한 MapTransfer에 대한 첫 번째 호출인 경우 MmGetMdlVirtualAddress에서 반환된 값(CurrentVa)

      그렇지 않으면 드라이버는 버퍼에서 다음 전송 작업을 시작해야 하는 위치를 나타내는 업데이트된 CurrentVa 값을 제공합니다.

    • 이 전송에 대한 바이트 수를 나타내는 변수(Length)에 대한 포인터입니다.

      드라이버가 MapTransfer 에 대한 단일 호출로 요청된 모든 데이터를 전송할 수 있고 해당 DMA 작업에 대한 디바이스별 제약 조건이 없는 경우 Length 는 드라이버의 IRP I/O 스택 위치에 있는 Length 값으로 설정할 수 있습니다. 최대 바이트 길이는 (PAGE_SIZE * IoGetDmaAdapter에서 반환된 NumberOfMapRegisters)일 수 있습니다. 그렇지 않으면 드라이버는 전송 요청 분할에 설명된 대로 요청을 분할해야 하며, 현재 IRP에 대한 MapTransfer에 대한 후속 호출에서 Length 값을 업데이트해야 합니다.

    • 전송 작업의 방향을 나타내는 부울 값(WriteToDevice)입니다(시스템 메모리에서 디바이스로 데이터를 전송하려면 TRUE).

    MapTransfer는 논리 주소를 반환합니다. 시스템 DMA를 사용하는 드라이버는 이 값을 무시해야 합니다.

  4. AdapterControl 루틴은 DMA 작업에 대한 디바이스를 설정합니다.

  5. AdapterControl 루틴은 KeepObject를 반환합니다.

디바이스가 현재 DMA 작업이 완료되었음을 나타내는 경우 드라이버는 일반적으로 드라이버의 DpcForIsr 루틴에서 FlushAdapterBuffers를 호출해야 합니다.

DMA 작업을 완료하는 DpcForIsr 루틴 또는 다른 드라이버 루틴은 FlushAdapterBuffers 를 호출하여 시스템 DMA 컨트롤러에 캐시된 모든 데이터를 시스템 메모리로 읽거나 디바이스에 기록하도록 합니다. 또한 현재 IRP에 대한 더 많은 데이터를 전송하기 위해 시스템 DMA 컨트롤러를 다시 프로그래밍해야 하는 경우에도 동일한 루틴에서 MapTransfer 를 다시 호출해야 합니다. 마찬가지로 각 전송 작업 후 FlushAdapterBuffers를 다시 호출해야 합니다.

드라이버가 현재 IRP에 대해 MapTransfer 를 두 번 이상 호출해야 하는 경우 모든 호출에서 동일한 어댑터 개체 포인터, Mdl 포인터, MapRegisterBase 핸들 및 전송 방향을 제공합니다. 그러나 드라이버는 MapTransfer에 대한 두 번째 및 후속 호출을 하기 전에 CurrentVaLength 매개 변수를 업데이트해야 합니다. 이러한 각 매개 변수에 대해 업데이트된 값을 계산하려면 다음 수식을 사용합니다.

  • CurrentVa = CurrentVa + (MapTransfer에 대한 이전 호출에서 요청된 길이)

  • Length = Minimum(전송할 남은 길이, (PAGE_SIZE * IoGetDmaAdapter에서 반환된 NumberOfMapRegisters))

각 드라이버가 DMA 전송에 대해 유지 관리해야 하는 컨텍스트 정보는 특정 디바이스의 요구 사항에 따라 달라집니다. 일반적인 컨텍스트에는 MDL(CurrentVa)의 현재 가상 주소, 지금까지 전송된 바이트 수, 전송할 남은 바이트 수, 현재 IRP에 대한 포인터 및 드라이버 작성기가 유용하다고 판단하는 기타 정보가 포함될 수 있습니다.

요청된 전송이 완료되거나 드라이버가 IRP에 대한 오류 상태를 반환해야 하는 경우 드라이버는 FreeAdapterChannel 을 즉시 호출하여 다른 드라이버 및 이 드라이버가 사용할 시스템 DMA 컨트롤러를 해제해야 합니다.