WDM驱动程序设计[1]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 candycat 的 blog

wdm驱动程序设计 作者:汤琳 发布时间:2001/03/14
 
文章摘要:
  现在windows98和windows2000已经成了主流操作系统的主流,原先用来实现驱动程序的vxd技术随着win95的淡出也慢慢地将退出历史舞台,在windows98和windows2000中设备驱动程序将根据windows驱动程序模型(wdm)来设计。wdm通过提供一种灵活的方式来简化驱动程序的开发,在实现对新硬件支持的基础上减少并降低所必须开发的驱动程序的数量和复杂性。
       

正文:  



wdm驱动程序设计
  


一.wdm简介
  微软不断推出新的操作系统,现在windows98和windows2000已经成了主流,原先用来实现驱动程序的vxd技术随着win95的淡出也慢慢地将退出历史舞台,在windows98和windows2000中设备驱动程序将根据windows驱动程序模型(wdm)来设计。wdm通过提供一种灵活的方式来简化驱动程序的开发,在实现对新硬件支持的基础上减少并降低所必须开发的驱动程序的数量和复杂性。
  windows驱动程序模型分两个方面,除了核心模型描述设备驱动程序的标准结构外,wdm还为常见类型的设备实现了一个模块化的、分层次类型的总线驱动程序和类驱动程序。总线驱动程序实现了支持通用串行总线(usb)、ieee1394(firewire)协议等。类驱动程序是为实现标准windows功能提供条件。wdm对标准类接口的支持减少了windows 95和windows nt所需的设备驱动程序的数量和复杂性。在windows平台上,wdm将成为21世纪主流的驱动模式。
  wdm支持usb、ieee 1394、acpi等全新的硬件标准。而且以往在两个平台上同时运行时需要编写两个截然不同的驱动程序,现在只需要编写一个wdm驱动程序就可以了。wdm驱动程序也是分层的,即不同层上的驱动程序有着不同的优先级,而windows 9x下的vxd则没有此结构。

 

  wdm还引入了功能设备对象fdo(functional device object)与物理设备对象pdo(physical device object)两个新类来描述硬件,一个pdo对应一个真实硬件。一个硬件只允许有一个pdo,却可以拥有多个fdo,在驱动程序中直接操作的不是硬件而是相应的pdo与fdo。在用户态和内核态通讯方面,系统为每一个用户请求打包形成一个irp结构,将其发送至驱动程序,并通过识别irp中的pdo来区别是发送给哪一个设备的。另外,在驱动程序的加载方面,wdm不通过驱动程序名称识别,而是通过一个128位的全局唯一标识符guid来实现驱动程序的识别。我们用上图来说明设备驱动程序的分层及调用。
  写wdm和其它模式驱动程序基本上是相同的,代码中的主要区别在于如何创建设备。
  在wdm驱动程序中,即插即用(pnp)管理器告知何时向系统添加一个设备,或者从系统删除设备。pnp管理器使用安装的inf文件查找新设备的正确驱动程序;而其它模式驱动程序必须发现它自己的设备,使用专门的安装程序安装。
另外在细节上也存在很多区别,其它模式驱动程序参数一般由注册表提供,在driverentry里调用读注册表的函数,然后根据注册表再调用createdevice,但是wdm一般不是这样,这是由于windows 2000下支持pnp,在加载的时候pnp管理器调用adddevice入口点创建设备。一般在driverentry里创建的是一个与设备或者对象毫无关系的虚拟设备,用于管理与win32的通讯。如果不想对该设备做什么特别的处理,或者设备不复杂,adddevice可以简单返回nt_success,不用调用createdevice。
  另外整个设备驱动树也发生了改变,从而使安装程序发生了很大的改变。wdm本身的pnp管理器被抽象地提升到了root的地位。pnp管理器负责所有的总线驱动程序的加载。总线驱动程序则负责遍历所有位于总线上的设备,并且为每个设备创建相应的设备对象。当pnp管理器发现一个设备对象,就查找该对象对应的driver。并调用该driver的add device例程。如果driver不在内存中,就先加载,然后调用add device例程。
  当然,总线本身并没有发出任何信号告诉pnp管理器自己的存在,所以,总线driver是在nt的安装时设定的。而isa设备并没有规范,因为需要kmd自己检查硬件存在及状态,所以它是老式kmd存在的惟一理由。这也是微软极力在新规范里取消isa总线的理由之一。wdm支持pnp协议和pm协议,而且实现时仅仅需要在major function里加入一些对pnp和pm事件响应的例程即可。
  一个完整的驱动程序要完成以下工作:初始化;创建与删除设备;处理应用层程序的打开和关闭句柄的请求;处理应用层程序的输入/输出请求;串行化对设备的访问;访问硬件;调用其他驱动程序;取消i/o请求;超时i/o请求;处理可热插拔设备的加入和删除事件;电源管理和wmi。

