转载注明 >> 【作者:张佩】【镜像:http://www.yiiyee.cn/Blog/pnp/】
这一节讲述一般设备的PNP和电源特性。
PNP特性
PNP是Plug And Play的简称,代表和外部设备插拔有关事件的处理。PNP是现代操作系统必须支持的基本特性,其目的是希望操作系统能够在软硬件支援下,在基本无需用户干预的情况下,即可很好地处理外部设备的接入和移除操作;当设备配置发生动态变更时,系统也能悄没生息地处理好,并一切正常地使用它们。
有些笔记本是当成工作站来用的,这样就需要很多外部接口。但一般的笔记本,局限于物理空间,不能够提供过多的外部接口,会使用接口坞来扩展(见左图例)。大的接口坞上通常有十几、数十个扩展接口,来满足工作站的接口要求。其实,一些移动设备,如手机、平板电脑,也使用接口坞的方式实现扩展,不过接口少一些。接口坞接入主机的时候,系统如果有PNP支援,就能够直接使用上面的接口了,不用重启系统,一般也不用手动安装设备驱动。
PNP特性,需要操作系统、驱动程序和硬件的三方支持。缺了某一方都不能实现。比如PCI设备,虽然可以在PCI驱动程序中实现某种程度的PNP支持,但因为设备本身的电气化特性,是不支持PNP的,所以我们仍不能热插拔PCI设备。另外一种情况是,如果设备驱动写得不好,未能正确地处理PNP请求,那么即使设备本身是支持热插拔的,也会有问题。比如现在很多定制的USB设备,如加密U盘、网银密码器等,如果驱动写的不好,用户往往会在插拔设备的时候遭遇蓝屏。
概括地讲,为了很好地支援PNP特性,需要做到下面几点:
- 运行时识别设备。不仅在系统初始化的时候,能识别并正确配置设备。在系统正常运行的过程中,如果有设备动态接入,也能够正确识别并配置设备;如果设备动态移除,也能够正确响应并回收系统资源。
- 系统还需要为设备动态加载设备驱动程序。设备的驱动信息保存在注册表中,系统从注册表中查找设备的驱动信息。如果注册表中找不到相关记录,系统会尝试自动为设备安装驱动,否则就通过UI界面,要求用户手动安装驱动。
- 动态识别并配置设备。操作系统可以动态配置外部设备,而不应假设只有某些设备会接入系统,并为它们静态分配或保留系统资源。不能因为新设备的动态接入而令系统陷入错误状态,比如系统停止响应,系统崩溃等。操作系统要有为设备动态分配系统资源的能力,这些系统资源包括:IO地址空间、物理内存映射、中断、DMA等。设备驱动再根据它所动态获取的资源来配置设备。比如一个支持硬件中断的设备,它每次从系统处获得的中断号,都可能不同。那么设备和驱动程序,就不能假定设备的中断号是一个固定的值。
- PNP接口。操作系统中有一个PNP管理器模块,包含用户和内核两个子模块,所以它能够对用户程序和内核驱动分别提供PNP支持。它们和设备驱动、用户程序之间,有一个定义良好的接口。这个接口用来互相通知PNP事件。简略地讲,它包含三个方面:
- 1. 当PNP管理器检测到PNP事件的时候,能够把这些事件通知给设备驱动。包括设备接入、移除、异常移除等。
- 2. 当设备驱动需要向系统报告子设备的时候,能把这个信息通知给系统。当用户程序想动态移除指定设备的时候,也可能通过UI程序实现,这些UI程序实际上是调用了系统提供的PNP接口来实现的。比如我们在移除U盘设备的时候,一般不会直接拔除,而是先通过托盘栏中的弹出设备程序移除设备,以免破坏数据。
- 3. 驱动或用户程序,还可以通过注册通知函数,来接收PNP通知。比如内核驱动可以通过调用IoRegisterPlugPlayNotification函数注册一个通知函数,当感兴趣的目标发生PNP事件时,PNP管理器就会调用它的通知函数,并通过参数告知它PNP事件的详细信息。用户程序也可以通过WM_DEVICECHANGE消息来接收设备PNP的通知。
- 这套接口,主要由PNP管理器所提供的若干接口函数,若干类型为IRP_MJ_PNP的IRP包,及驱动程序所提供的AddDevice回调来实现。
电源特性
电源操作的目的是类似的,也是为了能够在用户尽量少介入的情况下,就能够正确地配置和使用外部设备。现代计算机和操作系统,都实现了多个级别的系统和设备电源状态。系统和设备可以在这些电源状态之间进行切换,并达到正常情况下全力供电,空闲情况下尽量省电的目的。
系统的电源状态用S0-S5来标识。S0是正常状态,S1-S3是休眠状态,但休眠的深度有差别,S4是睡眠状态,S5是软关机状态(Soft Off,不完全等同于断电)。除了S0和S5这两个必须支持的状态外,系统还支持哪些电源状态,是由系统BIOS决定的。一般来讲,计算机系统都会支持S3和S4这两个状态。否则除了开机就是关机,电脑用起来会很麻烦。
设备的电源状态用D0-D3来标识。D0是正常状态,D1-D2是休眠状态,但深度有差别,D3是断电状态。其中D3还分Hot和Cold两种子状态。
在D3Hot状态下,设备的功能已丧失但仍有外部或总线供电,使得设备本身还能被系统检测到。和设备相连的控制器设备认为此设备还连接着,只要控制器上有设备连接着,控制器就要处于工作状态。但在D3Cold状态下,系统已检测不到设备,这可能是由于设备的已经断电了,或者系统本身已经处于休眠状态而导致的。和设备连接的控制器,已经不认为设备和自己连着,在其它条件满足的情况下,控制器可以进入完全的休眠状态。
设备电源状态,需要由设备本身和设备驱动一起来实现。有些设备只支持正常和断电两种状态(即D0和D3),而没有休眠的功能。那么设备驱动只需要处理D0和D3两种状态即可。有些设备则提供了休眠功能(即可进入D1或D2状态),驱动程序在这种情况下,仍然可以决定支持或不支持设备的休眠状态。在支持的情况下,当设备进入休眠状态时,驱动程序负责关闭部分硬件模块,让其它模块继续工作。
系统中有一个电源管理器模块,它负责系统范围内的电源策略。当系统的电源状态发生变化时,它负责把要进行的电源操作及电源状态,通知给每个设备栈,让它们来处理电源变化。设备驱动需正确地处理电源事件,有很多系统蓝屏就发生在驱动程序处理电源事件的过程中。
物理设备的功能设备驱动,一般就是这个物理设备的电源策略制定者,功能设备驱动在设备初始化的时候,会把设备电源状态映射到系统电源状态,并把这个映射汇报给电源管理器。这样电源管理器就可以根据系统电源状态,发送相应的设备电源状态给设备驱动。这个映射体现在设备管理器程序中的设备属性界面中,我们可以通过它来观察不同设备的电源状态映射。下图就是一个例子: