버전 3 DMA 루틴에 대한 기본 호출 패턴
DMA 작업 인터페이스 버전 3의 루틴을 사용하는 DMA 전송을 수행하려면 드라이버가 다음 목록에 설명된 단계를 따라야 합니다. 이러한 단계는 하위 디바이스와 버스 master 디바이스 모두에 공통적으로 적용됩니다. 이 인터페이스의 버전 3은 Windows 8 시작해서 사용할 수 있습니다. 이 인터페이스의 루틴에 대한 자세한 내용은 DMA_OPERATIONS 참조하세요.
1단계: DMA 어댑터 개체 가져오기
DMA 전송을 준비하기 위해 드라이버는 IoGetDmaAdapter 루틴을 호출하여 DMA 어댑터 개체를 가져옵니다. DMA 어댑터 개체는 버스 master 디바이스 또는 시스템 DMA 컨트롤러의 요청 줄을 나타내는 소프트웨어 개체입니다. 이 개체에는 디바이스에서 데이터를 전송하는 데 사용되는 버스에 대한 DMA 작업 인터페이스가 포함되어 있습니다. 또한 이 개체는 전송을 수행하는 데 필요한 공유 리소스에 대한 드라이버의 액세스를 동기화합니다. 자세한 내용은 어댑터 개체 소개를 참조하세요.
2단계: 필요한 DMA 리소스에 대한 설명 가져오기
드라이버는 GetDmaTransferInfo 루틴을 호출하여 전송을 수행하는 데 필요한 DMA 리소스에 대한 설명을 가져옵니다.
이 호출의 입력 매개 변수는 전송에 사용할 메모리 버퍼와 전송 방향(읽기 또는 쓰기)을 설명합니다.
이 호출에서 얻은 리소스 요구 사항에는 맵 레지스터 수와 전송을 위한 데이터 버퍼를 설명하는 데 필요한 분산/수집 목록의 크기가 포함됩니다. AllocateAdapterChannelEx 루틴에 대한 후속 호출(3단계 참조)에서 드라이버는 맵 레지스터 수를 입력 매개 변수로 제공합니다.
3단계: 필요한 DMA 리소스 요청
드라이버는 AllocateAdapterChannelEx 루틴을 호출하여 DMA 어댑터 개체에 할당할 리소스를 할당합니다. 이러한 리소스에는 DMA 채널 및 맵 레지스터가 포함됩니다.
AllocateAdapterChannelEx 호출은 비동기 또는 동기적일 수 있습니다.
DMA_SYNCHRONOUS_CALLBACK 플래그가 설정되지 않은 경우 호출은 비동기적입니다. 이 경우 ExecutionRoutine 매개 변수는 요청된 리소스를 사용할 수 있을 때 호출되는 호출자가 제공한 실행 루틴을 가리킵니다. 성공하면 비동기 AllocateAdapterChannelEx 호출은 실행 루틴이 실행될 때까지 기다리지 않고 STATUS_SUCCESS 반환합니다.
DMA_SYNCHRONOUS_CALLBACK 플래그가 설정되면 AllocateAdapterChannelEx 호출이 동기적입니다. 이 경우 호출의 ExecutionRoutine 매개 변수는 선택 사항이며 AllocateAdapterChannelEx 는 다음과 같이 동작합니다.
ExecutionRoutine이 NULL이 아니고 DMA 리소스를 즉시 할당할 수 있는 경우 AllocateAdapterChannelEx는 호출 스레드의 컨텍스트에서 실행 루틴을 호출합니다. 실행 루틴 실행이 완료되면 AllocateAdapterChannelEx 는 STATUS_SUCCESS 반환합니다. 리소스를 즉시 사용할 수 없는 경우 AllocateAdapterChannelEx가 실패하고 코드 STATUS_INSUFFICIENT_RESOURCES 오류 상태 반환합니다.
ExecutionRoutine이 NULL이고 AllocateAdapterChannelEx가 DMA 리소스를 즉시 할당할 수 있는 경우 AllocateAdapterChannelEx는 STATUS_SUCCESS 반환합니다. 모든 리소스를 즉시 사용할 수 없는 경우 코드 STATUS_INSUFFICIENT_RESOURCES 오류 상태 호출이 실패합니다.
STATUS_SUCCESS 반환하는 동기 호출의 경우 AllocateAdapterChannelEx에 대한 MapRegisterBase 매개 변수가 NULL이 아닌 경우 AllocateAdapterChannelEx는 할당된 맵 레지스터의 기본 주소를 MapRegisterBase 매개 변수가 가리키는 주소에 씁니다. ExecutionRoutine이 NULL이면 MapRegisterBase는 NULL이 아니어야 합니다. ExecutionRoutine이 NULL이 아닌 경우 AllocateAdapterChannelEx에 대한 MapRegisterBase 매개 변수는 선택 사항이며, 실행 루틴은 맵 레지스터 기본 주소를 입력 매개 변수로 받습니다.
비동기 AllocateAdapterChannelEx 호출의 경우 ExecutionRoutine 은 NULL이 아니어야 하며 실행 루틴은 맵 레지스터 기본 주소를 입력 매개 변수로 받습니다.
MapTransferEx 루틴에 대한 후속 호출(5단계 참조)에서 드라이버는 맵 레지스터 기본 주소를 입력 매개 변수로 제공합니다.
ExecutionRoutine이 NULL이 아닌 경우 실행 루틴은 할당된 리소스의 처리를 나타내는 상태 값을 반환합니다. 시스템 DMA 전송의 경우 이 반환 값은 KeepObject여야 합니다. 이 값은 어댑터 개체(및 할당된 모든 리소스)가 사용 중이며 해제되어서는 안 됨을 운영 체제에 알릴 수 있습니다. 실행 루틴이 제공되지 않으면 드라이버는 FreeAdapterObject 루틴을 대신 호출하고 KeepObject 를 AllocationOption 매개 변수로 제공해야 합니다.
4단계: 필요한 경우 보류 중인 리소스 요청을 취소합니다.
AllocateAdapterChannelEx 호출이 DMA 어댑터를 큐에 대기하여 DMA 리소스를 기다린 후 드라이버는 필요한 경우 CancelAdapterChannel 루틴을 호출하여 보류 중인 리소스 요청을 취소할 수 있습니다.
CancelAdapterChannel이 TRUE를 반환하면 리소스 요청이 성공적으로 취소됩니다. AllocateAdapterChannelEx 호출에서 실행 루틴이 제공된 경우 이 루틴은 실행되지 않습니다.
CancelAdapterChannel이 FALSE를 반환하는 경우 리소스 요청이 이미 부여되었으므로 취소할 수 없습니다. AllocateAdapterChannelEx 호출에서 실행 루틴이 제공된 경우 이 루틴이 호출됩니다.
5단계: DMA 리소스 초기화 및 DMA 전송 시작
드라이버는 MapTransferEx 를 호출하여 DMA 리소스를 초기화하고 DMA 전송을 시작합니다. 이 호출은 AllocateAdapterChannelEx를 호출하는 동일한 드라이버 스레드에서 발생하거나 드라이버가 AllocateAdapterChannelEx에 제공하는 실행 루틴에서 발생할 수 있습니다. 전체 DMA 데이터 버퍼를 전송하기 위해 둘 이상의 MapTransferEx 호출이 필요한 경우 이전 MapTransferEx 호출에 대한 완료 루틴에서 나중에 MapTransferEx 호출이 발생할 수 있습니다.
MapTransferEx 는 연결된 MDL을 입력 매개 변수로 지원합니다. 각 MDL은 가상 메모리에서 연속되는 DMA 버퍼의 영역을 설명합니다. MapTransferEx가 분산/수집 목록을 빌드할 때 드라이버 개입 없이 가상으로 연속된 버퍼 영역 중 하나에서 다음으로의 전환을 자동으로 처리합니다. 자세한 내용은 MapTransferEx 루틴 사용을 참조하세요.
시스템 DMA 전송의 경우 DMA 완료 루틴에 대한 포인터를 선택적 DmaCompletionRoutine 매개 변수의 MapTransferEx에 전달할 수 있습니다. 이 루틴은 DMA 전송이 완료되었음을 나타내는 시스템 DMA 컨트롤러의 인터럽트 에 대한 응답으로 디스패치 수준에서 실행되도록 예약됩니다.
MapTransferEx가 요청된 전체 전송 크기를 매핑할 수 없는 경우 *Length 출력 매개 변수를 매핑된 길이로 설정하고 STATUS_SUCCESS 반환합니다.
6단계: 필요한 경우 하드웨어별 작업 수행
MapTransferEx는 STATUS_SUCCESS 반환하여 DMA 전송이 성공적으로 시작되었음을 나타냅니다. 일부 플랫폼에서는 드라이버가 전송을 시작하기 위해 MapTransferEx 호출 외부에서 몇 가지 추가 작업을 수행해야 할 수 있지만 이러한 유형의 지연된 시작은 모든 플랫폼에 필요하지 않습니다. 드라이버는 할당된 리소스 사용 및 해제에 대한 결정을 위해 이러한 지연에 의존해서는 안 됩니다.
DMA 작업 인터페이스의 루틴은 이러한 루틴을 사용하는 드라이버에 투명한 방식으로 DMA 전송에 대한 캐시 일관성을 유지합니다. 하드웨어에서 캐시 일관성을 적용하지 않는 플랫폼에서 MapTransferEx 는 쓰기(메모리-디바이스) 전송 전에 프로세서 데이터 캐시가 플러시되도록 합니다. 읽기(디바이스-메모리) 전송의 경우 모든 MapTransferEx 호출을 따르는 FlushAdapterBuffersEx 루틴(8단계 참조)을 호출하는 동안 캐시가 무효화됩니다.
7단계: DMA 전송이 완료되면 알림 받기
DMA 전송이 완료되면 드라이버는 다음 두 가지 방법 중 하나로 알림을 받습니다.
- 버스 master 디바이스의 디바이스 드라이버 인터럽트
- 시스템 DMA 컨트롤러를 사용하는 하위 디바이스의 드라이버 제공 완료 루틴 실행
시스템 DMA 전송의 경우 드라이버는 MapTransferEx 에 완료 루틴을 입력 매개 변수로 제공할 수 있습니다.
8단계: 캐시에 남아 있는 모든 데이터 플러시
DMA 전송이 완료되면 드라이버는 FlushAdapterBuffersEx 루틴을 호출하여 캐시에 남아 있는 모든 데이터를 플러시해야 합니다. 드라이버는 MapTransferEx 호출 후 FlushAdapterBuffersEx를 호출해야 합니다.
MapTransferEx 호출이 DMA 데이터 버퍼의 일부만 매핑하는 경우 드라이버는 MapTransferEx를 다시 호출하여 나머지 데이터를 매핑해야 합니다. 복잡한 전송에는 여러 MapTransferEx 호출이 필요할 수 있습니다. 각 추가 MapTransferEx 호출에 대해 5~8단계를 반복합니다.
9단계: DMA 채널 및 지도 레지스터 해제
전체 DMA 데이터 버퍼가 성공적으로 매핑되고 최종 전송이 완료되면 드라이버는 FreeAdapterChannel 루틴을 호출하여 DMA 채널과 이전에 할당된 모든 맵 레지스터를 해제해야 합니다.
10단계: DMA 어댑터 개체 해제
모든 DMA 전송이 완료되고 이전에 할당된 맵 레지스터가 해제되면 드라이버는 PutDmaAdapter 루틴을 호출하여 어댑터 개체를 해제합니다.