다음을 통해 공유


전원 IRP 전달

전원 전환이 깔끔하게 관리되도록 하려면 전원 IRP를 디바이스 스택 아래로 PDO로 전달해야 합니다. 드라이버는 IRP가 디바이스 스택 아래로 이동함에 따라 디바이스 전원을 줄이는 IRP를 처리합니다. 드라이버는 IRP가 디바이스 스택을 다시 이동할 때 IoCompletion 루틴에서 디바이스 전원을 적용하는 IRP를 처리합니다.

다음 그림에서는 Windows 7 및 Windows Vista의 디바이스 스택에서 전원 IRP를 전달하기 위해 드라이버가 수행해야 하는 단계를 보여 있습니다.

windows vista에서 전원 irp를 전달하는 것을 보여 주는 다이어그램

이전 그림과 같이 Windows 7 및 Windows Vista에서 드라이버는 다음을 수행해야 합니다.

  1. IoCompletion 루틴을 설정하는 경우 IoCopyCurrentIrpStackLocationToNext를 호출하거나, IoCompletion 루틴을 설정하지 않으면 IoSkipCurrentIrpStackLocation을 호출합니다.

    이러한 두 루틴은 다음 하위 드라이버에 대한 IRP 스택 위치를 설정합니다. 현재 스택 위치를 복사하면 IoCompletion 루틴이 실행될 때 IRP 스택 포인터가 올바른 위치로 설정됩니다.

    잘못 작성된 드라이버가 IoSkipCurrentIrpStackLocation 을 호출한 다음 완료 루틴을 설정하는 실수를 하는 경우 이 드라이버는 아래 드라이버에서 설정한 완료 루틴을 덮어쓸 수 있습니다.

  2. 완전한 루틴이 필요한 경우 IoSetCompletionRoutine 을 호출하여 IoCompletion 루틴을 설정합니다.

  3. IoCallDriver를 호출하여 IRP를 스택의 다음 하위 드라이버에 전달합니다.

다음 그림에서는 Windows Server 2003, Windows XP 및 Windows 2000에서 디바이스 스택에 전원 IRP를 전달하기 위해 드라이버가 수행해야 하는 단계를 보여 있습니다.

전원 irp(windows server 2003, windows xp 및 windows 2000)를 전달합니다.

이전 그림과 같이 드라이버는 다음을 수행해야 합니다.

  1. 드라이버 유형에 따라 PoStartNextPowerIrp를 호출할 수 있습니다. 자세한 내용은 PoStartNextPowerIrp 호출을 참조하세요.

  2. IoCompletion 루틴을 설정하는 경우 IoCopyCurrentIrpStackLocationToNext를 호출하거나, IoCompletion 루틴을 설정하지 않으면 IoSkipCurrentIrpStackLocation을 호출합니다.

    이러한 두 루틴은 다음 하위 드라이버에 대한 IRP 스택 위치를 설정합니다. 현재 스택 위치를 복사하면 IoCompletion 루틴이 실행될 때 IRP 스택 포인터가 올바른 위치로 설정됩니다.

  3. IoSetCompletionRoutine을 호출하여 IoCompletion 루틴을 설정합니다. IoCompletion 루틴에서 대부분의 드라이버는 PoStartNextPowerIrp를 호출하여 다음 전원 IRP를 처리할 준비가 되었음을 나타냅니다.

  4. PoCallDriver를 호출하여 IRP를 스택의 다음 하위 드라이버에 전달합니다.

    드라이버는 시스템이 전원 IRP를 제대로 동기화하도록 IoCallDriver 대신 PoCallDriver(다른 IRP)를 사용해야 합니다. 자세한 내용은 IoCallDriver 호출 및 PoCallDriver 호출을 참조하세요.

IRQL = DISPATCH_LEVEL IoCompletion 루틴을 호출할 수 있습니다. 따라서 하위 수준 드라이버가 IRP를 완료한 후 드라이버가 IRQL = PASSIVE_LEVEL 추가 처리가 필요한 경우 드라이버의 완료 루틴은 작업 항목을 큐에 대기한 다음 STATUS_MORE_PROCESSING_REQUIRED 반환해야 합니다. 작업자 스레드는 IRP를 완료해야 합니다.

Windows 98/Me에서 드라이버는 IRQL = PASSIVE_LEVEL 전원 IRP를 완료해야 합니다.

