处理设备电源状态的 IRP_MN_SET_POWER
设备集电源 IRP 请求更改单个设备的状态,并将其发送到设备堆栈中的所有驱动程序。 此类 IRP 在 I/O 堆栈位置的 Power.Type 成员中指定 DevicePowerState。
驱动程序在堆栈中向下移动时处理断电的 IRP。 对于上电 IRP,驱动程序在 IRP 向下移动堆栈时设置 IoCompletion 例程,然后在 IRP 返回堆栈时处理 IoCompletion 例程中的 IRP。 典型设备堆栈中的驱动程序处理设备集电源 IRP,如下所示:
大多数筛选器驱动程序应只需调用 IoMarkIrpPending,将 IRP 传递给下一个较低的驱动程序 (请参阅) 传递 Power IRP ,并从 DispatchPower 例程返回STATUS_PENDING。 但是,某些筛选器驱动程序可能首先需要执行特定于设备的任务,例如排队传入 IRP 或保存设备电源状态。
函数驱动程序调用 IoMarkIrpPending, (执行特定于设备的任务,例如完成挂起的 I/O 请求、排队传入 I/O 请求、保存设备上下文或更改设备电源) ,如有必要,设置 IoCompletion 例程,并将设备电源 IRP 传递给下一个较低级别的驱动程序 (请参阅) 传递 Power IRP 。 它从其 DispatchPower 例程返回STATUS_PENDING。
如果总线驱动程序能够更改设备电源,则调用 PoSetPowerState 以通知电源管理器新的设备电源状态。 仅在 Windows Server 2003、Windows XP 和 Windows 2000 中,驱动程序还必须调用 PoStartNextPowerIrp ,以在设置电源状态后启动下一个电源 IRP。 然后,驱动程序完成 IRP,并指定IO_NO_INCREMENT。 如果驱动程序无法立即完成 IRP,它将调用 IoMarkIrpPending,从其 DispatchPower 例程返回STATUS_PENDING,稍后完成 IRP。
即使目标设备已处于请求的电源状态,每个函数或筛选器驱动程序也必须将 IRP 向下传递到下一个较低级别的驱动程序。 每个设置功率的 IRP 必须一直沿着设备堆栈向下移动到总线驱动程序,从而完成它。
位于总线驱动程序上方的功能和筛选器驱动程序不得使设备设置电源 IRP 失败。 如果删除设备或正在移除设备,总线驱动程序可能会使设备通电 IRP 失败。
驱动程序堆栈中的每个驱动程序 (函数、筛选器和总线驱动程序) 都必须调用 PoSetPowerState ,以通知电源管理器其相应设备对象的电源状态发生更改。
与与设备通电和关机关联的其他驱动程序任务一样,如果新状态为 D0) ,则必须在设备开机 (或设备关机之前调用 PoSetPowerState , (新状态为任何其他状态) 。
每个驱动程序应跟踪其设备的电源状态。 电源管理器不会向驱动程序提供此信息。
处理设备电源状态 的IRP_MN_SET_POWER 请求时,驱动程序应尽快从 DispatchPower 例程返回。 驱动程序不得在其 DispatchPower 例程中等待处理同一 IRP 的代码发出信号的内核事件。 由于电源 IRP 在整个系统中是同步的,因此可能会出现死锁。
为了确保最高级别的系统性能(尤其是对于多媒体应用程序),驱动程序应在中断请求级别执行耗时的操作, (IRQL) 等于PASSIVE_LEVEL。 若要在 IRQL= PASSIVE_LEVEL执行操作,驱动程序可以使用 专用线程 或 系统工作线程。 有关优化多媒体平台驱动程序性能的指南,请参阅 流媒体设备设计指南。
驱动程序处理电源 IRP 所必须执行的确切步骤取决于设备是开机还是关机,如以下部分所述: