WDF驱动开发-电源策略(一)

对于每个设备,一个 并且只有一个设备驱动程序必须是设备的 电源策略所有者。 电源策略所有者确定 设备的相应设备电源状态 ,并在设备的电源状态发生更改时向设备的驱动程序堆栈发送请求。

基于框架的驱动程序不包含请求更改设备电源状态的代码,因为框架提供了该代码。 默认情况下,每当系统进入 系统睡眠状态时,框架会要求驱动程序提供设备的总线,以将设备电源状态降低到 D3。 如果设备提供唤醒功能,则驱动程序可以更改默认行为,以便框架将设备的睡眠状态设置为 D1 或 D2。 当系统电源恢复到其 工作 (S0) 状态时,框架会请求总线驱动程序将设备还原到其工作 (D0) 状态。

电源策略所有者还负责启用和禁用以下设备功能:

  • 当设备处于空闲状态且系统保持工作 (S0 ) 状态 时,设备能够进入低功耗 (睡眠) 状态
  • 设备在检测到外部事件时能够从睡眠状态中唤醒自身
  • 设备在检测到外部事件时能够将整个系统从系统睡眠状态唤醒

如果设备支持这些空闲关机和系统唤醒功能,电源策略所有者还可以调用 WdfDeviceInitSetPowerPolicyEventCallbacks 来注册一组电源策略事件回调函数。

默认情况下,对于基于框架的驱动程序,设备的函数驱动程序是电源策略所有者。 (如果没有函数驱动程序,并且总线驱动程序已调用 WdfPdoInitAssignRawDevice,则总线驱动程序是电源策略所有者) 。 如果要更改驱动程序堆栈的电源策略所有者,默认电源策略所有者必须调用 WdfDeviceInitSetPowerPolicyOwnership 来禁用所有权,而将成为电源策略所有者的驱动程序必须调用 WdfDeviceInitSetPowerPolicyOwnership 才能启用所有权。

框架为电源策略所有者执行以下操作:

  • 它处理驱动程序与驱动程序堆栈其余部分之间的所有电源策略通信。 例如,驱动程序不必请求总线驱动程序来更改设备的电源状态,因为框架发出请求;
  • 如果驱动程序注册了电源策略事件回调函数,框架会在启用或禁用设备从低功耗状态唤醒自身的功能时调用它们;
  • 如果驱动程序允许用户修改空闲和唤醒设置,框架会以设备管理器显示的属性表页的形式提供用户界面;
支持空闲时关闭电源

当系统保持工作 (S0) 状态时,某些设备可能会进入低功率 (Dx) 状态。 从 Windows 8 开始,设备可以在进入 Dx 状态之前转换为低功率功能电源状态 (Fx) 。 对于此类设备,框架在设备处于空闲状态后启动设备或组件的电源降低, 在预先确定 和可设置时间内不使用。

其中一些设备还可以在检测到外部事件时在总线上触发唤醒信号。 总线驱动程序响应此信号,驱动程序堆栈将设备还原到其工作状态。 在框架要求总线驱动程序启动将设备还原到其工作状态之前,未检测到外部事件的设备仍处于低功耗状态。

如果设备或组件在空闲时可以关机,电源策略所有者中的 EvtDriverDeviceAdd 回调函数必须执行以下两个步骤:

1. 调用 WdfDeviceAssignS0IdleSettings 以指定:

  • 设备将进入的低功耗状态
  • 设备在降低电源状态之前 必须保持空闲 状态的时间
  • 设备是否可以检测外部事件并在总线上触发唤醒信号
  • 用户是否可以控制设备的空闲设置
  • 是启用还是禁用了设备的空闲断电功能
  • 当系统返回到其工作 (S0) 状态时,设备是否会返回到其工作 (D0) 状态
  • 设备的空闲超时值是否由电源管理框架 (PoFx)
  • 当空闲超时期限到期时,框架是否可以将设备置于 D3cold 电源状态

2. 调用 WdfDeviceInitSetPowerPolicyEventCallbacks 以注册以下事件回调函数,如果需要它们用于设备的话:

  • EvtDeviceArmWakeFromS0,使设备硬件 (而不是总线) 响应外部唤醒事件
  • EvtDeviceDisarmWakeFromS0, 禁用总线响应外部唤醒事件的能力
  • EvtDeviceWakeFromS0Triggered,通知司机总线检测到唤醒信号

