处理设备断电 IRP

设备断电 IRP 指定IRP_MN_SET_POWER次要 函数代码, 以及设备电源状态 (PowerDeviceD0PowerDeviceD1PowerDeviceD2PowerDeviceD3) ,这些) 低功率或等于当前设备电源状态。 当 IRP 沿着设备堆栈向下传输时,驱动程序必须处理掉电的 IRP。 较高级别的驱动程序必须先处理 IRP,然后再处理较低级别的驱动程序。 没有要执行特定于设备的任务的驱动程序应立即将 IRP 传递给下一个较低的驱动程序。

下图显示了处理此类 IRP 所涉及的步骤。

说明处理设备关闭请求的示意图。

如果 IRP 指定 PowerDeviceD3,则函数驱动程序通常应执行以下任务:

  • 调用 IoAcquireRemoveLock,传递当前 IRP,以确保驱动程序在处理电源 IRP 时不会收到 PnP IRP_MN_REMOVE_DEVICE 请求。

    如果 IoAcquireRemoveLock 返回失败状态,驱动程序不应继续处理 IRP。 相反,从 Windows Vista 开始,驱动程序应调用 IoCompleteRequest 以完成 IRP,然后返回失败状态。 在 Windows Server 2003、Windows XP 和 Windows 2000 中,驱动程序应调用 IoCompleteRequest 以完成 IRP,然后调用 PoStartNextPowerIrp 以启动下一个电源 IRP,然后返回失败状态。

  • 执行删除设备电源之前必须执行的任何特定于设备的任务,例如关闭设备、完成或刷新任何挂起的 I/O、禁用中断、 排队后续传入 IRP 以及保存从中还原或重新初始化设备的设备上下文。

    例如,驱动程序不应导致长时间延迟 (,用户在处理 IRP 时可能会认为此类设备) 延迟不合理。

    驱动程序应对任何传入的 I/O 请求进行排队,直到设备返回到工作状态。

  • 可能检查 Parameters.Power.ShutdownType 中的值。 如果系统设置电源 IRP 处于活动状态, 则 ShutdownType 提供有关系统 IRP 的信息。 有关此值的详细信息,请参阅 系统电源操作

    休眠路径上的设备的驱动程序必须检查此值。 如果 ShutdownTypePowerActionHibernate,驱动程序应保存还原设备所需的任何上下文,但不应关闭设备电源。

  • 如果驱动程序能够这样做,并且更改合适,请更改设备的物理电源状态。

  • 调用 PoSetPowerState 以通知电源管理器新的设备电源状态。

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

  • 设置调用 PoStartNextPowerIrpIoCompletion 例程,该例程指示驱动程序已准备好处理下一个电源 IRP。 在 Windows 7 和 Windows Vista 中不需要此步骤。

  • 在 Windows 7 和 Windows Vista) 调用 IoCallDriver (,或在 Windows Server 2003、Windows XP 和 Windows 2000) 中调用 PoCallDriver (,以便将 IRP 传递给下一个较低的驱动程序。 IRP 必须一直传递到总线驱动程序,从而完成 IRP。

  • 调用 IoReleaseRemoveLock 以释放以前获取的锁。

  • 返回STATUS_PENDING。

在转发 IRP 之前,驱动程序必须保存任何设备上下文信息并设置新的电源状态。 上下文信息至少应包含请求的新电源状态。 它还应包括驱动程序在开机时所需的任何其他信息。 完成 IRP 并关闭设备电源后,驱动程序将无法再访问设备,并且设备上下文不可用。

每个驱动程序都必须将 IRP 传递给下一个较低的驱动程序。 当 IRP 到达总线驱动程序时,总线驱动程序关闭设备电源 (它是否能够进行此) ,调用 PoSetPowerState 以通知电源管理器,并完成 IRP。

但是,如果总线驱动程序为休眠设备提供服务,则应检查 IRP 中 ShutdownType 的值是否为 PowerSystemHibernate。 如果是这样,总线驱动程序应调用 PoSetPowerState 来报告 PowerDeviceD3,但不应关闭设备电源。 保存休眠文件后,设备将关机,以及系统的其余部分。

在其所有子设备关闭电源后,总线驱动程序可能也会选择关闭其总线。 此类行为依赖于设备。

如果 IRP (D0、D1 或 D2) 指定任何其他状态,则所需的驱动程序操作依赖于设备。 通常,当 I/O 请求到达时,支持这些状态的设备可以快速恢复到工作状态。 此类设备的驱动程序必须完成任何挂起的 I/O 请求、对任何新请求进行排队,并保存所有必要的上下文,然后再将 IRP 转发到下一个较低的驱动程序。 当 IRP 到达总线驱动程序时,它会将硬件设置为请求的状态。 驱动程序在处于睡眠状态时无法访问设备。

在某些情况下,当设备已处于 D0 状态时,函数或筛选器驱动程序可能会收到指定 PowerDeviceD0 的设备电源 IRP。 驱动程序应像处理任何其他设置电源 IRP 一样处理此 IRP:完成挂起的 I/O 请求、排队传入的 I/O 请求、设置 IoCompletion 例程,并将 IRP 向下传递到下一个较低级别的驱动程序。 但是,驱动程序不得更改设备的硬件设置。 当总线驱动程序收到 IRP 时,它应该只需完成 IRP。 IRP 完成后,函数和筛选器驱动程序可以处理任何排队的请求。 在 IRP 完成之前排队 I/O 消除了较低驱动程序尝试更改设备寄存器而较高驱动程序尝试 I/O 的任何可能性。