Power IRP에서 함수 코드를 변경하지 마세요.

IRP 처리를 제어하는 일반적인 규칙 외에도 IRP_MJ_POWER IRP에는 다음과 같은 특별한 요구 사항이 있습니다. 전원 IRP를 수신하는 드라이버는 전원 관리자 또는 상위 수준 드라이버에 의해 설정된 IRP의 모든 I/O 스택 위치에서 주 함수 및 부 함수 코드를 변경해서는 안 됩니다. 전원 관리자는 IRP가 완료될 때까지 변경되지 않은 상태로 유지되는 이러한 함수 코드를 사용합니다. 이 규칙을 위반하면 디버그하기 어려운 문제가 발생할 수 있습니다. 예를 들어 운영 체제가 응답을 중지하거나 "중단"할 수 있습니다.

전원 IRP를 처리하는 동안 차단 안 함

드라이버는 전원 IRP를 처리하는 동안 긴 지연을 일으키지 않아야 합니다.

전원 IRP를 전달할 때 드라이버는 IoCallDriver(Windows 7 및 Windows Vista) 또는 PoCallDriver(Windows Server 2003, Windows XP 및 Windows 2000)를 호출한 후 최대한 빨리 DispatchPower 루틴에서 돌아와야 합니다. 드라이버는 커널 이벤트를 기다리거나 반환하기 전에 지연하면 안됩니다. 드라이버가 짧은 시간 안에 전원 IRP를 처리할 수 없는 경우 STATUS_PENDING 반환하고 전원 IRP가 완료될 때까지 들어오는 모든 IRP를 큐에 대기시켜야 합니다. (이 동작은 차단할 수 있는 PnP IRP 및 DispatchPnP 루틴의 동작과 다릅니다.)

드라이버가 디바이스 스택 아래로 다른 드라이버의 전원 작업을 기다려야 하는 경우 DispatchPower 루틴에서 STATUS_PENDING 반환하고 전원 IRP에 대한 IoCompletion 루틴을 설정해야 합니다. 드라이버는 IoCompletion 루틴에서 필요한 작업을 수행한 다음 PoStartNextPowerIrp (Windows Server 2003, Windows XP 및 Windows 2000에만 해당) 및 IoCompleteRequest를 호출할 수 있습니다.

예를 들어 디바이스의 전원 정책 소유자는 일반적으로 요청된 시스템 전원 상태에 적합한 디바이스 전원 상태를 설정하기 위해 시스템 전원 IRP를 보유하는 동안 디바이스 전원 IRP를 보냅니다.

이 경우 전원 정책 소유자는 시스템 전원 IRP에서 IoCompletion 루틴을 설정하고, 시스템 전원 IRP를 다음 하위 드라이버에 전달하고, DispatchPower 루틴에서 STATUS_PENDING 반환해야 합니다.

IoCompletion 루틴에서는 PoRequestPowerIrp를 호출하여 디바이스 전원 IRP를 보내고 요청의 콜백 루틴에 대한 포인터를 전달합니다. IoCompletion 루틴은 STATUS_MORE_PROCESSING_REQUIRED 반환해야 합니다.

마지막으로 드라이버는 콜백 루틴에서 시스템 IRP를 전달합니다. 드라이버는 DispatchPower 루틴에서 커널 이벤트를 기다리지 않아야 하며 현재 처리 중인 IRP에 대한 IoCompletion 루틴으로 신호를 보내면 안됩니다. 시스템 교착 상태가 발생할 수 있습니다. 자세한 내용은 디바이스 전원 정책 소유자에서 시스템 Set-Power IRP 처리를 참조하세요.

비슷한 상황에서 시스템이 절전 모드로 전환될 때 전원 정책 소유자는 디바이스 IRP를 전송하여 디바이스 전원을 빼기 전에 보류 중인 I/O를 완료해야 할 수 있습니다. I/O가 완료되고 DispatchPower 루틴에서 대기할 때 이벤트를 알리는 대신 드라이버는 작업 항목을 큐에 대기하고 DispatchPower 루틴에서 STATUS_PENDING 반환해야 합니다. 작업자 스레드에서는 I/O가 완료되기를 기다린 다음 디바이스 전원 IRP를 보냅니다. 자세한 내용은 IoAllocateWorkItem을 참조하세요.