电源管理是WDM驱动的一个重点和难点,需要处理好,否则在测试、使用过程中很容易出现各种异常。最严重的就是 bug check 0x9F 相关的各种BSOD。
这里简单介绍下,power Irp包括两类,一类是系统状态相关power Irp(system-irp),另一类是设备状态相关power Irp(device-irp)。我们在Driver Entry中注册的dispatch可以接受上述system-irp和device-irp。本文下面提到的system-irp/device-irp都是指system power irp/device power irp。
本节只介绍下面四种power相关Irp,包括 IRP_MN_QUERY_POWER System-Irp,IRP_MN_QUERY_POWER Device-Irp,IRP_MN_SET_POWER System-Irp,IRP_MN_SET_POWER Device-Irp。
上述四种power相关Irp,系统在转换power state时会首先下发system-Irp,设备的 function driver收到后,会产生一个与之对应的device-Irp,并通过系统下发到power dispatch。处理的流程是首先将system-Irp设置为pending,在device-Irp处理完毕后,依据返回状态设置system-Irp的status,再complete此 system-Irp。具体的处理流程可以参考后面的详细介绍。
上述四种power相关Irp可以依据不同的标准划分,可以划分为system、device相关,还可以划分为 query、se、wakeup相关。本节只讨论query、set相关的power Irp。这里简单描述下query和set的区别。Query通常是用于系统询问设备,是否可以进入某种power状态。Set通常在query之后发送,是系统明确要求设备进入某种power状态。
下面依据query、set的分类来描述下上述Irp的处理过程。
IRP_MN_QUERY_POWER :
1) 系统会下发IRP_MN_QUERY_POWER system-irp
2a) Function Driver收到 IRP_MN_QUERY_POWER system-irp
-function driver设置I/O completion call back,以便在底层bus driver返回时做一些必要的处理
-function driver将此Irp继续向底层driver发送
-function driver返回STATUS_PENDING
在底层bus driver处理完毕,complete此system-irp后,会call到上述的I/O completion call back A函数
2b) 2a)中提到的I/O completion call back A中需要请求Power Manager依据上述IRP_MN_QUERY_POWER system-irp的内容,发送一个IRP_MN_QUERY_POWER device-irp。在请求PM下发IRP_MN_QUERY_POWER device-irp的同时,设置completion call back B函数,同时返回STATUS_MORE_PROCESSING_REQUIRED。
2c) function driver收到IRP_MN_QUERY_POWER device-irp,可以complete with Success(可以允许device进入要求的状态) or fail(禁止device进入要求的状态)。
在这之后,系统会call到2b)中提到的completion call back B。
2d) 在completion call back B中将IRP_MN_QUERY_POWER system-irp的status设置为IRP_MN_QUERY_POWER device-irp的status。同时complete IRP_MN_QUERY_POWER system-irp。
2c)中提到的允许/禁止系统进入想要进入的状态并非always生效,在某些情况下系统可以不care这些result直接通过IRP_MN_SET_POWER来要求device进入相应的状态。
IRP_MN_SET_POWER :
3) 系统会下发IRP_MN_SET_POWER system-irp
4a) Function Driver收到 IRP_MN_SET_POWER system-irp
-function driver设置I/O completion call back,以便在底层bus driver返回时做一些必要的处理
-function driver将此Irp继续向底层driver发送
-function driver返回STATUS_PENDING
在底层bus driver处理完毕,complete此system-irp后,会call到上述的I/O completion call back C函数
4b) 4a)中提到的I/O completion call back A中需要请求Power Manager依据上述IRP_MN_SET_POWER system-irp的内容,发送一个IRP_MN_QUERY_POWER device-irp。在请求PM下发IRP_MN_SET_POWER device-irp的同时,设置completion call back D函数,同时返回STATUS_MORE_PROCESSING_REQUIRED。
4c) function driver收到IRP_MN_SET_POWER device-irp,需要明确Set power的state,确认是power-up还是power-down。
4c1) 如果是power-up irp,首先需要将此irp下发至底层bus driver,因为device首先需要底层bus供电。除此之外,function driver还需要等待所有pending irp结束后方可开始操作。当然function driver不可以直接阻塞等待,因为会影响到系统的运行。通常的做法是:
-function driver将此device-irp设置为pending,并设置I/O completion call back E,在底层bus driver处理完毕后会call到此call back。之后将此irp下发至底层driver,并返回STATUS_PENDING,此时system-irp、device-irp都处于pending状态
-在bus driver complete上述device-irp后,会call上述I/O completion call back E,此时function driver仍然需要等待之前处于pending的irp结束。由于在completion call back中无法死等,因此需要透过system work thread在PASSIVE_LEVEL来处理。可以设置一个workitem A,并返回STATUS_MORE_PROCESSING_REQUIRED。
-system worker thread会在PASSIVE_LEVEL调用上述workitem A,可以等待所有处于pending的irp结束后在返回。最终会complete上述device-irp。
4c2) 如果是power-down irp,function driver需要在下发此device-irp之前做一些必要的处理,因为一旦bus driver断电后,resume时所需的一些必要操作将变得不可访问。
-function driver可以通过设置workitem B,并返回SSTATUS_PENDING。而在system worker thread PASSIVE_LEVEL中做一些必要的backup操作。
-system worker thread会在PASSIVE_LEVEL调用上述workitem B,在backup动作完成后,将此device-irp下发至底层driver。
4d) 在completion call back D中将IRP_MN_QUERY_POWER system-irp的status设置为IRP_MN_QUERY_POWER device-irp的status。同时complete IRP_MN_QUERY_POWER system-irp。