二.开发设备驱动程序

2.1设计工具ddk的安装

  编写wdm设备驱动程序我们需要microsoft的驱动程序开发工具包ddk。尽管微软宣称wdm驱动程序是windows98和2000之间二进制兼容的,为了安全起见我们还是在不同的系统下仅安装相应的ddk。

(一).windows 98 ddk的安装
  这一部分描述如何安装windows 98 ddk。我们约定%98ddk%为安装windows 98 ddk的根目录;%mstools%为微软sdk平台的根目录;%vcppdev%为安装的vc++开发环境的根目录。
  使用ddk的软件平台通常为windows 98操作系统和vc++ 4.2或5.0版本,若要编译视频捕获示例则需要vc++ 5.0版本。你必须在安装windows 98 ddk之前先安装vc++编译/开发环境,否则运行时,windows 98 ddk的setenv.bat文件将不能建立正确的编译环境 。阅读ddk 文档需要ie 4.01以上版本,如果是从光盘或需要测试光盘驱动程序则需要光驱,16mb内存是不可少的,完整安装需要82mb硬盘空间(最小安装需要32mb硬盘空间)。
  windows 98 ddk所带的所有驱动程序例子都不需要在安装有sdk的平台下构造。不过,如果你开始开发自己的驱动程序,可能需要windows 98 ddk中没有而是在sdk平台中的头文件,因此可以考虑两种方法:拷贝所需的头文件或sdk平台的文件到在%98ddk%和%vcppdev%下适当的include 目录中;也可以直接安装sdk平台,编辑%98ddk%\bin中setenv.bat文件,并运行安装在%mstools%里的setenv.bat文件。
  用setup程序安装ddk,步骤为:
  (1)运行windows 98 ddk中的setup.exe文件,按照对话框提示安装windows 98 ddk到%98ddk%。
  (2)安装vc++ 5.0到%vcppdev%。
  (3)修改config.sys增大环境变量空间。在config.sys文件最后加入一行:
  shell=c:\windows\command.com /p /e:4096
  在安装windows 98 ddk之前,必须先安装vc++编译器/开发环境,否则运行时,win
dows 98 ddk的setenv.bat批处理文件将不能建立正确的环境。
  下面介绍建立windows 98驱动程序构造环境以及利用构造环境和工具构造驱动程序的方法。
  1. 用setenv.bat来安装驱动程序构造环境
  开始菜单中有"development kits\windows 98 ddk"的目录。这个目录包括自由构造环境项和检查构造环境项。每次重启操作系统,在构造驱动程序前,单击这些程序文件夹中合适的一项。这些项调用%98ddk%\bin里的setenv.bat批处理文件来创建正确的环境变量的驱动程序构造环境。

  2. 手工运行setenv.bat
  在ms-dos提示符下,或在"开始/运行"中使用下列语句:
  setenv  %98ddk%  [free | checked]
  例如,在c:\98ddk\bin〉提示符下,键入setenv c:\98ddk free,其中第一个参数指定ddk被安装的文件夹,注意缺省安装是\98ddk;可选的第二个参数说明目标构造环境,缺省类型是free。

  3. 构造wdm驱动程序
  使用一系列规则以指定驱动程序怎样被创建,构造实用程序可用来在windows 98 和windows nt平台上构造wdm驱动程序。
  在windows 98 ddk被安装之后,wdm驱动程序构造树的工作例子和组成部分文件在硬盘上就可以得到了。驱动程序构造树根目录在%98ddk%\src。查看%98ddk%\inc里makefile.def文件的内容,以及贯穿驱动程序构造树的各种的dirs文件和源文件的内容,可以利用这些代码作为工作实例。

  4.构造驱动程序
  在当前目录的驱动程序构造树中创建一个子目录,然后,运行构造实用程序。在构造树的当前目录中,构造实用程序可以自动创建出驱动程序的源代码。构造实用程序在windows 98 ddk例子驱动程序构造树的根目录下(%98ddk%\src)运行。例如,如果仅仅对为声音设备类构造的例子驱动程序有兴趣,可以设置当前目录到%98ddk%\src\audio上,然后,运行构造实用程序。

  5.检查windows 98 ddk的安装
  经常使用的构造指令形式为build -cz ;从而使构造实用程序做相关文件的扫描,执行完整的创建,并生成错误记录。检查安装的方法为:在\〈destination〉\src目录运行build -cz,构造安装的例子驱动程序源代码的完整集。这个实用程序在构造驱动程序之前构造全部相关文件,自动建立文件关联关系。这个过程可能需要30多分钟。如果构造没有完成或报告过多的编译错误,则需要确认是否正确执行了以上的安装步骤。通过安装ddk和相应的开发软件,我们构造好了wdm驱动程序的开发环境。接着,我们就要深入进行设计与开发工作了。
  安装ddk后,在ddk程序组下有检查check和自由free两个编译环境,check环境用于编译带调试信息的驱动程序,free则是编译正式发布版本的环境。通常情况下设备驱动程序的编译采用命令行的方式。通过一定的设置可以在vc ++的集成环境下编译。
  一般来说,成功编译一个最基本的设备驱动程序需要四个文件,第一个是驱动程序,即c语言源程序文件(例如isousb.c,注意下面所有的例子都是以isousb来说明);第二个是rc文件(例如isousb.rc);第三个是sources文件;第四个文件是makefile文件。sources文件和make文件类似,用来指定需要编译的文件以及需要连接的库文件。这三个辅助文件都很简单,在ddk samples的每个例程里都有三个这样的文件,依样画瓢就能理解它们的结构和意义。

