Отправка IRP_MN_QUERY_POWER или IRP_MN_SET_POWER для состояний питания устройства

Владелец политики управления питанием устройства отправляет IRP с запросом на питание устройства (IRP_MN_QUERY_POWER), чтобы определить, могут ли более низкие драйверы соответствовать изменению состояния питания устройства, и IRP для набора питания устройства (IRP_MN_SET_POWER) для изменения состояния питания устройства. (Этот драйвер также может отправить IRP ожидания или пробуждения, чтобы его устройство пробуждалось в ответ на внешний сигнал. Дополнительные сведения см. в разделе Вспомогательные устройства с Wake-Up возможностями .)

Драйвер должен отправить запрос IRP_MN_QUERY_POWER , если выполняется одно из следующих действий:

  • Драйвер получает системное IRP на основе запросов.

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

Драйвер должен отправить запрос IRP_MN_SET_POWER , если выполняется любое из следующих действий:

  • Драйвер определил, что устройство находится в режиме простоя и может быть помещено в спящий режим.

  • Устройство находится в спящем режиме и должно повторно войти в рабочее состояние для обработки ожидающих операций ввода-вывода.

  • Драйвер получает системный IRP с питанием.

Драйвер не должен выделять собственный IRP питания; диспетчер питания предоставляет для этой цели подпрограмму PoRequestPowerIrp . Как объясняется в правилах обработки power IRP , PoRequestPowerIrp выделяет и отправляет IRP и в сочетании с IoCallDriver (в Windows 7 и Windows Vista) или PoCallDriver (в Windows Server 2003, Windows XP и Windows 2000) гарантирует правильную синхронизацию всех запросов на питание. Вызывающие функции PoRequestPowerIrp должны выполняться в среде IRQL <= DISPATCH_LEVEL.

Ниже приведен прототип этой подпрограммы.

NTSTATUS
PoRequestPowerIrp (
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR MinorFunction,
    IN POWER_STATE PowerState,
    IN PREQUEST_POWER_COMPLETE CompletionFunction,
    IN PVOID Context,
    OUT PIRP *Irp OPTIONAL
    );

Чтобы отправить IRP, драйвер вызывает PoRequestPowerIrp, указывая указатель на целевой объект устройства в DeviceObject, дополнительный код IRP IRP_MN_SET_POWER или IRP_MN_QUERY_POWER в MinorFunction, значение DevicePowerState в PowerState. Тип и состояние питания устройства в PowerState. Состояние. В Windows 98/Me DeviceObject должен указать PDO базового устройства; в Windows 2000 и более поздних версиях Windows это значение может указывать на PDO или FDO драйвера в том же стеке устройств.

Если драйвер должен выполнять дополнительные задачи после того, как все остальные драйверы завершили IRP, он должен передать указатель на функцию завершения питания в CompletionFunction. Диспетчер операций ввода-вывода вызывает CompletionFunction после вызова всех подпрограмм IoCompletion, заданных драйверами при передаче IRP вниз по стеку.

Всякий раз, когда владелец политики управления питанием устройства отправляет IRP запроса на питание устройства, он должен затем отправить IRP набора устройств из подпрограммы обратного вызова (CompletionFunction), указанной в вызове PoRequestPowerIrp. Если запрос выполнен успешно, IRP set-power указывает состояние запрашиваемой мощности. Если запрос завершился сбоем, IRP set-power повторно подтверждает текущее состояние питания устройства. Повторная проверка текущего состояния важна, так как драйверы в очереди ввода-вывода в ответ на запрос; Владелец политики должен отправить IRP set-power, чтобы уведомить драйверы в стеке устройств о начале обработки запросов ввода-вывода в очереди.

Имейте в виду, что владелец политики для устройства не только отправляет IRP питания устройства, но и обрабатывает IRP по мере его передачи в стеке устройств. Таким образом, такой драйвер часто задает подпрограмму IoCompletionIoSetCompletionRoutine) как часть кода обработки IRP, особенно при выключении устройства. Подпрограмма IoCompletion вызывается в последовательности с подпрограммами IoCompletion , заданными другими драйверами, и до завершенияfunction. Дополнительные сведения см. в разделе Процедуры IoCompletion для irP питания устройств.

Так как IRP был завершен всеми драйверами при вызове CompleteFunction , CompleteFunction не должен вызывать IoCallDriver, PoCallDriver или PoStartNextPowerIrp с созданным им IRP. (Однако эти подпрограммы могут вызываться для другого энергопотребления IRP.) Вместо этого эта подпрограмма выполняет все дополнительные действия, необходимые драйверу, который является источником IRP. Если драйвер отправил IRP устройства в ответ на системный IRP, Функция Завершения может завершить системный IRP. Дополнительные сведения см. в разделе Обработка системного Set-Power IRP в владельце политики управления питанием устройства.

В ответ на вызов PoRequestPowerIrp диспетчер питания выделяет IRP питания и отправляет его в верхнюю часть стека устройств для устройства. Диспетчер питания возвращает указатель на выделенный IRP.

Если ошибок не возникает, PoRequestPowerIrp возвращает STATUS_PENDING. Это состояние означает, что IRP успешно отправлен и ожидает завершения. Вызов завершается ошибкой, если диспетчеру питания не удается выделить IRP или если вызывающий объект указал недопустимый дополнительный код power IRP.

Запросы на включение устройства должны обрабатываться сначала базовым драйвером шины для устройства, а затем каждым последовательно более высоким драйвером в стеке. Поэтому при отправке запроса PowerDeviceD0 драйвер должен убедиться, что его Функция Завершения выполняет необходимые задачи после завершения IRP и включения устройства.

При выключении устройства (PowerDeviceD3) каждый драйвер в стеке устройств должен сохранить весь необходимый контекст и выполнить необходимую очистку перед отправкой IRP в драйвер следующего ниже. Объем сведений о контексте и очистка зависят от типа драйвера. Драйвер функции должен сохранять аппаратный контекст; драйверу фильтра может потребоваться сохранить собственный программный контекст. Набор CompletionFunction в этой ситуации может выполнять действия, связанные с завершенным IRP питания, но драйвер не может получить доступ к устройству.