阅读:1065回复:0
利用WinDriver 开发Windows 设备驱动程序
1 引言
在Windows 环境下,开发用户自制硬件的设备驱动程序, 最近一直是讨论的热门话题。编写驱动程序,一般为访问I/ O 和中断处理,尽管Win32 应用程序可以直接访问I/ O ,但却不 能提供中断服务。这是因为Windows 操作系统对设备的处 理,采用32 位Ring0 VxDs ,一般的模型是:由一个VxD 掌管所 有中断并执行所有数据传输,应用程序则使用function calls 的 方式对VxDs 发出需求。要编写Windows 设备驱动程序,一般 要写开发VxD。Microsoft 为开发者提供了设备驱动程序工具 箱(DDK) ,但它提供的许多VMM服务都使用寄存器的调用方 式,要使用汇编语言编写VxD。对开发者来说,是非常烦琐 的。目前已出现许多优秀的开发工具,帮助程序员开发设备 驱动程序,这里介绍由KRFTech 公司设计的WinDriver 工具。 你可从http :/ / www. krftech. com/ dnload. html 下载该工具,免费 30 天使用。WinDriver 是开发驱动程序的工具箱,让你能迅速地开发 以PCI/ ISA/ ISA PnP/ EISA为基础的驱动程序,使用WinDriver 的优点是:开发者并不需要熟悉任何操作系统内核编程或 DDK及任何驱动程序。WinDriver 同时允许开发者在自己熟 悉的开发环境下,利用使用者模式(User Mode) 来开发所需的 驱动程序―如使用VC ,Boland C ++ Builder ,Dephi 或VB 等任 何Win32 编译器。使用WinDriver 开发的驱动程序均可用于 Windows 9x ,NT/ 2000 ,Windows CE ,Linux和Solaris。 该工具箱提供的向导(Driver Wizard) 可以迅速地生成由 VC或Boland C ++ Builder 写的API 函数代码。在你的C ++ 程序中,可直接调用这些API 函数,这些函数通过工具提供的 Windrvr. VXD/ SYS来存取硬件。下面为你介绍如何用VB 来 编写驱动程序。2 用VB 设计驱动程序 该工具一个模式文件windrvr. cls ,在该文件里,用VB 将 WinDriver 提供的低层API 函数全部编写出来,包括系统内部 所用数据结构的定义。我们借此文件,参考系统生成的C ++ 程序,可以用VB 设计驱动程序。最近,我们成功地用VB 开 发出自制硬件ISA 卡的设备驱动程序。下面以我们的硬件资 源为例,介绍使用VB 的开发过程。 我们设计的ISA 卡占用中断号为5 ,端口地址为&H600 至&H602。 2. 1 访问I/ O 创建一个应用程序,加入模式文件windrvr. cls ,再加入一 个新的模式文件,用来编写访问I/ O 的设备驱动程序。将下 列代码加入到你新建的模式文件里。 Public Const Mycard ―IORange1 = 0 Public Const Mycard ―Interrupt1 = 1 Public Const Mycard ―Items = 2 Public Const Mycard ―Interrupt1 ―Irq = &H5 ′中断号 Public Const MYD―IORange1 ―ADDR = &H600 ′端口起始地址 Public Const MYD―IORange1 ―BYTES = &H3 ′地址长度 Public Mycard ―ErrorString As String Public Type Mycard ―Handle hWD As Long ′设备号 cardReg As WD―CARD―REGISTER ′卡资源信息结构 Interrupt1 As WD ―INTERRUPT ′中断结构 End Type Public hMycard As Mycard ―Handle Sub Mycard ―SetCardElements () ′internal function used by Mycard ―Open() hMycard. cardReg. Card. dwItems = Mycard ―Items hMycard. cardReg. Card. Item (Mycard ―IORange1) . Item = ITEM―IO hMycard. cardReg. Card. Item (Mycard ―IORange1) . fNotSharable = False hMycard. cardReg. Card. Item (Mycard ―IORange1) . dw1 =MYD―IORange1 ―ADDR hMycard. cardReg. Card. Item (Mycard ―IORange1) . dw2 = MYD―IORange1 ―BYTES hMycard. cardReg. Card. Item (Mycard ―Interrupt1) . Item = ITEM―INTERRUPT hMycard. cardReg. Card. Item (Mycard ―Interrupt1) . fNotSharable = False hMycard. cardReg. Card. Item (Mycard ―Interrupt1) . dw1 = Mycard ―Interrupt1 ―Irq hMycard. cardReg. Card. Item (Mycard ―Interrupt1) . dw2 = INTERRUPT―LEVEL ―SENSITIVE End Sub Public Function Mycard ―Open() As Boolean Dim ver As WD―Version hMycard. cardReg. hCard = 0 hMycard. hWD = WD―Open() If hMycard. hWD = INVALID―HANDLE―VALUE Then Mycard ―ErrorString = ″ERROR - Cannot open WinDriver device″ GoTo Error End If WD―Version hMycard. hWD , ver If ver. dwVer < WD―VER Then Mycard ―ErrorString = ″ERROR - incorrect WinDriver version″ GoTo Error End If Call Mycard ―SetCardElements ′hMycard hMycard. cardReg. fCheckLockOnly = False WD―CardRegister hMycard. hWD , hMycard. cardReg If (hMycard. cardReg. hCard = 0) Then Mycard ―ErrorString = ″ERROR - could not lock device″ GoTo Error End If Mycard Open = True GoTo finish Error : If (hMycard. cardReg. hCard < > 0) Then WD―CardUnregister hMycard. hWD , hMycard. cardReg End If If (hMycard. hWD < > INVALID―HANDLE―VALUE) Then WD―Close hMycard. hWD End If Mycard ―Open = False finish : End Function Sub Mycard ―Close () If (hMycard. cardReg. hCard < > 0) Then WD―CardUnregister hMycard. hWD , hMycard. cardReg End If WD―Close (hMycard. hWD) End Sub Function Mycard ―ReadByte (hMYD As Mycard ―Handle , PortAddr As Long) As Byte Dim trans As WD―Transfer trans. cmdTrans = RP ―BYTE trans. dwPort = PortAddr WD―Transfer hMYD. hWD , trans Mycard ―ReadByte = trans. dwDataTransfer End Function Sub Mycard ―WriteByte (hMYD As Mycard ―Handle , ByVal PortAddr As Long , ByVal data As Byte) Dim trans As WD―Transfer trans. cmdTrans = WP ―BYTE trans. dwPort = PortAddr trans. dwDataTransfer = data WD―Transfer hMYD. hWD , trans End Sub Sub StrCopy(lic As WD―License , str As String) Dim l As Integer Dim i As Integer Dim a As Byte l = Len(str) For i = 0 To l - 1 a = Asc ( (Mid $(str , i + 1 , 1) ) ) lic. cLicense (i) = a Next i End Sub Sub RegisterWinDriver () Dim hWD As Long Dim lic As WD―License Dim s1 As String hWD = WD―Open If hWD < > INVALID―HANDLE―VALUE Then s1 = ″xxxxxxxxxxxxxxx″ ′你收到的注册码 Call StrCopy(lic , s1) Call WD―License (hWD , lic) Call WD―Close (hWD) End If End Sub 说明: 其中Mycard―SetCardElements 过程,设置硬件的资 源,每一段I/ O、内存DMA 和中断号为一个资源,每个资源都 作为一项进行设置,然后才可以访问;函数Mycard―Open 返回 打开的设备号,供以后使用;过程Mycard―Close 关闭打开的设 备;过程Mycard―WriteByte 向设备中指定地址写一个字节数 据;函数Mycard―ReadByte 向设备中指定地址读出一个字节数 据( 类似可写出读写字指令、读写长整型指令) ; 过程 RegisterWinDriver 用来将你收到的注册码写入VxD ,无此注册 码,软件过期不可用。 在应用程序中,首先打开设备,对硬件设备资源进行设 置,注册软件,然后就可调用I/ O 读写函数或过程访问设备。 最后,程序退出时关闭设备。 2. 2 中断处理 经过分析Driver Wizard 生成的VC 示例, 我们明白了 WinDriver 对中断处理的原理:首先开放中断,然后创建一个子 线程,等待中断到来,调用中断处理程序,主线程里做其它一 般处理工作。将下面代码加入到一个你的模式文件里。在这 里调用三个API 函数需要声明,CreateThread 用来生成线程,在 线程里等待中断处理; WaitForSingleObject 调用&HFFFFFFFF 使线程运行停下来;CloseHandle 关闭线程(该函数在windrvr. cls 已声明) 。 Declare Function CreateThread Lib ″kernel32″ (ByVal lpSecurityAttributes As Long , ByVal dwStackSize As Long , ByVal lpStartAddress As Long , ByVal lpParameter As Long , ByVal dwCreationFlags As Long , lpThreadId As Long) As Long Public Declare Function WaitForSingleObject Lib ″kernel32″(ByVal hHandle As Long , ByVal dwMilliseconds As Long) As Long ′Declare Function CloseHandle Lib ″kernel32″ ′( ByVal hObject As Long) As LongPublic hThread As Long 速访问,如下实例: # include ″sybasesql . h″ / / 引入头文件 void main() { SybaseSQL s (″servername″,″username″,″password″,″database″) ; / / 创建SybaseSQL 对象 if (s. sqlcode = = - 1) { printf (″%s″,s. sqlerr) ; / / 打印登录出错信息 return ; } int i ,j ; char buf [128 ] ; SqlRet sqlret ; / / 定义获取数据的对象 i = s. TransSqlExe (″select 3 from test INSERT test VALUES (′test1′,′12311′,′wqotq′) ″,sqlret) ; / / 调用的以事务方式执行Sql 语句的函数 if (i ! = - 1) { for (i = 0 ;i < sqlret . GetCol () ;i ++ ) { printf (″%s \\ t″,s. colname[ i ]) ; / / 输出表头 } printf (″\\ n″) ; for (i = 0 ;i < sqlret . GetRow() ;i ++ ) { for (j = 0 ;j < sqlret . GetCol () ;j ++ ) / / 输出结果记录 { sqlret . GetItem(i ,j ,buf) ; / / 获得执行结果放入缓冲区中 printf (″%s \\ t″,buf) ; } printf (″\\ n″) ; } else printf (″%s″,s. sqlerr) ; / / 打印执行SQL 语句的出错信息 } 4 结论 对象SybaseSQL 将DB - Library 的一些重要函数进行了封 装,使得用户能够很方便地使用,而不必再去重复编写一些复 杂的代码。从软件工程的角度来看,大大地提高了软件的生 产效率,该代码的复用率也是很高的。所以,以面向对象的方 法来编写程序,将大大提高代码的复用度,提高软件的生产效 率。 |
|