微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 模拟电路设计 > Windows设备驱动程序编写时的主要问题及解决方案

Windows设备驱动程序编写时的主要问题及解决方案

时间:04-18 来源:互联网 点击:


3?内存的读写 Winsows工作在32位保护模式下,保护模式与实模式的根本区别在于CPU寻址方式上的不同,这也是Windows驱动程序设计中需要着重解决的问题。Windows采用了分段、分页机制如图1?,这样使应用程序产生一种错觉,好象程序中可以使用非常大的物理存储空间。这样做最大的好处就是一个程序可以很容易地在物理内存容量不一样的、配置范围差别很大的计算机上运行,编程人员使用虚拟存储器可以写出比任何实际配置的物理存储器都大得多的程序。每个虚拟地址由16位的段选择子和32位段偏移量组成。通过分段机制,系统由虚拟地址产生线性地址。再通过分页机制,由线性地址产生物理地址。线性地址被分割成页目录(Page Directory)、页表(Page Table)和页偏移(Offset)三个部分。当建立一个新的Win32进程时,操作系统会为它分配一块内存,并建立它自己的页目录、页表,页目录的地址也同时放入进程的现场信息中。当计算一个地址时,系统首先从CPU控制器CR3中读出页目录所在的地址,然后根据页目录得到页表所在的地址,再根据页表得到实际代码/数据页的页帧,最后再根据页偏移访问特定的单元。硬件设备读写的是物理内存,但应用程序读写的是虚拟地址,所以存在着将物理内存地址映射到用户程序线性地址的问题。

从物理地址到线性地址的转换工作也是由驱动程序来完成的。在Windows 95下,使用DDK的VMMCall_MapPhysToLinear进行地址映射。驱动程序的内存映射部分主要是调用VxD的系统服务MapPhysToLinear。在VtoolsD中这个函数的定义如下:

PVOID MapPhysToLineag(CONST VOID * PhysAddr,DWORD nBytes,DWORD Flags); 其中第一个参数PhysAddr就是要映射的内存的物理地址的起始位置,而nBytes是内存区域的长度,Flags必须设置为0。这个函数返回的就是这段物理地址映射的线性内存地址。如果指定的内存不能存取,函数将返回FFFFFFFFH。 比如要映射物理内存ED000000H开始的4096个字节,可以这样做: PCHAR *PointerToPage=(PCHAR)MapPhysToLinear((PVOID)OxED000000,4096,0); 而将PointerToPage传递给调用驱动的用户程序,在用户程序中使用 DWORD *pFIFOBodyBase=(DWORD*)PointerToPage; 而这个PFIFOBodyBase指针就可以象普通的指针一样进行读写操作,而通过对这个指针的操作就可以实现对物理内存ED000000H进行读写。
在Windows NT下,首先调用IoReportResourceUsage请求使用设备的内存。然后调用HalTranslateBusAddress转换与总线相关的内存为系统的物理内存地址。再使用MmMapIoSpace把设备的内存映射到虚拟空间。在设备驱动卸出时,调用MmUnmapIoSpace断开设备的内存和虚拟空间的连接。 ?

(4)?中断的设置、响应与调用 对中断的设置、响应与调用应该在驱动程序中完成。
对中断的调用?象前面调用BIOS的1AH中断读取配置寄存空间?可以由DDK的Exec_Int完成。
PCI设备驱动程序应当从PCI配置寄存器的中断寄存器(INTLN)和中断引脚寄存器(INTPIN)?中获得有关中断的信息。DDK还提供了响应中断事件的服务。如在Windows 95中,VPICD服务用来管理所有硬件中断事件。PC机的硬件中断需要确定硬件中断的IRQ,对一个特定的IRQ中断源,VPICD或者提供缺省的中断处理函数,或者允许其它VxD重载中断处理函数。在VtoolsD中,要处理硬件中断应该从VHardwareInt继承一个类。在这个类中,VtoolsD提供了编写中断响应程序所需的功能。
在Windows NT中,同VPICD对应的中断服务为中断请求层(IRQL)。设备驱动首先使用HalGetInterrupuVector将与总线有关的中断向量转换为系统的中断向量,然后利用IoConnectInterrupu指定中断服务。

3 设备驱动的调用
编写设备驱动并不是最终的目的,总是需要由用户程序来调用驱动并实现一定的功能。一般调用设备驱动是使用CreateFile函数打开设备文件,得到一个文件句柄。具体到我们的设备驱动程序中,使用如下的语句就可以打开文件。
hVxD=CreateFile("\\\\.\\PCIBIOS.VXD",0,0,0, CREATE-NEW,FILE-FLAG-DELETE-ON-CLOSE,0); 打开设备文件后,调用DeviceIoControl函数就可以同设备驱动程序交换数据了。
完成硬件操作之后,可以调用CloseHandle(hVxD);关闭设备驱动。
这种调用方式也是Windows NT调用设备驱动的标准方法。对于VxD来说还有其它的调用方式,如DPMI方式,但采用DeviceIoControl的方法可以保证程序在Windows NT和Windows 9X下的兼容性,在两个操作系统下,仅有CreateFile语句是不同的。
4 设备驱动的进一步封装 至此,完成了对驱动程序的初步设计。但考虑到在上面调用设备驱动时使用的DeviceIoControl函数仍是比较复杂的,程序也不太容易具有通用性。而且,在有些开发工具中,如Visual Basic,不包括直接读写I/O端口的语句,所以可以考虑根据不同软件的需要对驱动程序进行不同的封装。目前,我们实现了以DLL、ActiveX、VCL和C++类库进行封装。DLL可以在大多数软件环境中进行调用。ActiveX可以在Visual Basic等可视编程环境中使用。VCL可以在Delphi和C++ Builder中使用。考虑到许多用户使用Visual C++,所以也提供了C++类库方式。
参考文献
1 马卫国,何佩琨.通用高速PCI总线目标模块的设计.电子技术应用,1999;25(1)
2 Art Baker.Windows NT设备驱动程序设计指南.北京:机械工业出版社,1997
3 AMCC S5933 PCI Controller Data Book.Applied Micro Circuits Corporation,1996 ? (收稿日期:1999-06-16)

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top