发送设备电源状态的 IRP_MN_QUERY_POWER 或 IRP_MN_SET_POWER

设备电源策略所有者发送设备查询电源 IRP (IRP_MN_QUERY_POWER) ,以确定较低级别的驱动程序是否可以适应设备电源状态的更改,设备设置电源 IRP (IRP_MN_SET_POWER) 来更改设备电源状态。 (此驱动程序还可以发送等待/唤醒 IRP,使其设备能够唤醒以响应外部信号;有关详细信息 ,请参阅支持具有Wake-Up功能的设备 。)

当以下任一情况为 true 时,驱动程序应发送 IRP_MN_QUERY_POWER 请求:

  • 驱动程序接收系统查询电源 IRP。

  • 驱动程序准备将空闲设备置于睡眠状态,因此必须查询较低的驱动程序,以确定这样做是否可行。

当以下任一项为 true 时,驱动程序应发送 IRP_MN_SET_POWER 请求:

  • 驱动程序已确定设备处于空闲状态,可以进入睡眠状态。

  • 设备处于睡眠状态,必须重新进入工作状态才能处理等待的 I/O。

  • 驱动程序接收系统设置电源 IRP。

驱动程序不得分配自己的电源 IRP;电源管理器为此提供 PoRequestPowerIrp 例程。 正如 处理电源 IRP 的规则 所解释的, PoRequestPowerIrp 分配和发送 IRP,并与 Windows 7 和 Windows Vista) 中的 IoCallDriver (或 Windows Server 2003、Windows XP 和 Windows 2000) 中的 PoCallDriver (结合使用,确保所有电源请求正确同步。 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 中目标设备对象的指针、MinorFunction 中的次要 IRP 代码IRP_MN_SET_POWER或IRP_MN_QUERY_POWER,PowerState 中的值 DevicePowerState。键入PowerState 中的设备电源状态。状态。 在 Windows 98/Me 中, DeviceObject 必须指定基础设备的 PDO;在 Windows 2000 及更高版本的 Windows 中,此值可以指向同一设备堆栈中驱动程序的 PDO 或 FDO。

如果驱动程序必须在所有其他驱动程序完成 IRP 后执行其他任务,则应在 CompletionFunction 中传递指向电源完成函数的指针。 I/O 管理器在调用驱动程序设置的所有 IoCompletion 例程后调用 CompletionFunction,因为他们将 IRP 向下传递堆栈。

每当设备电源策略所有者发送设备电源查询 IRP 时,它应随后从回调例程 (CompletionFunction) 发送它在调用 PoRequestPowerIrp 中指定的设备 set-power IRP。 如果查询成功,则 set-power IRP 将指定查询的电源状态。 如果查询失败,则 set-power IRP 会重新断言当前设备电源状态。 重新断言当前状态非常重要,因为驱动程序会排队 I/O 以响应查询;策略所有者必须发送 set-power IRP,以通知其设备堆栈中的驱动程序开始处理排队的 I/O 请求。

请记住,设备的策略所有者不仅发送设备电源 IRP,而且还在 IRP 向下传递设备堆栈时处理 IRP。 因此,此类驱动程序通常会使用 IoSetCompletionRoutine) 设置 IoCompletion 例程 (作为其 IRP 处理代码的一部分,尤其是在设备开机时。 IoCompletion 例程与其他驱动程序设置的 IoCompletion 例程在 CompletionFunction 之前按顺序调用。 有关详细信息,请参阅 设备电源 IRP 的 IoCompletion 例程

由于调用 CompletionFunction 时所有驱动程序都已完成 IRP,因此 CompletionFunction 不得使用它发起的 IRP 调用 IoCallDriverPoCallDriverPoStartNextPowerIrp 。 (但是,它可能会为不同的电源 IRP 调用这些例程。) 相反,此例程执行发起 IRP 的驱动程序所需的任何其他操作。 如果驱动程序发送设备 IRP 以响应系统 IRP, 则 CompletionFunction 可能会完成系统 IRP。 有关详细信息,请参阅 处理设备电源策略所有者中的系统Set-Power IRP

为了响应对 PoRequestPowerIrp 的调用,电源管理器分配电源 IRP 并将其发送到设备的设备堆栈顶部。 电源管理器返回指向分配的 IRP 的指针。

如果没有发生错误, PoRequestPowerIrp 将返回STATUS_PENDING。 此状态表示 IRP 已成功发送,并且正在等待完成。 如果电源管理器无法分配 IRP,或者调用方指定了无效的次要电源 IRP 代码,则调用将失败。

启动设备的请求必须先由设备的基础总线驱动程序处理,然后由堆栈中每个连续更高的驱动程序处理。 因此,在发送 PowerDeviceD0 请求时,驱动程序必须确保其 CompletionFunction 在 IRP 完成且设备已开机后执行所需的任务。

关闭设备 (PowerDeviceD3) 时,设备堆栈中的每个驱动程序都必须保存其所有必要的上下文并执行任何必要的清理,然后再将 IRP 发送到下一个较低的驱动程序。 上下文信息和清理的范围取决于驱动程序的类型。 函数驱动程序必须保存硬件上下文;筛选器驱动程序可能需要保存其自己的软件上下文。 在这种情况下设置的 CompletionFunction 可以执行与已完成电源 IRP 关联的操作,但驱动程序无法访问该设备。