模块化的设备驱动程序设计方法

导读:
  (1.辽宁工程技术大学机械工程学院,辽宁阜新1230002.华中科技大学材料科学与工程学院,湖北武汉430074)
  摘 要:介绍了Windows NT下设备驱动程序的开发环境,一种模块化的设计方法,应用程序与驱动程序之间的同步以及驱动程序的安装。

 

模块化的设备驱动程序设计方法

刘冠权1,程俊廷1,刘帅军2

(1.辽宁工程技术大学 机械工程学院,辽宁阜新 123000
2.
华中科技大学 材料科学与工程学院,湖北武汉 430074)


    摘  要
介绍了Windows NT下设备驱动程序的开发环境,一种模块化的设计方法,应用程序与驱动程序之间的同步以及驱动程序的安装。
    关键词Windows NT;设备驱动程序;Event对象


1
        Windows NT/2K
以其形象直观的界面、简单方便的操作,基本上已经取代DOS成为测控软件的操作平台。又因为Windows NT/2K出于安全性、稳定性的考虑,为了防止用户应用程序访问和更改重要的操作系统数据,Windows NT/2K使用两种“处理器访问模式”:用户态和核心态。在用户态,应用程序不能直接对硬件进行访问和操作;而在核心态中,程序对任何I/O备有全部的访问权,还能访问任何虚地址和控制虚拟内存硬件。为了使用户态的程序访问和操作硬件,必须通过某种机制,也就是使用设备驱动程序跨越操作系统的边界对物理硬件进行访问操作。同时提供一些控制接口,进而用户态的应用程序利用设备驱动程序提供的接口间接地对物理硬件进行访问操作。
2
设备驱动程序的开发环境

    安装
4种软件:Microsoft Visual C++6.0Platform SDK(Software Develop Kit) for Windows NTDDK(Device Develop Kit) for Windows NTDriverStudio2.0 。然后进行一些系统环境变量的设置:
        (1)
变量名:MSTOOLS,值:SDK在操作系统中的安装路径(如:C:/mstools)
        (2)
变量名:CPU,值:i386
        (3)
变量名:BASEDIR,值:DDK在操作系统中的安装路径(如:C:/NTDDK)
    在开发驱动程序时,首先要生成
DriverStudio需要的库文件vdw.lib(通过编译DriverStudio安装目录下\DriverWorksSourcevdw.dsw)。然后运用DriverStudio2.0生成一个编程框架,并删除DriverStudio所生成的编程框架中的所有文件,就可以在这个框架中编写自己的设备驱动程序;编写完以后可以直接在Visual C++6.0Build生成设备驱动程序*.sys
3
模块化驱动程序的编写

3.1
设备驱动程序包括的几大模块

    设备驱动程序管理实际数据传输和控制物理设备的操作,包括开始和完成
I/O操作、处理中断和执行设备要求的任何操作。
    一般通用的设备驱动程序可以分为主要
4个模块:初始化例程、卸载例程、驱动程序和应用程序之间的数据交换例程、中断服务例程。
3.1.1
初始化例程(DrvierEntry)
    是驱动程序的入口。在这个例程中主要包括以下步骤:

        (1)
初始化Driver对象;
        (2)
调用IoCreateDevice创建一个Device对象,并通过调用IoCreateSymbolicLinks使设备对Win32子系统可见;
        (3)
初始化Device对象的DeviceExtension;
        (4)
查找和分配驱动程序要管理的任何硬件;
        (5)
把一个设备连接到一个Interrupt对象,如果需要并初始化驱动程序的DPC对象。
3.1.2
卸载例程(DriverUnload) 
    它与驱动程序的初始化例程刚好相反。

        (1)
把与设备连接的Interrupt对象断开。一旦Interrupt对象消失,设备不产生任何中断请求,这是最重要的;
        (2)
释放驱动程序所占用的任何系统资源;
        (3)
使用IoDeleteSymbolicLinkWin32名字空间删除设备,并用IoDeleteDevice删除Device对象自身。
3.1.3
驱动程序与应用程序之间的数据交换例程
    首先简单介绍一下
I/0请求包(IRP)IRPI/O系统用来存储I/O请求信息的地方。IRP由两部分组成:固定部分(称作标题)和一个或多个堆栈单元。固定部分信息包括:请求的类型和大小、同步请求还是异步请求,用于缓冲I/O的指向缓冲区的指针和由于请求的进展而变化的状态信息;IRP的堆栈单元包括一个功能码、功能特定参数和一个指向调用者文件对象的指针。
    应用程序与驱动程序交换数据主要是由
Win32 CreateFileCloseHandleReadFileWriteFileDeviceIoControl函数发出请求,接着I/O管理器把这些请求转化为叫做I/O请求包(IRP)的数据结构形式,再由I/O管理器把这些I/O请求包发送到驱动程序。数据交换例程的主要作用是接收I/O管理器所发出的IRP,然后解析这些IRP,从而得知IRP从应用程序传递过来的数据。解析IRP主要是运用C语言的switch语句,根据IRP的堆栈单元中的参数(IRP_MJ_CREATEIRP_MJ_READIRP_MJ_DEVICE_CONTROL)进行不同的处理。最后IRP的完成处理也非常重要,它要做的是返回系统,完成一个I/O请求的信息,系统根据返回的信息释放IRP,以便使系统顺利进行下一个IRP的处理。这里需要说明的是这个例程只是完成了数据从应用程序到驱动程序的传递,而没有进行任何实际的设备操作。
3.1.4
中断服务例程
    中断服务例程主要是进行直接的任何设备的操作。驱动程序与应用程序之间的数据交换例程只完成了数据从用户空间到核心空间的传递,而中断服务例程根据传递过来的数据,直接对
