드라이버에서 IOCTL 요청 만들기

클래스 드라이버 또는 기타 상위 수준 드라이버는 I/O 컨트롤 요청에 대해 IRP를 할당하고 다음과 같이 다음 하위 드라이버로 보낼 수 있습니다.

  1. 주 함수 코드 IRP_MJ_DEVICE_CONTROL 또는 IRP_MJ_INTERNAL_DEVICE_CONTROLIRP(I/O 요청 패킷)를 할당하거나 다시 사용합니다. IoBuildDeviceIoControlRequest 루틴을 사용하여 IOCTL IRP를 구체적으로 할당할 수 있습니다. IoAllocateIrp, IoReuseIrp 또는 IoInitializeIrp와 같은 범용 IRP 만들기 및 초기화 루틴을 사용할 수도 있습니다. IRP 할당에 대한 자세한 내용은 Lower-Level 드라이버용 IRP 만들기를 참조하세요.

  2. IOCTL_XXX 코드 및 적절한 매개 변수를 사용하여 IRP에 대한 낮은 드라이버의 I/O 스택 위치를 설정합니다.

  3. IOCTL 요청을 비동기적으로 완료하려면 KeInitializeEvent 루틴을 호출하여 이벤트 개체를 알림 이벤트로 초기화합니다. 드라이버는 이 이벤트를 사용하여 I/O 작업이 완료될 때까지 기다립니다.

  4. 필요한 경우 상위 드라이버에서 IoCompletion 루틴을 제공할 수 있도록 IRP를 사용하여 IoSetCompletionRoutine을 호출하여 다음을 수행합니다.

    • 하위 드라이버가 지정된 요청을 처리하는 방법을 결정합니다.

    • 낮은 드라이버가 요청된 작업을 완료한 후 IRP를 다시 사용하여 다른 요청을 보내거나 드라이버에서 만든 IRP를 삭제합니다. 드라이버는 IoBuildDeviceIoControlRequest 가 만든 IRP를 다시 사용할 수 없습니다. 자세한 내용은 IRP 재사용을 참조하세요.

  5. IoCallDriver를 호출하여 낮은 드라이버에 요청을 전달합니다.

  6. IoCallDriver가 STATUS_PENDING 반환하는 경우 KeWaitForSingleObject 루틴을 호출하여 현재 스레드를 대기 상태로 만듭니다. 드라이버는 루틴의 Object 매개 변수를 KeInitializeEvent 호출에서 초기화된 이벤트 개체의 주소로 설정합니다.

    참고 드라이버가 Timeout 매개 변수를 NULL로 설정하거나 0이 아닌 값이 포함된 변수의 주소로 KeWaitForSingleObject를 호출하는 경우 드라이버는 비항만 스레드 컨텍스트에서 IRQL <= APC_LEVEL 실행되어야 합니다. 그렇지 않으면 드라이버가 IRQL <= DISPATCH_LEVEL 실행 중이어야 합니다.

이 이벤트는 IOCTL 요청이 완료되면 IoCompletion 루틴에 의해 신호를 받습니다. 이벤트가 신호를 받으면 스레드는 실행을 다시 시작합니다.

중요 드라이버가 이벤트 개체를 스택의 지역 변수로 할당하는 경우 드라이버는 WaitMode 매개 변수가 KernelMode로 설정된 KeWaitForSingleObject를 호출해야 합니다. 이 매개 변수 값을 사용하면 스택이 페이징되지 않습니다.

동기화 문제 및 가능한 액세스 위반을 방지하기 위해 I/O 제어 코드의 매개 변수에는 포함된 포인터가 거의 포함되지 않습니다. 특정 SCSI 요청을 제외하고 Irp-ASSOCIATedIrp>의 버퍼입니다. SystemBuffer, Irp-MdlAddress> 및Parameters. DeviceIoControl. 드라이버의 I/O 스택 위치에 있는 Type3InputBuffer는 다른 데이터 버퍼에 대한 포인터를 포함하지 않으며 시스템 정의 I/O 컨트롤 코드에 대한 포인터를 포함하는 구조체도 포함하지 않습니다. I/O 컨트롤 코드가 포함된 IRP에서 데이터 버퍼를 사용하는 방법에 대한 자세한 내용은 I/O 컨트롤 코드에 대한 버퍼 설명을 참조하세요.

그럼에도 불구하고 내부 I/O 제어 코드를 정의하는 클래스/포트 드라이버 쌍은 상위 수준 드라이버에서 하위 수준 드라이버로 드라이버 할당 메모리에 대한 포함된 포인터를 전달할 수 있습니다. 이러한 클래스/포트 드라이버 쌍은 다음이 true인지 확인하는 역할을 합니다.

  • 한 번에 하나의 드라이버만 데이터에 액세스할 수 있습니다.

  • 프라이빗 데이터 버퍼는 포트 드라이버에 의해 임의의 스레드 컨텍스트에서 액세스할 수 있습니다.

디스플레이 드라이버는 GDI 함수 EngDeviceIoControl 을 호출하여 시스템 비디오 포트 드라이버를 통해 해당 어댑터별 비디오 미니포트 드라이버까지 시스템 정의 공용 I/O 제어 요청뿐만 아니라 개인적으로 정의된 디바이스별 I/O 제어 요청을 보낼 수 있습니다.

드라이버 패키지의 모든 사용자 모드 구성 요소는 DeviceIoControl 을 호출하여 드라이버 스택에 I/O 컨트롤 요청을 보낼 수 있습니다. I/O 관리자는 IRP_MJ_DEVICE_CONTROL 요청을 만들어 최상위 드라이버에 전달합니다.