Передача power IRP

Power IRP должны передаваться вплоть до стека устройств в PDO, чтобы обеспечить чистое управление переходами питания. Драйверы обрабатывают IRP, который уменьшает мощность устройства, когда IRP перемещается вниз по стеку устройств. Водители обрабатывают IRP, которое применяет питание устройства в подпрограммах IoCompletion , когда IRP перемещается вверх по стеку устройств.

На следующем рисунке показаны шаги, которые необходимо выполнить драйверам для передачи IRP питания в стек устройств в Windows 7 и Windows Vista.

схема, иллюстрирующая передачу power irp в Windows Vista.

Как показано на предыдущем рисунке, в Windows 7 и Windows Vista драйвер должен выполнять следующие действия.

  1. Вызовите IoCopyCurrentIrpStackLocationToNext , если задана подпрограмма IoCompletion , или IoSkipCurrentIrpStackLocation , если не задана подпрограмма IoCompletion .

    Эти две подпрограммы задают расположение стека IRP для следующего ниже драйвера. Копирование текущего расположения стека гарантирует, что при выполнении подпрограммы IoCompletion для указателя стека IRP будет задано правильное расположение.

    Если неправильно написанный драйвер допустит ошибку при вызове IoSkipCurrentIrpStackLocation и последующем задании процедуры завершения, этот драйвер может перезаписать подпрограмму завершения, заданную драйвером ниже.

  2. Вызовите IoSetCompletionRoutine , чтобы задать подпрограмму IoCompletion , если требуется полная подпрограмма.

  3. Вызовите IoCallDriver , чтобы передать IRP следующему драйверу в стеке.

На следующем рисунке показаны шаги, необходимые драйверам для передачи IRP питания в стеке устройств в Windows Server 2003, Windows XP и Windows 2000.

передача power irp (Windows Server 2003, Windows XP и Windows 2000).

Как показано на предыдущем рисунке, драйвер должен сделать следующее:

  1. В зависимости от типа драйвера можно вызвать PoStartNextPowerIrp. Дополнительные сведения см. в разделе Вызов PoStartNextPowerIrp.

  2. Вызовите IoCopyCurrentIrpStackLocationToNext , если задана подпрограмма IoCompletion , или IoSkipCurrentIrpStackLocation , если не задана подпрограмма IoCompletion .

    Эти две подпрограммы задают расположение стека IRP для следующего ниже драйвера. Копирование текущего расположения стека гарантирует, что при выполнении подпрограммы IoCompletion для указателя стека IRP будет задано правильное расположение.

  3. Вызовите IoSetCompletionRoutine , чтобы задать подпрограмму IoCompletion . В процедуре IoCompletion большинство драйверов вызывают PoStartNextPowerIrp , чтобы указать, что они готовы к обработке следующего IRP питания.

  4. Вызовите PoCallDriver , чтобы передать IRP следующему драйверу в стеке.

    Драйверы должны использовать PoCallDriver, а не IoCallDriver (как и другие irP), чтобы обеспечить правильную синхронизацию источников интеграции питания. Дополнительные сведения см. в статье Вызов IoCallDriver и вызов PoCallDriver.

Помните, что процедуры IoCompletion можно вызывать по адресу IRQL = DISPATCH_LEVEL. Таким образом, если драйверу требуется дополнительная обработка в IRQL = PASSIVE_LEVEL после завершения работы драйверов более низкого уровня с IRP, процедура завершения драйвера должна ставить рабочий элемент в очередь, а затем возвращать STATUS_MORE_PROCESSING_REQUIRED. Рабочий поток должен завершить IRP.

В Windows 98/Me драйверы должны выполнять irp питания в IRQL = PASSIVE_LEVEL.

Не изменяйте коды функций в Power IRP

В дополнение к обычным правилам, которые регулируют обработку IRP, IRP_MJ_POWER IRP имеют следующее особое требование: драйвер, получающий IRP питания, не должен изменять основные и второстепенные коды функций в любых расположениях стека ввода-вывода в IRP, которые были заданы диспетчером питания или драйверами более высокого уровня. Диспетчер управления питанием полагается на эти коды функций, которые остаются неизменными до завершения IRP. Нарушения этого правила могут привести к проблемам, которые трудно отлаживать. Например, операционная система может перестать отвечать или "зависать".

Не блокировать при обработке power IRP

Драйверы не должны вызывать длительные задержки при обработке irP питания.

При передаче IRP питания драйвер должен вернуться из своей процедуры DispatchPower как можно скорее после вызова IoCallDriver (в Windows 7 и Windows Vista) или PoCallDriver (в Windows Server 2003, Windows XP и Windows 2000). Драйвер не должен ждать события ядра или другой задержки перед возвратом. Если драйвер не может обработать IRP питания в течение короткого времени, он должен вернуть STATUS_PENDING и поставить в очередь все входящие irP до завершения IRP питания. (Обратите внимание, что это поведение отличается от поведения PnP IRP и подпрограмм DispatchPnP , которые разрешено блокировать.)

Если драйвер должен ждать действия питания другого драйвера дальше по стеку устройств, он должен вернуть STATUS_PENDING из своей подпрограммы DispatchPower и задать процедуру IoCompletion для IRP питания. Драйвер может выполнять любые задачи, необходимые в подпрограмме IoCompletion , а затем вызывать PoStartNextPowerIrp (только Windows Server 2003, Windows XP и Windows 2000) и IoCompleteRequest.

Например, владелец политики управления питанием для устройства обычно отправляет IRP питания устройства при удержании IRP питания системы, чтобы задать состояние питания устройства, соответствующее запрошенной системной системе.

В этом случае владелец политики управления питанием должен задать подпрограмму IoCompletion в системном IRP питания, передать IRP питания системы следующему ниже драйверу и вернуть STATUS_PENDING из подпрограммы DispatchPower .

В процедуре IoCompletion она вызывает PoRequestPowerIrp для отправки IRP питания устройства, передавая указатель на подпрограмму обратного вызова в запросе. Подпрограмма IoCompletion должна возвращать STATUS_MORE_PROCESSING_REQUIRED.

Наконец, драйвер передает системное IRP из процедуры обратного вызова. Драйвер не должен ждать события ядра в своей подпрограмме DispatchPower и сигнализировать с помощью процедуры IoCompletion для IRP, который он обрабатывает в настоящее время; может возникнуть взаимоблокировка системы. Дополнительные сведения см. в разделе Обработка системного Set-Power IRP в владельце политики управления питанием устройства.

В аналогичной ситуации, когда система переходит в спящий режим, владельцу политики управления питанием может потребоваться выполнить некоторые ожидающие операции ввода-вывода перед отправкой IRP устройства для выключения устройства. Вместо того, чтобы сигнализировать о событии о завершении ввода-вывода и ожидании в подпрограмме DispatchPower , драйвер должен ставить рабочий элемент в очередь и возвращать STATUS_PENDING из подпрограммы DispatchPower . В рабочем потоке он ожидает завершения ввода-вывода, а затем отправляет IRP питания устройства. Дополнительные сведения см. в разделе IoAllocateWorkItem.