空闲条件

框架认为设备处于空闲状态,并在满足以下所有条件时开始计算空闲时间:

  • 为此设备实例创建的电源托管队列中没有任何请求在队列中等待或被调度到驱动程序。 如果请求已调度到驱动程序,并且驱动程序将其发送到 I/O 目标,则请求仍与队列相关。 除非驱动程序使用 send and forget 选项 发送请求,否则设备不会被视为空闲。 非电源托管队列中的请求不计入设备空闲状态;
  • 如果驱动程序以前调用 了 WdfDeviceStopIdle,则驱动程序随后调用了 WdfDeviceResumeIdle;
  • 如果电源策略所有者是总线驱动程序,则总线驱动程序的所有子设备都不在 D0 中;

 如果驱动程序 (或用户) 为设备启用空闲电源关闭,则可能必须使用 WdfDeviceStopIdle 方法。 如果设备处于工作 (D0) 状态,则此方法可防止设备在驱动程序调用 WdfDeviceResumeIdle 之前闲动。 如果驱动程序调用 WdfDeviceStopIdle 时设备处于低功耗状态,并且系统处于工作 (S0) 状态,框架会请求总线驱动程序将设备还原到其工作 (D0) 状态。 每次成功调用 WdfDeviceStopIdle 都必须通过对 WdfDeviceResumeIdle 的调用进行匹配。 

如果设备可以从低功耗状态唤醒自身,则设备总线的驱动程序将参与唤醒设备。 总线驱动程序通常提供 EvtDeviceEnableWakeAtBus 和 EvtDeviceDisableWakeAtBus 回调函数。 这些函数在总线适配器上执行任何必要的操作,以启用和禁用设备从低功耗状态唤醒的功能。

支持系统唤醒

当系统处于低功耗状态时,某些设备可以检测外部事件(如传入的网络数据包),然后唤醒系统。 例如,如果 PCI 设备具有系统唤醒功能,如设备的电源管理功能 (PMC) 寄存器中所述,它会通过在 PCI 总线上引发电源管理事件 (PME) 信号来唤醒系统。

如果设备可以从系统范围的低功耗状态唤醒系统,电源策略所有者中的 EvtDriverDeviceAdd 回调函数必须执行以下两个步骤:

1. 调用 WdfDeviceAssignSxWakeSettings 以指定:

  • 设备将进入的低功耗状态
  • 用户是否可以控制设备的空闲设置
  • 是启用还是禁用设备的唤醒功能

2. 调用 WdfDeviceInitSetPowerPolicyEventCallbacks 以注册以下事件回调函数,如果需要它们用于设备:

  • EvtDeviceArmWakeFromSx 或 EvtDeviceArmWakeFromSxWithReason,使设备硬件能够响应外部唤醒事件;
  • EvtDeviceDisarmWakeFromSx,禁用设备响应外部唤醒事件的能力;
  • EvtDeviceWakeFromSxTriggered,通知司机总线检测到唤醒信号;
  • 公共汽车司机也参与唤醒系统。 设备总线的驱动程序通常提供 EvtDeviceEnableWakeAtBus 和 EvtDeviceDisableWakeAtBus 回调函数。 这些函数在总线适配器上执行任何必要的操作,以启用和禁用设备从低功耗状态唤醒的功能;

当总线驱动程序确定设备已触发唤醒信号时,它必须调用 WdfDeviceIndicateWakeStatus 来通知框架应恢复设备的电源。 然后框架将此信息传递给驱动程序堆栈中的其余驱动程序。

设备空闲和唤醒行为的用户控件

如果设备具有空闲电源关闭或唤醒功能,则可以决定是否应允许用户启用或禁用这些功能。

驱动程序可以使用 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS 结构的成员来指定具有注册表访问权限的用户是否可以启用或禁用设备的空闲电源关闭功能。

驱动程序可以使用 WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS 结构的成员来指定具有注册表访问权限的用户是否可以启用或禁用设备的唤醒功能。

