以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 网友互助 』  (http://bbs.xml.org.cn/list.asp?boardid=76)
----  处理系统电源状态请求  (http://bbs.xml.org.cn/dispbbs.asp?boardid=76&rootid=&id=42443)


--  作者:卷积内核
--  发布时间:1/18/2007 8:50:00 AM

--  处理系统电源状态请求
处理系统电源状态请求
所有驱动程序都必须能够响应系统电源状态的请求,而不管系统是成功地处于休眠,冬眠,还是在唤醒状态。

如果任何驱动程序都不支持系统电源管理,独立设备可以休眠或者唤醒,但是电源管理器不能使整个系统进入休眠状态中。

本章描述驱动程序应该如何响应改变或者查询系统电源状态的IRP。 它包括下列主题:

3.1 系统电源状态

3.1.1 系统工作状态S0

3.1.2 系统休眠状态S1,S2,S3,S4

3.1.3 系统关机状态S5

3.1.4 系统电源行动

3.2 系统电源策略

3.3 防止系统电源状态变化

3.4 为系统电源状态处理IRP_MN_QUERY_POWER

3.4.1 使一个系统查询电源IRP失效

3.4.2 在设备电源策略所有者中处理系统查询电源IRP

3.4.3 在总线驱动程序中处理系统查询电源IRP

3.4.4 在过滤驱动程序中处理系统查询电源IRP

3.5 为系统电源状态处理IRP_MN_SET_POWER

3.5.1 在设备电源策略所有者中处理系统设置电源IRP

3.5.1.1 确定当前的设备电源状态

3.5.1.2 发送一个响应系统设置电源IRP的设备设置电源IRP

3.5.2 在总线驱动程序中处理系统设置电源IRP

3.5.3 在过滤驱动程序中处理系统设置电源IRP

1.1 系统电源状态
系统电源状态描述整体系统的能源消耗。操作系统支持六种系统电源状态,即从S0(充分加电和操作)到S5(断电)。每一状态具有下列特征:

。能源消耗:计算机使用多少功率电源?

。软件恢复:操作系统从什么点重新启动?

。硬件等待时间:计算机返回工作状态需要多少时间?

。系统环境:要保持多少系统环境?操作系统必须重新启动以返回工作状态吗?

状态S0是工作状态。状态S1 、S2 、S3,和S4是休眠状态,因为要降低能源消耗,所以在这些状态中,计算机显示关闭形式,可是它保持着足够的环境,这样不用重新启动操作系统就能返回到工作状态。状态S5是中断或者关机状态。

当系统从关机状态(S5)或者任何一个休眠状态(Sl-S4)转变到工作状态(S0)时,系统进入唤醒状态。当系统从工作状态转变到任何一个休眠状态或者关机状态时,系统进入休眠状态。图3.1显示系统电源状态的几种可能的转变。

图3.1 系统电源状态转变的可能

从图中可以看到,系统不能从一种休眠状态直接进入另一种休眠状态;它必须在进入另一种休眠状态之前先进入工作状态。例如,系统不能从状态S2转变到S4,也不能从状态S4转变到S2。它必须首先返回到状态S0,然后才能再进入下一个休眠状态。 因为处于一种中间休眠状态的系统已经失去某种操作环境,在它进行其他状态转变之前,它必须返回工作状态以恢复该环境。

1.1.1 系统工作状态S0
系统状态S0是系统的工作状态,具有下列特点:

能源消耗:

最大值。当然,单独设备的电源状态能够动态地改变在个别设备基础上的电源保护。未使用的设备可以根据需要掉电或者加电。

软件恢复:

不适应。

硬件等待时间:

没有。

系统环境:

保持所有环境。

1.1.2 系统休眠状态S1,S2,S3,S4
S1,S2,S3,和S4状态都是休眠状态。在这些状态中的系统不执行任何计算任务,并且显示关闭形式。但是它不同于关机状态(S5)中的系统,休眠系统保持存储状态,或者是在硬件上或者是在磁盘上。操作系统不需要重新启动就能使计算机返回到工作状态。当某些事件发生时,一些设备能从休眠状态唤醒系统,例如对调制解调器的调用。此外,在一些计算机上,外部指示器还告诉用户系统只是处于休眠状态。

从S1到S4,在顺序的每一种休眠状态中,大多数计算机关机。所有ACPI顺序计算机在S1中关闭处理器时钟,并且在S4丢失系统环境(除非在关机之前已写好“冬眠”文件),就像本节下面几页中所列出的。休眠状态中间的一些细节情况主要取决于生产商如何设计机器。例如,在一些机器的某些芯片上,主板在状态S3上可能会掉电,而在其他一些类似的芯片上,直到状态S4还将保持电源。进一步说,一些设备或许只能从状态S1唤醒系统,而不能从较深层的休眠状态唤醒系统。

系统状态S1

系统状态S1是具有下列特点的一种休眠状态:

能源消耗:

小于在S0中的消耗,而大于在其他休眠状态的消耗。处理器时钟是关闭的,总线时钟是停止的。

软件恢复:

控制在其停止的地方重新启动。

硬件等待时间:

一般来说,不超过两秒时钟。

系统环境:

所有环境都由硬件保持和维护着。

系统状态S2:

除了CPU环境不同以外,系统状态S2类似于S1。由于处理器失去较低,所以系统高速缓存的内容被丢失。状态S2具有下列特点:

能源消耗:

小于在状态S1中的消耗,而大于在S3中的消耗。处理器时钟是关闭的,总线时钟是停止的。一些总线可能会掉电。

软件恢复:

在唤醒之后,从处理器的重置矢量开始控制。

硬件等待时间:

两秒或者更长时间,大于或者等于S1的等待时间。

系统环境:

CPU环境和系统高速缓存内容都已丢失。

系统状态S3:

系统状态S3是具有下列特点的一种休眠状态:

能源消耗:

小于状态S2中的消耗。处理器是关闭的,主板上的一些芯片也可能是关闭的。

软件恢复

在唤醒事件之后,控制从处理器的重置矢量开始。

硬件等待时间:

几乎与S2没有什么区别。

系统环境:

只有系统存储器被保留,而CPU环境、高速缓存内容、芯片上设置的环境都已丢失。

系统状态S4:

系统状态S4,即冬眠状态,是最低功率的休眠状态,并且有最长的唤醒等待时间。为了把能源消耗降低到最小,所有设备的硬件电源都是关闭。然而,操作系统环境被保持着,在进入S4状态之前系统就把它写在磁盘的那个冬眠文件上(内存映像)。当重新启动时,装入例程阅读此文件,并且跳到系统的上一个位置,即冬眠前的位置。

如果在状态S1,S2或者S3中的计算机失去了所有AC或者电池电源,那么它也就失去了系统环境,因此必须重新启动返回到S0。然而在状态S4中的计算机,甚至在它失去电池或者AC电源之后还能从其以前的位置重新启动。因为系统环境保存在冬眠文件中。在冬眠状态的计算机不使用电源(稀疏的电流是个例外情况)。

状态S4具有下列的特点:

能源消耗:

除了稀疏的电流会流到电源开关和类似的设备上之外,其余都是关闭的。

软件恢复:

系统从保存的冬眠文件中重新启动。 如果冬眠文件不能被装载,就要求重新启动。当系统在S4状态下时,重新配置的硬件可能会导致某些变化,阻止了冬眠文件的正确装载。

硬件等待时间:

等待时间长且未定义。只有物理互动才使系统返回到工作状态。这种互动可以包括:用户按下“ON”开关;如果有适当的硬件而且又能被唤醒,LAN上的调制解调器或活动的输入环等。如果硬件支持它,那么机器也能从恢复的定时器中唤醒。

系统环境:

硬件中没有保留任何内容。在掉电之前,系统在冬眠文件中写了一个存储映象。当操作系统被装载时,它阅读此文件并且跳到其以前的位置上。

1.1.3 系统关机状态S5
在S5状态或者称为关机状态中,机器没有存储状态,并且不执行任何计算任务。

状态S4和S5之间唯一的区别是:在状态S4中计算机能从冬眠文件中重新启动,而在状态S5中重新启动需要重新引导系统。

状态S5具有下列特点:

能源消耗:

除了流到电源按钮的稀疏电流之外,其余全是关闭的。

软件恢复:

在唤醒时要求引导。

硬件等待时间:

等待时间长且未定义。只有物理互动,诸如用户按下“ON”开关,使系统返回到工作状态。如果系统这样配置,BIOS也能从恢复的定时器上被唤醒。

系统环境:

没有保留任何内容。

1.1.4 系统电源动作
当电源管理器发送IRP设置或者查询系统电源状态时,它与附加的参数一同指定系统电源状态,给出有关电源状态变化的信息。这个参数,在Irp->Parameters.Power.ShutdownType中是一个POWER_ACTION类型的枚举变量。这个枚举变量描述系统电源状态的请求,如表3.1中所示:

表3.1系统电源动作

---------------------------------------------------------­­-- POWER_ACTION 枚举变量 要求的系统电源状态

————————————————————————————

PowerActionNone S0或者无系统电源IRP活动

PowerActionSleep S1 、S2,或者S3

PowerActionHibernate S4

PowerActionShutdown(只有 S5

Microsoftz@Windows@2000)

PowerActionShutdownReset S5

PowerActionShutdownOff S5

---------------------------------------------------------

对于状态S5, 当驱动程序收到一个系统查询IRP或者设置电源IRP时,它能对更多关于请求关机的信息检查ShutdownType。当机器正在重置而不是不确定的关闭电源时,驱动程序能用这个信息来优化它的关机序列。当系统重置时,大多数设备的驱动程序保持着电源。然而,对某些设备,诸如执行DMA的视频流设备,当系统重置时,驱动程序可以选择其设备掉电,这样就可以停止任何正在进行的I/O操作。

当设备电源策略所有者把设备电源IRP发送到其设备栈中以响应系统电源IRP时,驱动程序能使用ShutdounType参数得到有关当前系统电源IRP的信息。在这种情况下,ShutdownType值表明当前请求的系统电源状态,或者在系统要求并不明显时它是PowerActionNone。然而,如果设备IRP请求状态D0,驱动程序应该不依赖于这个信息。

在Windows 98上,当IRP请求设备电源状态时,这个字段总包含PowerActionNone。

1.2 系统电源策略
在系统电源策略管理模块中,电源管理器追踪系统的活动,确定适当的系统电源状态,并且发送IRP_MJ_POWER请求,以查询或者改变系统电源状态。它也通过应用程序读写电源策略的设置提供接口(参见平台SDK)。

电源管理器支持两项不同的电源策略—— 一个是对AC(畴壁电流)另一个是对DC(电池或者UPS),并且取决于当前电源在这两种电源策略之间的自动转换。一般来说,AC电源策略注重保护超过注重性能,而DC电源策略注重性能超过注重保护。为了查明系统何时从一种策略变成另一种策略,驱动程序能够注册带有系统\Callback\PowerState回调对象的通知。详见“Windows2000驱动程序开发参考”第2卷中的ExCreateCallback和“内核模式驱动程序设计指南”第1部分第3章中的Callback对象。

按照APCI说明的计算机能自动地从AC转换到电池电源,或者从一个电池转换到另一个电池,就象每一个这类电源断电一样。如果计算机硬件允许操作系统选择电源,那么电源管理器跟踪最近充电且功能依旧的电池,并且选择此电池作为计算机的电源。

一旦AC电源变得可供使用,计算机硬件便自动地开始给电池充电。如果硬件允许操作系统选择为哪一个电池充电,那么电源管理器就会选择放电最少的电池去再充电;这样任何时候系统至少具有一个充好电的电池的机会就增大了。

无论其他设置是什么,只要电池具有再充电能力或者提供的系统电源报告硬件条件“临界”,并且在两秒或者更长时间是处于放电状态中,那么电源管理器为临界电池执行DC电源策略。这种状态下的电源策略一般要求转变为冬眠状态或者关机状态。

1.3 防止系统电源状态变化
虽然驱动程序不能直接设置系统电源策略,可是电源管理器提供三个例程使驱动程序能防止系统的转变超越工作状态之外:PoSetSystemState,PoRegisterSystemState,和PoUnregisterSystemState。

通过调用PoRegisterSystemState或者PoSetSystemState,驱动程序能够向电源管理器通知用户已经到场或者驱动程序请求使用系统或者显示。

PoRegisterSystemState允许驱动程序注册一个连续地繁忙状态。由于驱动程序能稍迟改变其设置,它返回一个回柄。一旦状态注册生效,电源管理器就不能试图使系统进入休眠状态。驱动程序通过调用PoUnregisterSystemState撤消状态注册。

有了PoSetSystemState,驱动程序就能通知相同条件的电源管理器(用户在场,系统请求,显示请求),但是这个设置不是连续的。它具有重新启动与指定条件有关的递减计数器的作用。

使用这些例程,驱动程序能阻止许多、但并非所有超越工作状态之外的转变。当电源损失是非常紧迫的、或者当用户明确请求关机时,电源管理器总是关闭系统。

1.4 为系统电源状态处理IRP_MN_QUERY_P0WER
电源管理器发送带有次IRP码IRP_MN_QUERY_POWER和Parameters.Power.Type中的SystemPowerState的电源IRP,以确定它是否能安全地变为一个指定系统电源状态(S1-S5),并且允许驱动程序为这一变化做准备。

只要可能,电源管理器在发送一个较低(更小功率)状态请求IRP_MN_SET_POWER之前首先查询。然而,在失效的电池或者电源损失非常紧迫的情况下,电源管理器不先查询就直接发送设置电源IRP。在发送一个IRP将系统设置在工作状态之前,电源管理器决不发送查询请求。

对系统电源状态的IRP_MN_QUERY_POWER请求并不要求动作,除非驱动程序必须使IRP失效或者为其设备栈管理电源策略。大多数过滤驱动程序仅仅把IRP传递到相邻较低层驱动程序中,直到它到达完成它的总线驱动程序。驱动程序决不发送设备IRP_MN_SET_POWER请求以响应系统查询;它仅在收到系统设置电源请求之后,才请求这个IRP。

关于如何处理系统电源查询的更多信息参见下列内容:

。3.4.1 使系统查询电源IRP失效

。3.4.2 在设备电源策略所有者中处理系统查询电源IRP

。3.4.3 在总线驱动程序中处理系统查询电源IRP

。3.4.4 在过滤驱动程序中处理系统查询电源IRP

因为电源管理器把系统查询IRP发送到系统的每一个设备栈中,一种设备的驱动程序可能使查询失效,而其他设备的驱动程序则能成功地完成它。也可能电池用尽而查询激活,要求立即关机。因此,在查询IRP之后,每一个驱动程序必须准备接收下列任何电源IRP:

。查询状态的IRP_MN_SET_POWER

。不同电源状态的IRP_MN_SET_POWER

。当前电源状态的IRP_MN_SET_POWER

。任何状态的IRP_MN_QUERY_POWER

然而,一般来说,驱动程序收到一个跟随系统查询IRP之后的系统设置电源IRP。如果查询成功,则设置电源IRP指定查询状态。如果查询失效,则设置电源IRP重新确定当前电源状态。

1.4.1 使系统查询电源IRP失效
如果下列两者之一为真,功能驱动程序或者过滤驱动程序就使IRP_MN_QUERY_POWER请求失效:

。设备为唤醒被激活,并且请求系统电源状态的功率比SystemWake的值小,SystemWake的值指定了设备能唤醒系统的最小功率状态。例如,从S2而不是从S3中能唤醒系统的设备,对状态S3将是一个失效的查询,但是对状态S2可能是一个成功的查询。

。进入符合请求状态的设备状态会使驱动程序放弃丢失数据的操作,诸如打开调制解调器连接。由于这个原因,驱动程序很少丢失查询;在大多数情况下,应用例程处理这样的情况。

为了使IRP_MN_QUERY_POWER请求失效,驱动程序应该采取下列措施:

1.调用PoStartNextPowerIrp,表明其已准备处理下一个电源IRP。

2.设置Irp->IoStatus.Status为失效状态,并且调用IoCompleteRequest,指定IO_NO_INCREMENT。不把IRP传递到更下面的设备栈中。

3.调用IoReleaseRemoveLock,释放以前获取的锁。

4.从其DispatchPower例程中返回一个失效状态。

1.4.2 在设备电源策略所有者中处理系统查询电源IRP
当设备电源策略所有者为系统状态接收IRP_MN_QUERY_POWER时,它通过传递下来的查询请求,并且在IoCompletion例程中为设备电源状态发送一个IRP_MN_QUERY_POWER作为响应。当栈中所有的驱动程序都已完成设备查询时,设备电源策略所有者完成系统查询。拥有设备电源策略的驱动程序应该采取下列措施在其DispatchPower例程中响应一个系统查询请求:

1.调用IoAcquireRemoveLock,传递当前的IRP,保证在处理电源IRP时,驱动程序不接收PnP IRP_MN_REMOVE_DEVICE请求。如果IoAcquireRemoveLock返回失效状态,驱动程序不应该继续处理这个IRP。相反,它应该调用PoStartNextPowerIrp,然后,完成这个IRP(IoCompleteRequest),并且返回失效状态。

2.保证驱动程序能支持查询的系统电源状态,如在“使一个系统查询电源IRP失效”中所描述的。如果不能保证,就用在那节中所描述的失效状态完成这个IRP。

然而,如果设备具有唤醒能力,但它不能从冬眠状态唤醒系统,则其驱动程序对状态S4不能使一个查询请求失效。在这种情况下,对于驱动程序(发送IRP_MN_WAIT_WAKE)电源策略所有者必须撤消这个等待唤醒的IRP,并且完成系统查询。详见第4章中“撤消一个等待/唤醒的IRP”。

3.如果驱动程序能支持查询系统电源状态,则在系统查询电源IRP中设置一个IoCompletion例程。

4. 通过调用IoCopyCurrentIrpStackLocationToNext,为相邻较低层驱动程序创建IRP栈位置。

5.调用PoCallDriver,把IRP传递到相邻较低层驱动程序中。

6.从其DispatchPower例程中,由IoCallDriver传递返回的状态。

IoCompletion例程应该做下列事情:

l。 检查Irp->IoStatus.Status,保证低层驱动程序成功地完成IRP。如果任何驱动程序已失效于IRP,调用IoCompleteRequest完成此IRP,并且返回失效状态。

2.如果低层驱动程序已经成功地完成这个IRP,调用PoRequestPowerIrp,为所查询的系统状态是有效的设备状态发送一个设备查询电源IRP。如果必要的话,根据在DEVICE_CAPABILITIES结构中的DVICE_STATE数组,确定查询的系统状态中哪一个设备状态是有效的。

3.在调用PoRequestPowerIrp中,指定一个回调例程(CompletionFunction)并且在环境区域内传递系统IRP。

4.从IoCompletion例程中返回STATUS_MORE_PROCESSING_REQUIRED,这样驱动程序在回调例程中能完成处理中的系统查询IRP。

在IRP已经完成之后,并且在IRP处理过程中所创建的所有IoCompletion例程都已运行的情况下,电源管理器通过I/O管理器调用电源策略管理模块的回调例程。此回调例程必须依次执行下列操作:

1. 调用 PoStartNextPowerIrp,开始下一个电源IRP。

2. 对设备查询电源IRP,用返回的状态完成系统查询电源IRP(IoCompleteRequest)。

3. 调用IoReleaseRemoveLock,释放以前所获得的锁。

4. 用完成的查询IRP返回状态。

设备电源策略所有者不仅发送设备查询,而且还必须在其进入设备栈时处理它。详见第2章中的“为设备电源状态处理IRP_MN_QUERY_POWER”。

1.4.3 在总线驱动程序中处理系统查询电源IRP
当系统查询IRP到达总线驱动程序中时,总线驱动程序保证它能支持符合查询系统状态的设备状态;同时,如果能够等待/唤醒,则查询系统状态将不阻止其设备唤醒系统。

总线驱动程序调用PoStartNextPowerIrp,如果它能变为指定的电源状态,则在STATUS_SUCCESS中设置Irp->IoStatus.Status;如果它不能变为指定的电源状态,则设置一个失效状态。然后总线驱动程序调用IoCompleteRequest,指定IO_NO_INCREMENT。

在总线驱动程序完成IRP之后,电源管理器调用IoCompletion例程,这个例程是由传递IRP到栈中的其他驱动程序所创建的。

1.4.4 在过滤驱动程序中处理系统查询电源IRP
对于所有过滤驱动程序和功能驱动程序,如果它们并不拥有其设备栈的电源策略,那么它们就应该把一个系统查询电源IRP传递到相邻较低层驱动程序中,其步骤如下:

1.调用IoAcquireRemoveLock,传递当前IRP,保证驱动程序当处理电源IRP时不能接收PnP IRP_MN_REMOVE_DEVICE请求。

如果IoAcquireRemoveLock返回失效状态,则驱动程序不应该继续处理此IRP。相反,驱动程序应该调用PoStartNextPowerIrp,然后完成此IRP,并且返回失效状态。

2.确定它是否应该使查询失效。其方法和完整的处理过程参见3.4.1“使系统查询电源IRP失效”。

3.调用PoStartNextPowerIrp。

4.设置此IRP栈位置(IoSkipCurrentIrpStackLocation或者IoCopyIrpStackLocationToNext)。虽然驱动程序能在此IRP中创建一个IoCompletion例程,但是这样做没有太大的必要。

5.把这个IRP传递到相邻较低层驱动程序中(PoCallDriver)。

6.调用IoReleaseRemoveLock。如果驱动程序为此IRP创建了一个IoCompletion例程,那么用IoCompletion例程代替这次的调用。

7. 传递由PoCallDriver返回的状态作为其DispatchPower例程的返回状态。

1.5 为系统电源状态处理IRP_MN_SET_POWER
电源管理器发送一个电源IRP,指定次代码IRP_MN_SET_POWER和一个系统电源状态,由于下列原因之一:

。改变系统电源状态

。在一个失效的IRP_MN_QUERY_POWER请求之后,重新指定当前的电源状态

通过I/O管理器,电源管理器在每一个PnP设备节点上把IRP发送到设备栈中的顶端驱动程序。这个IRP通知当前系统电源状态栈中的所有驱动程序。

为了保证正常启动,电源管理器对系统加电IRP排序,所以在子设备加电之前,父设备有机会加电。电源管理器在发送系统电源IRP之前不进行查询。

为了保证计算机能正常休眠或关机,电源管理器发送系统IRP,指定休眠、冬眠,或者关机都处于一种定义好的序列中,这样离根较远的设备要比离根近的设备先掉电。只要可能,电源管理器在发送这样一个IRP之前要进行查询。详见“为系统电源状态处理IRP_MN_QUERY_POWER”。

系统电源IRP并不直接请求改变电源状态——它只是发出一个通知。驱动程序不能直接响应系统电源IRP以改变其设备的电源状态,而只能响应设备电源IRP来改变其设备的电源状态(设备电源策略所有者发送设备电源IRP,参见“在设备电源策略所有者中处理系统设置电源IRP”)。

对请求的系统电源状态,即使设备已经在一个有效的设备电源状态中,每一个驱动程序也必须把系统设置电源IRP传递到相邻较低层驱动程序中,直到它到达总线驱动程序。只有总线驱动程序允许完成这个IRP。驱动程序根据它在设备栈中的作用,处理这个IRP,在下面几节中描述:

。3.5.1在设备电源策略所有者中处理系统设置电源IRP

。3.5.2在总线驱动程序中处理系统设置电源IRP

。3.5.3在过滤驱动程序中处理系统设置电源IRP

驱动程序不能使IRP_MN_SET_POWER请求失效。电源管理器忽略此IRP返回的任何失效状态。

1.5.1 在设备电源策略所有者中处理系统设置电源IRP
对每一个系统设置电源IRP中指定的系统电源状态,在每一个设备栈中的设备电源策略所有者负责将其设备栈放到一个适当的设备电源状态中。

当设备电源策略所有者为系统电源状态接收IRP_MN_SET_POWER,它通过传递下来的IRP响应,同时在IoCompletion例程中,为一个相应的设备电源状态发送IRP_MN_SET_POWER。当栈中所有的驱动程序都已完成这个设备IRP时,设备电源策略所有者才完成系统IRP。

详见下列两节:

。3.5.1.1确定当前的设备电源状态

。3.5.1.2发送一个响应系统设置电源IRP的设备设置电源IRP

1.5.1.1 确定当前的设备电源状态
电源策略所有者能在DEVICE_CAPABILITY结构中,根据Device_State数组对每一系统状态确定设备电源的有效范围。对每个系统状态,数组列出位于下层的设备能支持的最大功率。

当在这个范围中选择特定状态时,需考虑下列情况:

。当系统进入S0状态时,大多数设备进入S0状态。

。当系统进入任何休眠状态时,大多数设备进入D3状态。然而,能够被唤醒的设备如果支持这些状态,则可以请求代替进入D1或者D2。详见第1章中“报告设备电源能力”。

。申请特殊规则的设备将掌握冬眠文件。如果系统IRP请求PowerSystemHibernate,掌握冬眠文件的设备决不能掉电。这个设备的电源策略所有者应该请求设备状态D3,并且保存环境。但是设备的驱动程序决不能使设备掉电。

如果系统IRP请求PowerSystemHibernate,驱动程序将在Irp->Parameter.Power.ShutdownType中检查POWER_ACTION的值,以获得更多关于状态变化原因的信息。详见3.1.4节“系统电源行动”。

设备电源策略所有者必须为每一个系统设置电源IRP发送设备设置电源IRP,即使设备已经处于当前的设备状态中。如果设备预先已经暂停操作响应查询电源IRP,则设置电源IRP就会通知设备停止IRP的排队,并且为其当前的电源状态返回正常的操作。 当设备处于D3状态时,唯一的例外情况是驱动程序不必对D3发送一个附加的IRP_MN_SET_POWER请求。

1.5.1.2 发送一个响应系统设置电源IRP的设备设置电源IRP
设备电源策略所有者应该采取下列措施来响应一个系统设置电源IRP:

1.调用IoAcquireRemoveLock,传递当前的IRP,保证当处理电源IRP时驱动程序不接收PnP IRP_MN_REMOVE_DEVICE请求。

如果IoAcquireRemoveLock返回失效状态,驱动程序不应该继续处理IRP。相反,它应该调用PoStartNextPowerIrp,完成IRP(IoCompleteRequest),并且返回失效状态。

2. 在系统设置电源IRP中创建IoCompletion例程。

3. 通过调用IoCopyCurrentIrpStackLocationToNext,为相邻较低层驱动程序创建IRP栈位置。

4.调用PoCallDriver,把IRP传递到相邻较低层驱动程序。

5.传递由PoCallDriver返回的状态作为其DispatchPower例程的返回值。

在IoCompletion例程中,驱动程序发送一个设备设置电源IRP的过程如下:

1.首先检查IRP得到请求的系统电源状态,然后为此系统电源状态选择一种适当的设备电源状态。详见3.5.1.1节“确定当前的设备电源状态”。

2.调用PoRequestPowerIrp,为以步骤1所确定的设备电源状态发送IRP_MN_SET_POWER。 即使设备已经处在那种状态中,电源策略所有者也必须发送设备SET_POWER请求。

3.在调用PoRequestPowerIrp指定回调例程(CompletionFunction),并且在环境区域中传递系统IRP。

4.从IoCompletion例程中返回STATUS_MORE_PROCESSING_REQUIRED,这样驱动程序能在回调例程中完成处理系统设置电源IRP。

记住,设备电源策略所有者不仅能发送设备设置电源IRP,而且当此IRP穿过设备栈还必须能处理它。因而,设备电源策略所有者不仅可以包含一个与设备设置电源IRP有关的回调例程和一个系统设置电源IRP所创建的IoCompletion例程,而且还可以包含一个为设备设置电源IRP所创建的IoCompletion例程。详见第2章中“为设备电源状态处理IRP_MN_SET_POWER”。

当设备设置电源IRP传递到设备栈中时,所创建的IoCompletion例程已经运行,回调例程被调用。这时,栈中的所有驱动程序都已完成设备设置电源IRP,同时设备电源的转变也已完成。

回调例程必须处理下列情况:

1.调用PoStartNextPowerIrp,开始下一个电源IRP。

2. 对于设备设置电源IRP,用返回的状态完成系统设置电源IRP(IoCompleteRequest)。

3. 调用 IoReleaseRemoveLock,释放以前获取的锁。

4. 用完成的设置电源IRP返回此状态

1.5.2 在总线驱动程序中处理系统设置电源IRP
当总线驱动程序接收一个系统设置电源IRP时,它必须采取下列的措施:

1. 调用PoStartNextPowerIrp,开始下一个电源IRP。

2. 把Irp->IoStatus.Status设置为STATUS_SUCCESS。驱动程序不能使系统设置电源IRP失效。

3. 调用IoCompleteRequest,指定IO_NO_INCREMENT,完成IRP。

总线驱动程序不能改变设备电源的设置,直到它收到一个请求设备电源状态的电源IRP。

1.5.3 在过滤驱动程序中处理系统设置电源IRP
对于所有过滤驱动程序和功能驱动程序,如果它们并不拥有其设备栈的电源策略,那么它们就仅仅把系统设置电源IRP传递到相邻较低层驱动程序中,其步骤如下:

1. 调用IoAcquireRemoveLock,传递当前IRP,保证当处理电源IRP时驱动程序不能接收PnP IRP_MN_REMOV_DEVICE请求。

如果IoAcquireRemoveLock返回失效状态,则驱动程序不应该继续处理IRP。相反,驱动程序应该调用PoStartNextPowerIrp,然后完成IRP,并且返回失效状态。

2. 调用PoStartNextPowerIrp。

3. 设置此IRP栈位置(IoSkipCurrentIrpStackLocation或者IoCopyIrpStackLocationToNext)。虽然驱动程序能在此IRP中创建IoCompletion例程,但是这样做的必要性不大。

4. 把这个IRP传递到相邻较低层驱动程序中(PoCallDriver)。

5. 调用IoReleaseRemoveLock。如果驱动程序为此IRP创建了一个IoCompletion例程,那么用此IoCompletion例程代替这次的调用。

6. 传递由PoCallDriver返回的状态作为其DispatchPower例程的返回状态。


--  作者:hjx_221
--  发布时间:1/23/2007 12:41:00 PM

--  
状态S0是工作状态。状态S1 、S2 、S3,和S4是休眠状态
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
62.500ms