I/O端口进行访问操作。
3.2
设备驱动程序的模块化实现

    每个
NT内核模式驱动程序,不管它的用途是什么,都必须显露一个叫做DriverEntry的例程,也就是设备驱动程序的初始化例程。它是驱动程序的入口点,DriverEntry是一个公认的名字(任何内核驱动程序的入口点必须用这个名字,不能改变),有了这个公认的名字,I/O管理器就能顺利地为每个驱动程序找到入口点并对其进行初始化。
    一些函数声明:
    ∥初始化Driver对象
    VOID InitializeDriverObject(IN PDRIVER_OBJECT  DriverObject);
    ∥创建一个Device对象和使设备对Win32子系统可见
    NTSTATUS CreateDevice(IN  PWSTR  DriverName,
    IN  DRIVER_TYPE DriverType,
    IN  PDRIVER_OBJECT  DriverObject,
    OUT  PDEVICE_OBJECT  *DeviceObject);
    ∥初始化DeviceExtension

    VOID InitializeDeviceExtension(IN PDEVICE_OBJECT DeviceObject,

    IN PDEVICE_EXTENSION DeviceExtension);
    ∥查找并给设备分配资源

        NTSTATUS QueryAndAllocateHardware(IN PUNICODE/--STRING path,

        IN PDEVICE_OBJECT DeviceObject);

    ∥连接一个中断

        NTSTATUS DriverConnectInterrupt(

        IN PDEVICE_EXTENSION DeviceExtension);

    如果以上几个函数中,有函数返回不成功的状态值时,一定要删除在调用这个函数之前创建成功的,可能是以下
3个中的1个和多个:创建的Device对象、Win32名字空间的设备和给设备分配的系统资源。
         NTSTATUS  DriverEntry(IN PDRIVER_OBJECT




            }
4 应用程序与驱动程序之间的同步
    一般在设备驱动程序中用中断服务例程来访问和操作硬件设备,它利用应用程序传递过来的数据进行中断操作。为了保证外界设备正常工作,在驱动程序中一定要有一个缓冲区来存储一定数量的数据。例如在数控加工中,让机床切一个圆,必须保证机床在切这个圆时的动作连续,如果没有一个缓冲区存储一定数量的数据,就有可能出现驱动程序等待应用程序传递数据,从而造成机床的暂时停顿。然而如果在驱动程序中开一个缓冲区来存储数据,也会产生一个问题:应用程序传递的数据与这些数据的执行之间有一定的时间差,导致应用程序不知道设备正在进行什么操作。为了解决这个问题,也就是要保证应用程序与驱动程序之间的同步。有了这个同步信号,可以让应用程序了解设备正在进行何种操作。解决同步问题可以用Event对象。
    具体方法:在驱动程序中创建内核的
Event对象,但是又因为驱动程序和应用程序分别运行于核心层和用户层,因此他们之间要看到对方定义的事件相对比较困难,必须要有一个专门的事件名存放空间。这里有一个命名方法可以使用户层和核心层都可看到Event对象,事件命名应为LBaseNamedObjectsxxx形式。
    在核心层用
IoCreateNotificationEvent创建一个Event对象,用KeSetEventEvent对象设置为Signal。用户层用OpenEvent创建Event对象,这个Event对象名一定要与在核心层创建Event对象名一样,然后用户层用WaitForSingleObject等待Event对象的状态为Signal一旦Event对象的状态为Signal,让应用程序访问一次驱动程序,从而可以让应用程序知道设备正在进行的操作,保证应用程序与驱动程序之间的同步。
5
设备驱动程序的安装

    设备驱动程序的安装可以分为:手动安装、非标准驱动程序的最终用户安装和标准驱动程序的最终用户安装。这里主要介绍前两种方法。

5.1
手动安装

    主要用于驱动程序的开发过程中,主要执行以下的基本步骤:

        (1)
把编译好的*.sys文件拷贝到系统的%SystemRoot%system32drivers目录下。
        (2)
在注册表中加入合适的项:

        (3)
使用控制面板中的Device应用小程序启动驱动程序。
5.2
非标准驱动程序的最终用户安装
    主要是使用下面一些
Win32 API调用建立自己的安装程序:
        (1)CopyFile
把驱动程序文件(包括一些自己定义的参数文件)拷贝到指定的目录。
        (2)RegCreateKeyEx
RegSetValueExRegistry中建立驱动程序需要的键和值。
        (3)CreateService
StartService创建和启动驱动程序。
        (4)OpenService
DeleteService来卸载驱动程序。
6
结论

    通过模块化的方法介绍了驱动程序的写法、驱动程序的开发环境和安装,给读者一个清晰的驱动程序的开发过程,有助于初学者快速抓住驱动程序开发的框架。

参考文献

[1] David A.Solomon. Windows NT技术内幕[M].北京:清华大学出版社,1996.
[
2] Walter Oney. Windows驱动程序模型设计[M].北京:北京大学出版社,1998.
[
3] Art Baker. Window NT设备驱动程序设计指南[M].北京:机械工业出版社,1999

机电工程

本文转自http://www.bjx.com.cn/files/wx/jdgc/2003-1/9.htm

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值