Поделиться через


Отправка запросов 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 , если одно из следующих значений имеет значение true:

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

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

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

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

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

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

Драйвер не должен выделять собственную мощность IRP; Диспетчер питания предоставляет подпрограмму PoRequestPowerIrp для этой цели. Как объясняют правила обработки Power IRPs, 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.Type и состояние питания устройства в PowerState.State. В Windows 98/Me DeviceObject должен указать PDO базового устройства; в Windows 2000 и более поздних версиях Windows это значение может указывать на PDO или FDO драйвера в том же стеке устройств.

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

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

Имейте в виду, что владелец политики для устройства не только отправляет энергетический IRP устройства, но и обрабатывает IRP по мере его передачи вниз по стеку устройств. Таким образом, такой драйвер часто задает подпрограмму IoCompletion (с помощью IoSetCompletionRoutine) как часть кода обработки IRP, особенно когда устройство включается. Подпрограмма IoCompletion вызывается в последовательности с подпрограммами IoCompletion, заданными другими драйверами, и перед подпрограммой CompletionFunction. Дополнительные сведения см. в разделе "Подпрограммы IoCompletion для IRP устройства питания".

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

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

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

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

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