笔者也是第一次开发驱动程序,以下是本人在前段时间驱动开发的一些体会和总结,也算是做下笔记吧,如果对看到本文的你有帮助的话,本人深感欣慰,很多不足之处,还恳请高手们能指点一下。
对于驱动程序开发的方式有以下几种:
1. DDK开发
2. DrvierStudio
3. WinDriver
对于以上几种的开发方式,网络上有比较详细的介绍,在此略为说明一下。
使用DDK开发的难度比较大,它需要开发人员比较熟悉操作系统的工作原理以及比较专业的硬件知识,一般大牛们都用这种方式来开发驱动程序。就像我们开发应用软件一样,直接使用SDK开发应用程序。
而使用DriverStudio工具开发,相对难度就比较低,不需要像使用DDK要求的专业知识比较高。类似于在应用软件开发中的VC开发工具。
WinDriver则是这几种开发工具中要求最低的一种,他有相应的Wizard工具作为驱动开发的引导。类似于应用软件开发工具中的VB。
对于三者以及更多驱动开发工具的介绍,可以去网络上查找更为详细的介绍。
由于之前一直在使用VC开发应用软件,只是最近一段时间开始做DSP中关于PCI驱动开发的一小部分工作。所以并没有什么驱动开发基础,对于硬件的了解也还只是停留在本科课程的微机原理和单片机原理上。为此我选择了使用WinDriver工具来开发驱动,同时也因为这个工具的开发周期相对来说比较短。很多的函数都是封装好了的,直接使用相对应的API函数就可以了,比较符合我个人的口味,hoho:)
个人感觉使用API函数比使用WinDriver自带的Wizard开发要相对容易点,使用Wizard生成的代码应该需要改不少东西,还是直接使用API函数来的清静~:)
好了,讲了不少的废话,开始我们的基于WinDriver的驱动开发之旅吧~。
第一, 熟悉WinDriver的各种API函数。
在WinDriver软件中自带的帮助文档中有比较详细的介绍。包括如何使用它来开发驱动以及各种相关API函数等等,有了这个帮助文档就足够了,也不需要去网络上找什么教程之类的文章了。更为方便的是,在介绍各个API函数的时候,帮助文档还提供了相应的例程,这是很好很方便的一种做法,不是吗,呵呵~ 。
第二, 熟悉WinDriver开发驱动的流程
由于笔者使用的是API函数开发的,即帮助文档中所说的Without WinDriverWizard的模式,所以关于使用Wizard开发的流程可以参照帮助文档,应该是比较简单的事情了。
第三, 编写驱动代码
根据帮助文档的API函数和上图的驱动开发流程,开始我们这次旅途最为关键的一步吧,驱动代码的编写。在编写代码的时候,最需要搞清楚的就是API函数的各参数的意义,以及哪些参数是需要输入的,而哪些参数是输出的,仔细地检查一下哦:)。比如说下面这些个参数:
WD_CARD_REGISTER.Card.Item.I.Mem.dwCpuPhysicalAddr
WD_CARD_REGISTER.Card.Item.I.Mem.dwPhysicalAddr
WD_CARD_REGISTER.Card.Item.I.Mem.dwTransAddr
WD_CARD_REGISTER.Card.Item.I.Mem.dwUserDirectAddr
在进行驱动调试的时候,就可以看到这些獠牙般可怕的地址的具体含义了,打开WinDriver的Debug窗口,在进行PCi设备注册的时候,可以看到如下一些信息:
Do_card_lock: registering item 2 bar 0 memory 0xe5800000-0xe5bfffff
Cpu_memory_address: entered, physical addr 0xe5800000, bus type 5, bus num 1
Cpu_memory_address: success. physical address 0xe5800000, translated 0xe5800000
Map_physical_mem_krnl: entered, physical addr 0xe5800000, length 0x400000
Cpu_memory_address: entered, physical addr 0xe5800000, bus type 5, bus num 1
Cpu_memory_address: success. physical address 0xe5800000, translated 0xe5800000
Map_physical_mem_krnl: success, linear addr 0xb7ef0000
Map_physical_mem_user: entered, physical addr 0xe5800000, length 0x400000
Map_physical_mem_user: ZwOpenSection() returned handle 0xa94
Map_physical_mem_user: ObReferenceObjectByHandle() returned handle 0xe1000a40
Cpu_memory_address: entered, physical addr 0xe5800000, bus type 5, bus num 1
Cpu_memory_address: success. physical address 0xe5800000, translated 0xe5800000
Map_physical_mem_user: success, user_addr0x6870000
Do_card_lock: registering item 3 bar 1 memory 0xe5000000-0xe57fffff
Cpu_memory_address: entered, physical addr 0xe5000000, bus type 5, bus num 1
Cpu_memory_address: success. physical address 0xe5000000, translated 0xe5000000
Map_physical_mem_krnl: entered, physical addr 0xe5000000, length 0x800000
Cpu_memory_address: entered, physical addr 0xe5000000, bus type 5, bus num 1
Cpu_memory_address: success. physical address 0xe5000000, translated 0xe5000000
Map_physical_mem_krnl: success, linear addr 0xb76f0000
Map_physical_mem_user: entered, physical addr 0xe5000000, length 0x800000
Map_physical_mem_user: ZwOpenSection() returned handle 0xa94
Map_physical_mem_user: ObReferenceObjectByHandle() returned handle 0xe1000a40
Cpu_memory_address: entered, physical addr 0xe5000000, bus type 5, bus num 1
Cpu_memory_address: success. physical address 0xe5000000, translated 0xe5000000
Map_physical_mem_user: success, user_addr0x6c70000
Do_card_lock: registering item 4 bar 2 io-range 0xb000-0xb00f
Do_card_lock: success
对照驱动程序调试时候的变量WD_CARD_REGISTER的结构变量中的上诉各地址的变量可知:
dwCpuPhysicalAddr和dwPhysicalAddr 地址相同,是物理地址,就是我们在WinDriver上直接看到的PCI设备上的地址,个人感觉应该是PCI设备的资源的本地的物理地址。
dwTransAddr,Map_physical_mem_krnl则是我们在访问PCI设备资源直接写入的地址,在进行资源读写操作的时候传入的地址,从Debug窗口的信息来看是线性地址,应该是PCI设备资源被映射到PC机上的地址,在核心态模式中直接访问的地址,。
dwUserDirectAddr,Map_physical_mem_user: success, user_addr,从字面意思理解就是用户模式地址,应该是和Map_physical_mem_krnl相对应的,具体有什么作用,本人也不是很清楚,反正在调试的时候,输入这些个地址进行读写都会出现资源地址的越界,只有传入dwTransAddr地址才是正确的,还望硬件高手能够更细致的指明下这些个獠牙咧齿地址的具体含义~J
IO地址不像MEN有那么多的地址,它只有一种地址~:)
第四, 驱动调试
在驱动程序调试的时候,最常遇见的事情就是死机,在访问硬件的时候,稍有不顺就会出现令人瞠目结舌的现象。
好在WinDriver为我们提供了一个Debug工具,在一般情况下,比如说你的读写IO/MEM越界的时候,如果使用这个Debug工具,那么你很幸运,程序不会出现死机的情况,而是在Debug窗口中提示你资源地址越界,呵呵。但是当你的访问在物理上合法(即资源地址不越界),而在逻辑上不合法(即有部分硬件不允许访问)的情况下,Debug工具这个时候就无能为力了,不过这种情况在你对硬件资源访问权限胸有成竹的时候,算不上是个棘手的问题。
好了,就这些了,希望你在调试的时候有个好心情,祝你早日通过这一关~
第五, 驱动程序的发布
在发布驱动程序之前,需要作以下一些准备:
1. 硬件控制程序
2. WINDRVR6.sys
3. Windrve6.inf
4. 一个用户设备的INF文件(可以由WinDriver自动生成的)
5. WinDriver的自带工具Wdreg
在以上东东准备好之后,就可以尊照帮助文档所要求的那样一步一步进行发布就OK了,这里只介绍一下其在Winxp/2000下的发布情况,其他情况可以参考WinDriver的帮助文档。
首先,我们必须安装WinDriver的核心模块,因为我们使用WinDriver开发的驱动程序,隐藏了很多硬件的细节问题,而这些细节问题则包含在WinDriver的核心模块当中,所以发布驱动程序时,必须连带的安装好WinDriver的核心模块,正所谓买一送一,在方便了用户开发驱动的同时,用户需要时刻带着它的核心模块才能有效地工作~。在Winxp/2000环境中,我们可以直接使用上诉提到的Wdreg命令来安装即可,可以参考如下:
/> wdreg -inf
/> wdreg -inf d:/MyDevice/windrvr6.inf install
然后,在安装好WinDriver的核心模块的时候,我们需要安装自己设备的INF文件,而INF文件的安装也类似于上诉的核心模块的安装,可以直接使用Wdreg工具。
最后,至此,就可以安心的运行你的用户程序了,即硬件控制程序,也即我们这里意义上所说的驱动程序。
是吧,似乎好像就是这么的EASY,不是吗?其实还有一些问题,我在下文还是会说明一下的~:)
第六, 一些疑惑
比如说,在开发驱动程序的时候,这里为什么没有生成所谓的SYS文件,因为一般看来,驱动程序的开发就意味着SYS文件的生成。其实刚开始的时候,我也是相当的疑惑,应该是这样的啊,是不?在WinDriver的帮助文档中已经写的蛮详细的了,有的时候有SYS文件,而有的时候却可以不要SYS文件,What’s wrong? 仔细看看,你就会发现,其实WinDriver开发驱动程序,有两种模式,一种是用户模式,一种是核心模式。用户模式比较简单,和一般的应用程序的开发没什么区别,除了调试时会出现习惯性死机之外。而核心模式的开发则有点繁琐,涉及到一些更加底层的东西,不过其和用户模式最大的区别就是控制硬件更加有效,很明显嘛,越是接近底层,效率自然就越高了。这是为了满足一部分用户对驱动要求高效率而设计的一种开发模式。
所以说使用WinDriver开发驱动,没有SYS文件是再正常不过的事情了~:)
总结
应该就是这么些东西了,也许在实际开发当中还会遇到各种各样稀奇古怪的问题,那就多上网搜索一下吧,内事不决问Baidu,外事不决问Google :)。
Chuajiang
2008-2-23 于珞珈山
参考:
《WinDriver Menual》