处理设备电源状态的 IRP_MN_QUERY_POWER

设备 query-power IRP 查询单个设备的状态更改,并发送到设备堆栈中的所有驱动程序。 此类 IRP 在 I/O 堆栈位置的 Power.Type 成员中指定 DevicePowerState

驱动程序在堆栈下行时处理查询能力 IRP。

如果以下任一条件成立,函数或筛选器驱动程序可能会使 IRP_MN_QUERY_POWER 请求失败:

  • 设备已启用唤醒,并且请求的电源状态低于设备可从中唤醒系统的状态。 例如,如果设备可以从 D2 唤醒系统,但不能从 D3 唤醒系统,则对 D3 的查询会失败,但会成功查询 D2。

  • 进入请求的状态将强制驱动程序放弃丢失数据的操作,例如打开调制解调器连接。 由于此原因,驱动程序很少会使查询失败;在大多数情况下,应用程序会处理此类情况。

若要使 IRP_MN_QUERY_POWER 请求失败,驱动程序会执行以下步骤:

  1. 调用 PoStartNextPowerIrp 以指示驱动程序已准备好处理下一个电源 IRP。 仅 (Windows Server 2003、Windows XP 和 Windows 2000。)

  2. Irp-IoStatus.Status> 设置为失败状态并调用 IoCompleteRequest,指定IO_NO_INCREMENT。 驱动程序不会在设备堆栈中进一步传递 IRP。

  3. 从其 DispatchPower 例程返回错误状态。

如果驱动程序成功执行查询电源 IRP,则它不得启动任何操作或采取任何其他操作来阻止其成功完成对查询电源状态的后续 IRP_MN_SET_POWER 请求。

成功 IRP 的驱动程序必须为查询状态准备设置电源 IRP,并向下传递查询 IRP,如下所示:

  1. 完成任何未完成的 I/O 操作。

  2. 队列传入 I/O 请求。

  3. 避免启动会干扰到指定电源状态转换的任何其他新活动。 但是,驱动程序不应保存设备上下文或采取其他步骤关闭。

  4. 调用 IoCopyCurrentIrpStackLocationToNext 为下一个较低级别的驱动程序设置 IRP 堆栈位置。

  5. 设置 IoCompletion 例程。 在 IoCompletion 例程中,调用 PoStartNextPowerIrp (Windows Server 2003、Windows XP 和 Windows 2000 仅) ,以指示驱动程序已准备好处理下一个电源 IRP。

  6. 在 Windows 7 中调用 IoCallDriver (,在 Windows Server 2003、Windows XP 和 Windows 2000 中调用 Windows Vista) 或 PoCallDriver (,) 将查询 IRP 传递到下一个较低的驱动程序。 不要完成 IRP。

  7. 返回STATUS_PENDING。 驱动程序不得更改 Irp-IoStatus.Status> 中的值。

查询电源 IRP 到达总线驱动程序时,总线驱动程序调用 PoStartNextPowerIrp (Windows Server 2003、Windows XP 和 Windows 2000 仅) ,如果驱动程序可以更改为指定的电源状态,则将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS如果驱动程序可以更改为指定的电源状态,或者如果不能,则设置失败状态。 然后,总线驱动程序调用 IoCompleteRequest,指定IO_NO_INCREMENT。

典型设备堆栈中的驱动程序处理设备查询电源 IRP,如下所示:

  • 大多数筛选器驱动程序只需将 IRP 传递到下一个较低的驱动程序 (请参阅 ) 传递 Power IRP 并返回STATUS_PENDING。 但是,某些筛选器驱动程序可能首先需要执行特定于设备的任务,例如排队传入 IRP 或保存设备电源状态。

  • 函数驱动程序执行设备特定的任务 (,例如完成挂起的 I/O 请求、排队传入的 I/O 请求、保存设备上下文或更改设备电源) 、设置 IoCompletion 例程,并将设备电源 IRP 传递给下一个较低的驱动程序 (请参阅 ) 传递 Power IRP 。 它从其 DispatchPower 例程返回STATUS_PENDING。

  • 总线驱动程序调用 PoStartNextPowerIrp (Windows Server 2003、Windows XP 和 Windows 2000 仅) 来启动下一个电源 IRP。 然后完成 IRP,指定IO_NO_INCREMENT。 如果驱动程序无法立即完成 IRP,它将调用 IoMarkIrpPending,从其 DispatchPower 例程返回STATUS_PENDING,稍后完成 IRP。

即使目标设备已处于查询电源状态,每个函数或筛选器驱动程序也必须将 I/O 排队,并将 IRP 向下传递到下一个较低的驱动程序。 IRP 必须一直沿着设备堆栈一直行驶到总线驱动程序,这样才能完成它。

处理 IRP_MN_QUERY_POWER 请求时,驱动程序应尽快从 DispatchPower 例程返回。 驱动程序不得在其 DispatchPower 例程中等待处理同一 IRP 的代码发出信号的内核事件。 由于电源 IRP 在整个系统中同步,因此可能会出现死锁。