WDM驱动开发之路
(一)了解篇
WDM模型(Windows Driver Model)是微软公司为当前主流操作系统Windows98和Windows 2000的驱动程序设计的一种构架。它和传统的win3.x和win95使用的vxd的驱动是完全不同的体系结构。不过对于最终用户来说,WDM驱动程序在Windows98和Windows2000下的表现很相似。作为驱动开发人员来说,它在两者中有很多的不同。并且Windows98中的WDM只能算是Windowss2000中的WDM的一个了集。在Windows98中有一些驱动程序只能使用VXD来实现,如串行通讯驱动等。
要写驱动程序,首先要了解操作系统的结构。在WDM体系中,windows2000操作系统中是最标准的实现方式,Windows98则是部分兼容WDM结构。照微软的说法,Windows98和Windows2000 X86(Intel 架构)版本实现二进制码兼容(参见98DDK),Windows2000 x86版本与其它CPU平台版本实现源码级兼容(因为Windows 2000是基本NT相似的结构,最底层是硬件抽象层HAL,所有我们相信它们之间能源码级兼容)。但实际上,Windows2000的WDM实现中有很多例程在Windows98中没有实现,一旦试图加载这样的WDM驱动程序到Windows98中,则不能正常加载,当然我们也有办法实现它,那就是利用“桩”技术。具体可参见Walter Oney写的《Programming the Microsoft Windows Driver Model》一书。我们首先来看看Windows 2000的系统结构,然后再来看看Windows 98的。
图一是Windows 2000的系统结构图。从图中我们可以看出:整个系统被分为两个态,用户态和核心态。
从图中可以明显看出I/O操作最后是怎样作用到硬件上的。用户态应用程序对Windows子系统进行win32 API调用,这个调用由系统服务接口作用到I/O管理器(严格地说,在Windows 系统中不存在I/O管理器这样的独立模块,这个只是为了方便叙述而将各种核心功能调用的集合称作I/O管理器,业界人士都这样称呼这个部分),I/O管理器进行必要的参数匹配和操作安全性检查,然后由这个请求构造出合适的IRP(IO Request Package,I/O请求包),并把此IRP传给驱动程序。简单情况下,驱动程序直接执行这个请求包,并与硬件打交道,从而完成I/O请求工作,最后由I/O管理器将执行结果返回给用户态程序。但在WDM体系结构中,大部分实行分层处理。即在图中“设备驱动“这部分,分成了若干层,典型地分成高层驱动程序、中间层驱动程序、底层驱动程序。每层驱动再把I/O请求划分成更简单的请求,以传给更下层的驱动执行。以文件系统驱动为例,最高层驱动只知道文件如何在磁盘上表示,但不知到怎样得到数据。最低层驱动程序只知道怎样从磁盘取出512B为单的数据块,但不知道文件怎样表示。举个更具体的生活例子。主人(最高层驱动)知道(并且需要)笔计本电脑,但不知道具体放在什么位置;而仆人(最底层驱动)却知道它放在具体什么地方,但
图一
不知道(也不需要管)怎么使用。
在WDM驱动体系中,驱动尽可能被设计成分层并且通用的。以USB驱动为例,USB总线驱动负责与硬件打交道,但不负责数据的逻辑表示。其它驱动程序只是扮演客户端驱动程序的角色,把各种请求转换成对USB总线驱动程序的请求。比如我们使用的HID驱动中的键盘驱动程序(USB接口),我们按下键时,它只是简单(当然不是想象的那么简单,只是相对于USB总线驱动而言的)地把它转化为对USB总线驱动程序的请求,然后将USB总线驱动程序得到的结果返回系统中。
还有一类驱动程序就是我们常说的过滤器驱动程序。它不负责完成基本的驱动任务,但它位其它驱动层次之间,并添加一些功能。在设计过程中,有一个原则就是不影响其它层次的功能。常见的例子是防火墙,底层实现其实是一种中间层过滤器驱动程序,负责检查IP包的进出情况,允许合法的包通过,阻止非法的包通过。
最底层的驱动程序在收到IRP后,通过硬件抽象层,然后与硬件发生作用,从而完成I/O请求工作。在这样的架构下,Windows 2000( or NT)上面的层就不需要对应每个操作系统都要开发一遍了。所以微软认为在Windows2000 x86平台下开发的驱动和其它CPU平台下Windows 2000源码级兼容。(试想一下,如果大家都用c写一个“hello world!”程序,那么只要有c编译器的操作系统平台下,运行的结果都是一致的。)
WDM驱动体系相对于Windows NT的KMD驱动体系不同之处在于它支持即插即用、拥有总线驱动和类驱动等等。WDM驱动体系重新定义驱动程序层次,以便适应即插即用系统。在这时我们引入了”驱动程序栈“的概念。驱动程序栈是WDM驱动体系中驱动层次的有序集合。可以这样理解:把各层次的驱动程序按一定顺序排列起来,各负责完成一定的功能。具体可以看以下的图示:
从图中我们可以看到,处于最下层的是总线驱动程序,上面是功能驱动程序。在总线驱动程序和功能驱动程序之间还有可能出现过滤器驱动程序(中间层驱动)。在某些特殊情况下有可能在第一个功能驱动程序层上出现几个另外的功能驱动程序。
总线驱动程序负责列举设备,也就是说,它负责发现总线上的所有设备并检测设备何时添加到总线上或何时从总线上删除。总线驱动程序每发现一个设备就创建一个对应的物理设备对象。一些总线驱动程序只是简单地控制对总线的访问权。我们知道,一旦拥有总线权时,我们就可以完成我们想做的任何工作。当然,大部分的总线驱动程序为我们完成这类总线上的所有任务。
功能驱动程序负责完成特定的功能,知道如何控制设备工作。它在驱动程序栈中位于总线驱动程序上面。功能驱动程序负责创建一个功能设备对象。在USB总线情形中,功能驱动程序必须使用总线驱动程序来访问它自己的设备。
在驱动程序栈中,可以插入各种类型的过滤驱动程序。对于总线上的所有设备,总线过滤驱动程序被添加在总线驱动之上;而对于一个特定类的所有功能的功能驱动程序添加类过滤驱动程序。设备过滤驱动程序仅对特定的设备添加。上层的过滤驱动程序添加在功能驱动程序之上,而低层的过滤驱动程序添加在功能驱动程序下面。
在WDM驱动体系中,为了实现上面所说的分层思想,也为了简化驱动程序的编写,预先提供了几种类驱动程序和总线驱动程序。主要包括如下几类:
- 人工输入设备(HID)类驱动程序
人工输入设备类驱动程序提供输入设备的一个抽象接口。实际的输入硬件可以使用不同的方法连接。这些方法被HID类驱动程序隐藏。如果是USB总线的人工输入设备,有可能要调用USB总线驱动程序,但HID类驱动提供给上层的接口是相同的,不因为底层接口的改变而有所不同。
- 静态图象体系
静态图象体系结构(STI)根本上不是一种驱动程序,而是使用小类驱动程序获得扫描仪和静态图象相机图形数据的一种手段。STI目前支持SCSI设备、串行设备、并行设备和USB设备。
- 流类驱动程序
流类驱动程序提供访问高带宽、时间关键的视频和音频数据的基础。流类驱动程序使用小类驱动程序接口到实际的硬件。我们可以编写中间过滤驱动程序来转换数据格式。
- 端口驱动程序
音频端口驱动程序和小端口驱动程序用于控制实际的硬件。通常由硬件制造商编写。
- IEEE 1394总线驱动程序
IEEE1394总线驱动程序列举并控制IEEE1394高速总线,这个总线驱动程序使用端口驱动程序访问IEEE1394硬件设备的控制电路。IEEE1394客户驱动程序发出IEEE1394请求块IRB来控制它们自己的设备(这点上和USB驱动程序很相似的)。
- USB总线驱动程序
USB总线驱动程序列举并控制低速的USB总线设备。主机控制器驱动程序(HOST设备)作为访问主要的两类USB主机控制器的标准。USB客户驱动程序使用各种IOCTL通过USB类驱动程序访问它们自己的设备。最主要的还是通过URB(USB请求块)来控制它们自己的设备。
- SCSI和CDROM/DVD驱动程序
SCSI和CDROM/DVD驱动程序用于访问硬盘、软驱、CDROM和DVD设备。和上面的相似,提供各种端口驱动程序和小端口驱动程序来访各自的硬件设备。例如:IEEE1394总线上的CDROM的请求会发送到IEEE1394总线驱动程序。
- ACPI
ACPI(高级配置和电源管理接口)总线驱动程序与PC ACPI BIOS作用,列举系统中的设备并控制它们的电源使用。
- PCI和PnPISA总线驱动程序
它们和USB总线驱动相似,列举各自总线上的设备并控制它们。PnPISA只对符合即插即用工业标准的ISA总线设备作这些工作。
还有一点必须明白,那就是I/O管理器向设备驱动程序栈发送的IRP是从栈顶进入的,理解这点很重要。这样,当用户向I/O管理器请求了它要访问的功能设备时,I/O管理器将保证它的全部请求都发送到设备栈的顶部,这样处在设备驱动程序栈中的任何层次的过滤器驱动程序或功能驱动程序都得到首先处理这些请求的机会。
这就是WDM驱动程序的简单介绍。上面我们主要讲述了Windows2000中的情形。在Windows98中很相似,但由于它继承于windows95,所有不能够所有的设备都实现WDM体系结构。有几种设备还只能使用VXD体系。如串口驱动和文件系统驱动等。
从上面我们已经知道wdm究竟是怎么回事,接下来让我们看看在Windows2000操作系统中有哪些驱动程序。请见图三。
- 虚拟设备驱动程序(VDD)是一个用户模式部件,它可以使DOS应用程序访问x86平台上的硬件。VDD通过屏蔽I/O权限掩码来捕获端口存取操作,它基本上是模拟硬件操作,这对于那些直接对裸机硬件编程的应用程序特别有用。尽管这种驱动程序在Windows 98和Windows 2000中共享一个名称并且有相同的功能,但实际上它们完全不同。我们用VDD缩写代表这种驱动程序,用VxD缩写代表Windows 98中的虚拟设备驱动程序,以示区别。
- 内核模式驱动程序的分类包含许多子类。PnP驱动程序就是一种遵循Windows 2000即插即用协议的内核模式驱动程序。准确地说,本书涉及的所有内容都是面向PnP驱动程序的。
- WDM驱动程序是一种PnP驱动程序,它同时还遵循电源管理协议,并能在Windows 98和Windows 2000间实现源代码级兼容(有限兼容,只限于两者都支持的功能)。WDM驱动程序还细分为类驱动程序(class driver)和小类驱动程序(minidriver),类驱动程序管理属于已定义类的设备,小类驱动程序向类驱动程序提供厂商专有的支持。
- 显示驱动程序是用于支持显示和打印设备的内核模式驱动程序。
- 文件系统驱动程序在本地硬盘或网络上实现标准PC文件系统模型(包括多层次目录结构和命名文件概念)。
- 遗留设备驱动程序也是一种内核模式驱动程序,它直接控制一个硬件设备而不用其它驱动程序帮助。这种驱动程序主要包括Windows NT早期版本的驱动程序,它们可以不做修改地运行在Windows 2000中。
以上简单介绍了Windows2000中的驱动程序种类。更详细的内容可以参看其它书籍。如果想对Windows2000操作系统有深入的了解,请参见《Inside Windows 2000》一书。