这两种结构都允许驱动程序启用该功能、禁用该功能或让用户控制该功能。 若要让用户控制,在适当的设置结构中,驱动程序将 UserControlOfIdleSettings 或 UserControlOfWakeSettings 成员分别设置为 IdleAllowUserControl 或 WakeAllowUserControl, 并将 Enabled 成员设置为 WdfTrue 或 WdfUseDefault。

如果驱动程序允许用户修改空闲和唤醒设置,框架会以属性表页的形式提供用户界面,设备管理器显示,以便用户可以启用或禁用空闲和唤醒功能。 框架修改 IdleInWorkingState 和 WakeFromSleepState 注册表值。驱动程序及其安装文件 不得 读取或修改这些值。

如果用户修改了设备的设置,框架会根据需要更新设备的电源状态以匹配新设置。 例如,如果用户禁用设备的空闲关闭功能,而设备由于处于空闲状态而处于低功耗状态,则框架会将设备返回到其工作状态。

如果驱动程序允许用户修改空闲和唤醒设置,框架默认启用这些设置。 某些驱动程序编写器可能希望在允许用户修改设置之前先禁用这些设置。

因此,对于 1.9 版及更高版本的 KMDF,框架提供两个驱动程序可定义的注册表值,名为 WdfDefaultIdleInWorkingState 和 WdfDefaultWakeFromSleepState,它们存储在设备的 Device Parameters\WDF 子项中的设备硬件密钥下。 值REG_DWORD类型,“0”表示禁用该功能,“1”表示已启用该功能。

驱动程序的 INF 文件可以使用 INF AddReg 指令 创建和设置 WdfDefaultIdleInWorkingState 和 WdfDefaultWakeFromSleepState 注册表值。 例如,如果驱动程序启用了设备的空闲电源关闭功能,但如果在安装设备时必须禁用该功能,则驱动程序的 INF 文件可以将 WdfDefaultIdleInWorkingState 设置为“0”。

仅当驱动程序在适当的设置结构中分别将 UserControlOfIdleSettings 或 UserControlOfWakeSettings 成员设置为 IdleAllowUserControl 或 WakeAllowUserControl,并将 Enabled 成员设置为 WdfTrue 或 WdfUseDefault 时,框架才会检查 WdfDefaultInWorkingState 和 WdfDefault 注册表值。

支持功能性电源状态

从 Windows 8 开始,电源管理器包括运行时电源管理框架 (PoFx) 。 PoFx 支持在组件 (或子设备) 级别进行电源和时钟管理。

从 KMDF 版本 1.11 开始,KMDF 驱动程序可以利用 PoFx 提供的精细电源控制。 具体而言,KMDF 驱动程序可以在单个设备中定义多个逻辑组件,其中每个组件都可以独立管理电源。

例如,函数驱动程序可能为设备的每个逻辑组件定义一组唯一的功能电源状态。 与设备和系统电源状态类似,F0 表示组件已完全打开,而可选状态 F1、F2 等表示逐渐降低功率状态。 若要支持 Fx 状态,驱动程序必须是设备的电源策略所有者。

下表汇总了对不同功能电源状态方案的框架支持:

类型KMDF 支持UMDF 支持何时使用/如何实现
单组件、单状态 (F0)支持支持

如果希望电源引擎插件 (PEP) 来确定空闲超时值,并且驱动程序只有一个 F 状态。

使用 IdleTimeoutType = SystemManagedIdleTimout 或SystemManagedIdleTimoutWithHint 调用 WdfDeviceAssignS0IdleSettings。

单组件、多状态 

支持

不支持

当驱动程序具有多个 F 状态时。

调用 WdfDeviceWdmAssignPowerFrameworkSettings 以注册 WDM PoFx 回调。
使用 IdleTimeoutType = SystemManagedIdleTimout 调用 WdfDeviceAssignS0IdleSettings。
在这种情况下,KMDF 处理大多数与 PoFx 的交互。

多组件、多状态支持使用 WDM 接口不支持当驱动程序具有多个组件时。 在这种情况下,必须直接使用 PoFx 接口。

 由于 KMDF 在 PoFx 的基础上添加了最少的抽象,因此在编写驱动程序之前,对 PoFx 有基本的了解会很有帮助。

  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值