开发驱动程序的过程

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

编写内核模式的代码于应用程序的代码是不同的,因为驱动程序是操作系统的信任的部分。它的代码必须遵循特殊的规则,小心的编写......

Content:编写内核模式的代码于应用程序的代码是不同的,因为驱动程序是操作系统的信任的部分。它的代码必须遵循特殊的规则,小心的编写。

驱动程序开发策略

像大多数的软件,驱动程序也使用有组织的开发方法。这个部分将介绍一些技巧来尽量减少开发时间。使用规范的开发方法

一般的,如果编写一个设备驱动程序没有一个开发策略。而是去匆忙的测试全新的硬件,往往测试代码会成为驱动程序的基础部分。也许设备驱动程序是被一些对操作系统不熟悉的程序员编写的,第一个驱动程序的编写会是一个驱动程序作者全面了解系统构架的旅程。

幸运的,疯狂的软件编写的日子过去了。在复杂的硬件和操作系统的环境下,想怎幺编写就怎幺编写的代码是不会运行的。

下面是一个简短的开发技术(它们中的一些是来自实时设计技术)列表。

1.数据流图可以将一个驱动程序分成独立的函数部分。通过这个图可以容易的看出各个部分的联系,和数据的流向。

2.状态机模型是一个描述驱动过程控制流的好的方法,特别是管理复杂的硬件和软件协议的驱动程序。在验证状态机的过程中,可能发现驱动程序中的同步问题。

3.分析期待的数据的重复率或者输入输出的响应将得到一系列定量的时序条件。对于确定驱动程序的总性能是非常重要的。

4.另一个有用的工具是外部事件和驱动程序响应动作的列表。这个列表应该包括设备的硬件事件和用户通过I/O管理器的软件事件。

使用这些技术分解一个驱动程序成为一个定义好的函数部分。有时,这些意味着分解一个简单的,单片的驱动程序一些硬件相关的端口和硬件无关的类驱动程序。在任何时候,在工程的开始,分析一个驱动程序的设计所花费的时间多于设计工程它自己,这样可以减少调试和维护的时间。

使用渐进的开发方法

一旦最初的分析和设计完成,就要开始编写代码了。按照以下的步骤进行可以减少调试的时间:

1.确定驱动程序需要哪些内核模式对象。

2.确定驱动程序需要哪些上下文环境或者状态信息和这些信息的存储位置。

3.首先编写DriverEntry和Unload例程,最初不要增加即插即用支持,这样允许通过控制面板手动的测试驱动程序的装载和卸载。

4.添加处理IRP_MJ_CREATE和IRP_MJ_CLOSE的操作和一些不需要进行设备的访问例程。然后可以使用一个简单的WIN32程序调用CreateFile和CloseHandle来测试。

5.添加寻找和分配驱动程序的硬件的代码,还有在驱动程序被卸载后的重新分配硬件的代码。如果硬件支持即插即用,这一步测试硬件和驱动程序的自动加载能力。

6.添加处理IRP_MJ_XXX函数的派遣例程,最初的例程应该没有使用物理设备,后来新的代码应该使用简单的WIN32程序进行测试,例如ReadFile和WriteFile调用,或者其它支持的函数。

7.最后完成Start I/O例程,ISR和DPC例程。现在可以使用真实的数据和硬件进行测试。

应一个有用的提示:当硬件的确切行为是不能肯定的时候,增加一个DeviceIoControl函数,这个例程直接访问设备的寄存器,这时可用一个简单的WIN32程序直接控制设备寄存器。记得在发布最后的驱动程序版本的时候删除这个功能。

使用驱动程序实例

Windows 2000驱动程序开发包(DDK)里面有相当多的驱动程序实例。有许多方法使用者些代码来使驱动程序的开发变的更容易,微软鼓励从这些代码实例中剪切和粘贴。

编码技术与习惯

编写一个信任的内核模式部分和编写应用程序是不同的。这个部分提供一些编码技术与习惯,使编写代码更加容易一些。

一般性的建议

首先,在编写驱动程序的时候应当遵循一些一般性的指导方针:

1.尽量避免使用汇编语言。因为它使代码难于阅读,没有移植性,维护困难。HAL宏提供一个安全的机制去访问I/O设备寄存器。因此,在驱动程序中级少使用汇编语言。

2.对于特定平台的代码,提供一个单独的模块,至少要用#ifdef/#endif语句将它们括起来。

3.不要使用标准的C运行时库连接驱动程序。它除了浪费存储器空间之外,一些库的例程的状态或者上下文环境不是线程安全或者驱动程序安全的方式。

4.这一条可能不适合编写设备驱动程序。天天使用运行库环境的C语言程序员,常常不清楚C程序和C运行库的差别。C运行库需要初始化,它尝试初始化一个堆区域和调用全局对象的构造器(使用C++时)。所有的这些任务防碍驱动程序的操作。

5.Windows 2000提供它自己的环境支持内核模式代码。包括RtlXxx函数(运行库)等多个公用的C语言运行库服务支持。

6.用某种源代码控制管理驱动程序工程。微软的Visual Source Safe是一个好的选择。对于大的跨平台的工程Rational公司的ClearCase也值得考虑。

命名规范

所有的大的软件工程应该为例程和变量定义制定一些标准的命名规范,设备驱动程序也不例外。好的命名规范提高开发,调试,除错和维护的效率。

微软为DDK提供一个命名规范,NTDDK.H定义所有的数据类型,结构,常数,宏。按照DDK规范,所有这些类型的名字都是大写的。甚至是C语言数据类型也提供一个相应的DDK名字。例如,C语言的数据类型void*在NTDDK.H中是PVOID。这些定义可以很容易的扩展到未来的64Bits的平台。

微软推荐将每个驱动程序例程的名字加上一个特殊的前缀。例如,编写一个鼠标类驱动程序,Start I/O 例程的名字可能是MouseClassStartIo。同样的缩写成为两个或者三个字符通常用在内部数据的命名。这样一个例程的名字可能是MouConfiguration。

头文件

除了包含NTDDK.h或者WDM.h,一个驱动程序应当使用私有的头文件去隐藏硬件和平台依赖的变量。例如,寄存器访问宏应该存储在一个私有的头文件,这些宏应该被#ifdef包括。这个技术解决在不同的I/O空间和存储器空间访问寄存器的问题。

甚至可解决移植性,寄存器访问宏是驱动程序容易阅读和维护。下列代码片段是一个并行端口设备访问的宏,这个实例假定驱动程序的一些初始化代码已经把第一个设备寄存器的地址放到设备Extension的PortBase中。

// 定义设备计存器为偏移地址

#define PAR_DATA 0

#define PAR_STATUS 1

#define PAR_CONTROL 2

//为寄存器定义访问宏,每个宏使用指向设备Extension的指针作为参数

#deinfe ParWriteData( pDevExt, bData ) \

(WRITE_PORT_UCHAR( pDevExt->PortBase + PAR_DATA, bData ) )

#define ParReadStatus( pDevExt ) \

(READ_PORT_UCHAR( pDevExt->>PortBase + PAR_STA TUS ))

#define ParWriteControl( pDevExt, bData ) \

(WRITE_PORT_UCHAR( pDevExt->PortBase + PAR_CONTROL, bData ) )

状态返回值

相关文档
最新文档