1.举例分析
  以下以isousb程序为例,设isousb.rc代码为:
  #include <windows.h>
  #include <ntverp.h>

  #define ver_filetype vft_dll
  #define ver_filesubtype vft2_unknown
  #define ver_filedescription_str "i82930 isochronous io test driver"
  #define ver_internalname_str "isousb.sys"
  #define ver_originalfilename_str "isousb.sys"

  #include "common.ver"
  设备驱动程序一般都使用build实用程序来进行,build只是nmake外面的一个外包装程序。build本身其实相当简单,编译的大部分工作实际上由build传递给nmake来进行。

  /sources/
  targetname=isousb
  targettype=driver
  targetpath=$(basedir)\lib
  drivertype=wdm

  includes=$(basedir)\inc; \
  $(basedir)\src\usb\inc; \
  $(basedir)\src\wdm\usb\inc; \
  .. \..\inc

  targetlibs=$(basedir)\lib\*\free\usbd.lib

  use_mapsym=1

  sources= \
  isousb.rc \
  iusbdbg.c \
  isousb.c \
  isopnp.c \
  isopwr.c \
  ioctliso.c \
  isostrm.c \
  ocrwiso.c
  /end of sources/
  注意sources的文件名没有任何扩展名。
  # makefile
  ###########################################################################
  #
  # copyright (c) microsoft corporation 1995
  # all rights reserved.
  #
  # makefile for wdm device driver kit
  #
  ###########################################################################

  #
  # do not edit this file!!! edit .\sources. if you want to add a new source
  # file to this component. this file merely indirects to the real make file
  # that is shared by all the driver components of the windows nt ddk
  #

  !include $(ntmakeenv)\makefile.def
  # end of makefile
  对所有驱动程序而言,makefile都是一样的,microsoft也警告不要编辑这个文件,如果需要,可以编辑修改sources文件达到同样的效果。对于设备驱动程序,所使用的c编译器基本上无一例外地选用vc++。

2.编译的基本步骤
  (1)首先进入check或free编译环境,初始化ddk编译环境。
  (2)运行vc安装目录下bin目录下的vcvars32.bat,初始化vc++编译环境。
  (3)运行build.exe进行编译。

(二).windows2000 ddk的安装

  由于前面我们已经详细介绍了windows98 ddk的安装,我们在这里主要介绍一下windows2000 ddk安装与windows98 ddk的不同。
  两者对系统的要求不同,windows2000 ddk需要windows2000或windows98操作系统,vc++5.0或6.0专业或企业版,至少64mb内存,推荐128mb或更多的内存,完全安装需要200mb,而且如果你在windows2000下安装的话,必须以管理员的身份登录。

2.2设备驱动程序的设计
  i/o请求包(irp)是驱动程序操作的中心,irp是一个内核对象,它是一个预先定义的数据结构,带有一组对它进行操作的i/o管理器例程。i/o管理器接收一个i/o请求后分配并初始化一个irp。一个irp有一个固定的首部和可变数目的irp栈单元块,每个i/o请求有一个主功能代码(irp_mj_xxx)并可能有次功能代码(irp_mn_xxx)。设计一个设备驱动程序,应该支持和其他相同类型设备的驱动程序相同的irp_mj_xxx和ioctl请求代码。如果设计一个中间层驱动程序,应该首先确认下层驱动程序所管理的设备,因为一个高层的驱动程序必须具有低层驱动程序绝大多数irp_mj_xxx例程入口。高层驱动程序在接到i/o请求时,在确定自身irp当前堆栈单元参数有效的前提下 ,设置好irp中下一个低层驱动程序的堆栈单元,然后再调用iocalldriver将请求传递给下层驱动程序处理。一旦决定好了驱动程序应该处理哪些irp_mj_xxx,就可以开始确定驱动程序应该有多少个dispatch例程。当然也可以考虑把某些irp_mj_xxx处理的例程合并为同一例程处理。

本文关键:WDM 驱动程序 VC
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top