- 相關推薦
Windows2000設備驅動程序的研制開發
引言:
由于工作關系,我經常涉及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的文件,驅動程序的作用被柔和在應用程序中,這樣,應用程序為了使用不同廠商的同一類設備,必須了解這些設備在接口上具體的硬件實現,同時,對于一個特定型號的硬件產品,所有支持它的應用軟件中對于控制整個設備動作的這部分代碼,可能被多次重寫。這種情況不適應硬件及應用軟件的飛速發展。Windows系統在這方面,進行了根本性改進,把控制設備動作的這部分代碼獨立出來,提出了設備驅動程序的概念,驅動程序是應用程序和硬件設備之間的一個橋梁,應用程序與驅動程序之間有明確的接口,應用程序通過與驅動程序交換信息,達到控制外設的目的。接口定義的操作是面向設備的,這就是說,在應用程序的設計中,并不用關心對外設操作的具體硬件實現,只是對驅動程序發出一系列指令既可;驅動程序接受來自上層應用程序的指示,具體操縱實際硬件,完成用戶功能。具體實現上,Win95/98系列與WindowsNT又有所區別,WindowsNT是嚴格按照上述思路設計的;而Win95/98系列不那么嚴格,其支持上述思路,但同時應用程序也可以繞過驅動程序直接訪問實際物理I/O,這樣做,增加程序設計的靈活性,但同時,對系統可靠性造成一定隱患。這也正是Win95/98系列可靠性低于WinNT的原因之一。
表1-1 三種操作系統下訪問接口比較
操作系統應用程序訪問接口方式訪問權限
DOS 直接訪問所有[注]
Windows95/98 通過設備驅動程序*.VXD 所有[注]
直接訪問僅I/O端口
WindowsNT 通過設備驅動程序*.SYS 所有[注]
[注]‘所有’指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
來源 IRQL
硬件 HIGHEST_LEVEL
POWER_LEVEL
IPI_LEVEL
CLOCK2_LEVEL
CLOCK1_LEVEL
PROFILE_LEVEL
DIRQLs(I/O設備中斷平臺相關的級數)
軟件 DISPATCH_LEVEL
APC_LEVEL
PASSIVE_LEVEL
WindowsNT設備驅動程序的編寫步驟與實例
現以一實際例子簡要說明設備驅動程序的開發步驟,本例以CINRAD天氣雷達測試卡實際應用為原型,加以簡化、抽象。
第一步,了解被控設備的接口情況。
本例為一ISA卡,占用PC機9號中斷,I/O地址360H及RAM地址D0228H分別一個字空間。
第二步,確定驅動程序的功能。
驅動程序每當9號中斷達到時,檢查運行標志變量RunFlag(為一BOOL變量),如果等于TRUE,中斷累積計數器counter(為一unsigned short變量)增一,把這個值寫入RAM地址D0228H,再從這個地址讀出,如果讀出值等于寫入值,把這個值寫入I/O地址360H,這個地址的內容會驅動板卡上的LED顯示,把寫入值顯示出來;如果讀出值不等于寫入值,設置運行標志變量FALSE。如果運行標志變量等于FALSE,什幺也不做,返回。
第三步,定義驅動程序與應用程序的軟件接口。
本例定義兩個接口命令:
IOCTL_IOCardA_START:應用程序設置驅動程序內部的運行標志變量等于TRUE。
IOCTL_IOCardA_READ:應用程序查詢驅動程序內部的中斷累積計數器的值。
第四步,畫流程圖。這里列舉本例實現的幾個主要流程圖,(圖略)。
系統傳給驅動程序入口函數系統定義的‘設備驅動對象’DrObj,通過初始化這個對象的一些成員變量,把驅動程序其它函數與這個對象聯系起來。
ISA卡為非即插即用設備,事先把資源占用信息手工添加注冊表如下:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\IOCardA\parameters]
"IRQ"=dword:00000009
"IOSPAN"=dword:00000004
"IOAdd"=dword:00000360
"RAMAdd"=dword:000d0228
"RAMSPAN"=dword:00000002
其中IOCardA以下各子鍵及其值為自定義,設備驅動程序利用相應函數檢索出這些值。
(3)每個設備驅動程序可以創建若干系統定義的‘設備對象’,本例根據需要只創建了一個‘設備對象’Dev。‘設備對象’其中一個成員變量為指向一非分頁的物理內存塊DeviceExtension,這塊內存大小及內容為用戶自定義,由于Dev或DeviceExtension對象會被系統傳給驅動程序的其它函數,這樣驅動程序各函數通過訪問這塊內存區,實際上達到互相傳遞信息的功能。本例在這里存儲設備硬件資源信息及RunFlag和中斷計數器counter,這些數值在DriverEntry()初始化后,供驅動程序的其它函數使用。
圖3-2為中斷服務程序IOCardAIsr()流程圖。操作系統接受中斷,連同DeviceExtension等參數傳給中斷服務程序,中斷服務程序利用這些參數,實現要求功能。
圖3-3為IOCardADispatch()流程圖,這個函數用于處理來自上層應用程序的命令。上層應用程序通過以下程序段設置驅動程序中RunFlag值為TRUE,從而啟動中斷服務程序開始計數。
BOOL cmd=TRUE;
hTest = CreateFile(...); //打開設備
DeviceIoControl(hTest, //設備句柄
IOCTL_IOCardA_START,//命令
&cmd,sizeof(BOOL), //輸入緩沖區地址及大小
NULL,0,&c,NULL);
CloseHandle(hTest); //關閉設備
上層應用程序通過以下程序段查詢當前的中斷計數器的值并存于變量w中。
unsigned short w;
hTest = CreateFile(...);
DeviceIoControl(hTest,
IOCTL_IOCardA_READ, //命令
NULL,0,
&w,sizeof(unsigned short),//輸出緩沖區地址及大小
&c,NULL);
CloseHandle(hTest);
其中DeviceIoControl()執行后,操作系統調用IOCardADispatch()函數,如流程圖所示,這個函數內部通過一個開關語句,根據命令執行相應的分支。驅動程序與應用程序通過此函數接口交換數據時,操作系統提供4種可選數據緩沖方式,本例由于數據I/O量比較小,故選用‘緩沖I/O’ (METHOD_BUFFERED)。過程是,I/O管理器首先分配一個非分頁池,它的大小為調用者輸入緩沖區和輸出緩沖區的較大者,第一段程序為sizeof(BOOL),第二段程序為sizeof(unsigned short),它的地址存到IRP(I/O請求包)的AssociatedIrp.SystemBuffer域中,然后把輸入數據拷貝到這個池中,在第一段程序中cmd的值TRUE被拷貝到池中,這樣驅動程序通過RtlCopyBytes()函數再把池中的值拷貝到驅動程序的RunFlag中。IOCardADispatch()函數執行完,I/O管理器把池中的內容拷貝到調用者的輸出緩沖區,在第二段程序中,驅動程序通過RtlCopyBytes()函數把counter的值拷貝到池中,從而最終傳遞到應用程序變量w中。
第五步,編程。在編寫設備驅動程序的同時,要編寫一個簡單的應用程序用于測試設備驅動程序的一些功能。
第六步,驅動程序的載入。
驅動程序C語言源程序經過編譯、連接生成擴展名為SYS的文件,本例為IOCardA.sys,把這個文件拷貝到\WINNT\system32\drivers\系統目錄下,同時手工添加如下信息到注冊表:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\IOCardA]
"ErrorControl"=dword:00000001
"Start"=dword:00000003
"Type"=dword:00000001
要保證IOCardA子鍵名與驅動程序文件名一致,其中Type=1表示此驅動程序為內核模式驅動程序,Start=3表示此驅動程序手動載入,ErrorControl=1表示當驅動程序發生錯誤時,日志記錄錯誤并顯示一個消息框。這樣當Windows重新啟動后,通過使用控制面板中的Device小應用程序,從列表中找到IOCardA設備名,按Start按鈕,于是,設備驅動程序就駐留內存并在底層開始工作了。
第七,調試。設備驅動程序沒有界面,完全在系統底層運行,為了觀察驅動程序的運行狀態,WindowsNT DDK提供windbj.exe程序用于設備驅動程序的調試,調試設備驅動程序需要兩臺CPU體系結構完全相同的計算機,一臺為‘宿主機’,運行windbj.exe程序,另一臺為‘目標機’,運行設備驅動程序,兩臺計算機用串口線連好,進行一系列軟件設置(參見[1]第17章),就可以開始調試了,從‘宿主機’可以控制及觀察‘目標機’上驅動程序的運行情況。最常用的調試手段是在驅動程序中必要的位置加入DbgPrint()函數,這個函數可以把指定信息輸出到‘宿主機’windbg.exe窗口中,通過分析這些信息,可以了解驅動程序當前的運行情況。
結束語
WindowsNT是一個復雜而嚴密的系統,驅動程序的開發不可避免的涉及現代操作系統理論及其它許多計算機理論,內涵相當廣泛,本文圍繞著開發實踐從一定深度探討了WindowsNT設備驅動程序開發最基本的知識及一般方法,希望對讀者有所幫助,對于復雜,特殊應用的實現及編程技巧,有待于讀者在各自實際應用中不斷探索。
參考文獻
1.《WindowsNT設備驅動程序設計指南》 Art Baker著 機械工業出版社
2.Microsoft Co. WindowsNT 4.0 Device Driver Kid
【Windows設備驅動程序的研制開發】相關文章:
基于Windows2000開發WDM設備驅動程序的方法03-19
windows nt環境下fddi網卡驅動程序設計03-18
對于設備驅動程序通知應用程序的幾種方法11-16
Windows 中斷程序設計03-28
在 DOS 下使用Windows *.WAV 文件03-03
Windows環境下對象的鏈接與嵌入03-16