引言:
由于工作关系,我经常涉及pc机与外围设备接口的工作,从pc机这方面要做的工作看来,主要是通过接口处理外围设备的中断,通过i/o端口或内存地址与外设互相传递数据。从计算机原理的角度看,所要达到的目的很简单,那么如何编写程序完成上述功能呢?
目前国内流行的pc操作系统有三种:dos,win95/98系列,windowsnt。dos是单用户、单任务操作系统,由于pc机硬件处理速度不断提高,基于单用户、单任务的操作系统越来越不能充分发挥硬件的功能,现在只应用于一些老式pc及其它个别场合,有逐渐被淘汰的趋势;win95/98系列和windowsnt属于多任务操作系统,不论从其原理还是界面上看,这两种操作系统都比dos有着无可比拟的优越性,这两种操作系统虽然在界面和操作上及其相似,但其内部实现的诸多方面有许多区别,有些区别是本质上的。win95/98设计目标是针对一般家庭用户,安全性及可靠性存在许多薄弱环节,就可靠性而言,win95/98系列不能很好的防止多任务环境中某个进程的非法操作导致系统中其它程序甚至整个系统的崩溃,而windowsnt在这方面及其它诸多方面设计的相当严谨。这两种操作系统是microsoft公司同一时期的产品,但针对不同的使用群,所以在一些重要场合及生产实践中应该选择windowsnt作为计算机的操作系统,此外,从发展趋势来看,windowsnt已经成为定型产品,具有相对稳定性。
在不同操作系统下编写驱动程序是有很大区别的,在dos平台上,应用程序和设备驱动程序之间没有标准的接口,它们在外部表现为一个扩展名为exe的文件,驱动程序的作用被柔和在应用程序中,这样,应用程序为了使用不同厂商的同一类设备,必须了解这些设备在接口上具体的硬件实现,同时,对于一个特定型号的硬件产品,所有支持它的应用软件中对于控制整个设备动作的这部分代码,可能被多次重写。wWw.133229.cOM这种情况不适应硬件及应用软件的飞速发展。windows系统在这方面,进行了根本性改进,把控制设备动作的这部分代码独立出来,提出了设备驱动程序的概念,驱动程序是应用程序和硬件设备之间的一个桥梁,应用程序与驱动程序之间有明确的接口,应用程序通过与驱动程序交换信息,达到控制外设的目的。接口定义的操作是面向设备的,这就是说,在应用程序的设计中,并不用关心对外设操作的具体硬件实现,只是对驱动程序发出一系列指令既可;驱动程序接受来自上层应用程序的指示,具体操纵实际硬件,完成用户功能。具体实现上,win95/98系列与windowsnt又有所区别,windowsnt是严格按照上述思路设计的;而win95/98系列不那么严格,其支持上述思路,但同时应用程序也可以绕过驱动程序直接访问实际物理i/o,这样做,增加程序设计的灵活性,但同时,对系统可靠性造成一定隐患。这也正是win95/98系列可靠性低于winnt的原因之一。
表1-1 三种操作系统下访问接口比较
[注]‘所有’指i/o端口,ram总线,中断,dma。
windowsnt设备驱动程序的组成原理
windowsnt操作系统结构分为用户模式和内核模式,用户模式下的编程为应用程序的设计,而开发设备驱动程序,则属于内核模式下的编程,内核模式组件包括nt executive(exxxx),内核(kexxx),硬件抽象层(halxxx)。其层次如图2-1所示,其中nt executive 包括几个独立的软件组件,它们是系统服务接口(zwxxx),对象管理器(obxxx),配置管理器,进程管理器(psxxx),安全监视器(sexxx),虚拟空间管理器(memxxx),本地进程调用,i/o管理器(ioxxx)。内核模式的系统服务并不是全部公开的,而是提供了一系列开发设备驱动程序需要的函数(上文括号内为函数形式,函数手册参见[2]kernel-mode drivers-reference章节),换言之,这些函数功能是所有内核模式的系统服务功能的子集。
驱动程序由一系列相对独立的函数组成,由i/o管理器根据需要调用这些函数,对于一个需要处理中断的最简单的驱动程序也需要由以下几个函数构成:
1.driverentry() 运行于passive_level
驱动程序入口点,当驱动程序被手动或自动装入系统后,驱动程序从这点开始执行,主要用于定位硬件资源,建立指向其它驱动程序函数的指针等其它初始化工作。
2.xxunload() 运行于passive_level
用于驱动程序从系统卸出之前,释放由驱动程序占用的所有系统资源。
3.xxisr() 运行于dirql
中断服务程序。
4.xxdpcforisr() 运行于dispatch_level
中断服务程序后处理程序,以排队方执行不太关键代码的执行,由于排队机制及优先级,不会造成代码拥塞从而提高中断服务程序的响应并且提高系统总体i/o吞吐率。
5.xxopen() 运行于passive_level
处理应用程序win32函数createfile()请求。
6.xxclose() 运行于passive_level
处理应用程序win32函数closehandle()请求。
7.xxdispatch() 运行于passive_level
处理应用程序win32函数deviceiocontrol()请求,通过一系列自定义命令,驱动程序与应用程序交换特定的信息。
windowsnt使用一个抽象化的cpu优先级方案, irql代表中断请求级,任一时刻cpu总处在某一级上,这个数越大,表示当前的任务重要性越大,如表2-1所示,从上至下irql越来越小。所有上述驱动程序的函数及内核模式函数都必须运行于各自的irql级上,如果违反这一调用规定,会造成系统崩溃。例如,中断服务程序(xxisr)运行于dirql及上,那幺在编写中断服务程序时,只能调用允许在这一级运行的内核模式函数(并不是所有内核模式函数都能运行于dirql级)。至于每个内核模式函数运行级别的说明,详见[2]kernel-mode drivers-reference章节。
windowsnt是一多任务系统,许多设备的驱动程序同时存在系统中,这样各个设备所占用的资源(中断,i/o及ram地址空间)很有可能冲突,如果设备驱动程序在运行之前不进行‘探测’而使用自己硬件设备的资源,有可能和系统内其它设备占用的资源冲突,后果不堪设想。windowsnt通过注册表管理硬件资源的占用信息,作为内核模式信任的组件,驱动程序使用硬件资源之前必须遵循‘查询-申请-使用-释放’的原则(如图2-2所示)。
表2-1
windowsnt设备驱动程序的编写步骤与实例
现以一实际例子简要说明设备驱动程序的开发步骤,本例以cinrad天气雷达测试卡实际应用为原型,加以简化、抽象。
第一步,了解被控设备的接口情况。
本例为一isa卡,占用pc机9号中断,i/o地址360h及ram地址d0228h分别一个字空间。
第二步,确定驱动程序的功能。
windowsnt是一个复杂而严密的系统,驱动程序的开发不可避免的涉及现代操作系统理论及其它许多计算机理论,内涵相当广泛,本文围绕着开发实践从一定深度探讨了windowsnt设备驱动程序开发最基本的知识及一般方法,希望对读者有所帮助,对于复杂,特殊应用的实现及编程技巧,有待于读者在各自实际应用中不断探索。
参考文献
1.《windowsnt设备驱动程序设计指南》 art baker著 机械工业出版社
2.microsoft co. windowsnt 4.0 device driver kid