劉 皓
(山西師范大學(xué)經(jīng)濟(jì)管理學(xué)院,山西臨汾041000)
計(jì)算機(jī)發(fā)展速度飛快,傳統(tǒng)的計(jì)算接口已經(jīng)不能滿足當(dāng)前計(jì)算機(jī)高速發(fā)展的需求,鍵盤、鼠標(biāo)、調(diào)制解調(diào)器、打印機(jī)、掃描儀、攝像頭、數(shù)碼相機(jī)、MP3隨身聽、外置硬盤、光驅(qū)設(shè)備往哪兒接呢?計(jì)算機(jī)業(yè)界迫切需要新的通用型、高速總線接口。
USB是一種應(yīng)用在計(jì)算機(jī)領(lǐng)域的新型接口技術(shù),它使得計(jì)算機(jī)周邊設(shè)備連接標(biāo)準(zhǔn)化,具有安裝方便、高帶寬、易于擴(kuò)展的特點(diǎn)。
本文利用 Visual C++6.0、Driver Works以及 Windows 2000 DDK開發(fā)包作為開發(fā)工具,采用WDM驅(qū)動(dòng)程序模式,開發(fā)USB接口驅(qū)動(dòng)程序,實(shí)現(xiàn)了USB鍵盤驅(qū)動(dòng)程序的開發(fā)、安裝及測(cè)試。
在WDM驅(qū)動(dòng)程序模型中,每個(gè)硬件設(shè)備包括兩個(gè)驅(qū)動(dòng)程序。一個(gè)驅(qū)動(dòng)程序是硬件設(shè)備驅(qū)動(dòng)程序,也稱功能驅(qū)動(dòng)程序,主要為用戶提供適合的控制方式。它了解硬件工作的所有細(xì)節(jié),負(fù)責(zé)初始化I/O操作,處理I/O操作完成時(shí)所帶來的中斷事件。通常由兩個(gè)分離的執(zhí)行文件組成。一個(gè)文件是類驅(qū)動(dòng)程序,它了解如何處理操作系統(tǒng)使用的WDM協(xié)議,以及如何管理整個(gè)設(shè)備的基本特征[3]。另一個(gè)文件稱為微小驅(qū)動(dòng)程序,它包含類驅(qū)動(dòng)用于管理設(shè)備實(shí)例的廠商專有特征例程。類驅(qū)動(dòng)程序和微小驅(qū)動(dòng)程序合在一起才成為一個(gè)完整的功能驅(qū)動(dòng)程序。
另一個(gè)驅(qū)動(dòng)程序稱為總線(BUS)驅(qū)動(dòng)程序,負(fù)責(zé)管理硬件與計(jì)算機(jī)的連接。
一個(gè)完整的驅(qū)動(dòng)程序包含許多例程,當(dāng)操作系統(tǒng)遇到IRP時(shí),它就調(diào)用驅(qū)動(dòng)程序的例程來執(zhí)行IRP的各種操作。
WDM驅(qū)動(dòng)程序?qū)嵭蟹謱犹幚?,被分成高層?qū)動(dòng)程序、中間層驅(qū)動(dòng)程序、底層驅(qū)動(dòng)程序。每層驅(qū)動(dòng)再把I/O請(qǐng)求劃分成更簡(jiǎn)單的請(qǐng)求,以傳給更下層的驅(qū)動(dòng)執(zhí)行。最底層的驅(qū)動(dòng)程序在收到I/O請(qǐng)求后,通過硬件抽象層,與硬件進(jìn)行交互,從而完成I/O請(qǐng)求工作。
WDM還引入了功能設(shè)備對(duì)象FDO(Functional Device Object)與物理設(shè)備對(duì)象PDO(Physical Device Object)兩個(gè)新類來描述硬件。總線驅(qū)動(dòng)程序(Bus Driver)位于最底層,控制對(duì)總線上所有設(shè)備的訪問,并為每個(gè)設(shè)備創(chuàng)建一個(gè)PDO,功能驅(qū)動(dòng)程序(Function Driver)管理FDO所代表的設(shè)備,過濾驅(qū)動(dòng)程序(Filter Driver)用于監(jiān)視和修改IRP流。
用Driver Wizard3.0創(chuàng)建Usbkbd的WDM框架將自動(dòng)生成一個(gè)工作區(qū)和兩個(gè)工程,Test_Usbkbd files和Usbkbd files。其中Test_Usbkbd files是測(cè)試應(yīng)用程序工程,Usbkbd files是驅(qū)動(dòng)程序工程[3]。
Test_Usbkbd files測(cè)試應(yīng)用程序工程
OpenByIntf.cpp:OpenByIntf.cpp 包含 OpenByInterface 函數(shù),OpenByInterface函數(shù)用GUID接口方式與WDM進(jìn)行通信。
Test_Usbkbd.cpp:是整個(gè)測(cè)試應(yīng)用程序的主要文件,在這里添加相關(guān)代碼,其作用是,打開設(shè)備的一個(gè)句柄,用于對(duì)設(shè)備進(jìn)行讀操作,并對(duì)DeviceIoControl函數(shù)進(jìn)行調(diào)用,DeviceIoControl函數(shù)包含了對(duì)驅(qū)動(dòng)程序的通信的命令。
Test_Usbkbd.cpp的文件結(jié)構(gòu)
UsbkbdDriverInterface.h:定義設(shè)備接口的GUID。
Usbkbdioctl.h:定義驅(qū)動(dòng)程序的控制代碼。
Usbkbd.cpp:功能驅(qū)動(dòng)程序,包含設(shè)備的初始化,Driver-Entry例程和AddDevice歷程。還重載了注冊(cè)信息參數(shù)。
UsbkbdDevice.cpp:設(shè)備驅(qū)動(dòng)程序,主要包括一些IRP的操作,如:清除(CleanUp(KIrp I))、關(guān)閉(Close(KIrp I))、創(chuàng)建(Create(KIrp I))、PnP 管理(DefaultPnp(KIrp I))、電源管理(DefaultPower(KIrp I))、I/O控制(DeviceControl(KIrp I))、開始設(shè)備(OnStartDevice(KIrp I))、停止設(shè)備(OnStop-Device(KIrp I))、移除設(shè)備(OnRemoveDevice(KIrp I))、對(duì)設(shè)備進(jìn)行讀操作(Read(KIrp I))、系統(tǒng)控制(SystemControl(KIrp I))、通信控制(USBKBD_IOCTL_800_Handler(KIrp I))等。
在以上文件中添加代碼。
function.h預(yù)定義相關(guān)的例程。
Usbkbd.h描述設(shè)備的相關(guān)信息,包括初始化時(shí)在注冊(cè)表中的路徑,注冊(cè)表的參數(shù),數(shù)據(jù)成員在 DriverEntry期間被載入。
Usbkbdioctl.h為設(shè)備定義I/O控制命令。
Usbkbd.inf安裝文件,在生成工程時(shí)自動(dòng)生成。安裝WDM設(shè)備驅(qū)動(dòng)程序需要的所有必須的信息,包括要復(fù)制的文件列表、創(chuàng)建的注冊(cè)表項(xiàng)等。
驅(qū)動(dòng)程序通常使用DriverEntry作為驅(qū)動(dòng)程序的默認(rèn)入口點(diǎn),當(dāng)PnP管理器發(fā)現(xiàn)一個(gè)硬件設(shè)備時(shí),首先調(diào)用Driver-Entry例程,DriverEntry例程是驅(qū)動(dòng)程序初始化的入口點(diǎn),它負(fù)責(zé)創(chuàng)建一個(gè)設(shè)備對(duì)象,定義其它的例程名稱,設(shè)置例程的入口指針,從注冊(cè)表中獲取信息,初始化驅(qū)動(dòng)程序,并初始化其它在驅(qū)動(dòng)程序范圍內(nèi)的數(shù)據(jù)結(jié)構(gòu)和資源。在DriverEntry中,主要的工作是在傳遞的驅(qū)動(dòng)程序?qū)ο笾写鎯?chǔ)一系列的回調(diào)例程指針。DRIVER_OBJECT結(jié)構(gòu)由操作系統(tǒng)用于存儲(chǔ)與驅(qū)動(dòng)程序有關(guān)的任何信息。以后使用一個(gè)分開的結(jié)構(gòu)存儲(chǔ)每個(gè)設(shè)備的信息。Default Pnp(即插即用)主要是實(shí)現(xiàn)一個(gè)IRP_MJ_PNP處理程序。在驅(qū)動(dòng)程序中,即插即用的基本處理包括:處理設(shè)備的添加和刪除;得到分配的資源;處理查詢停止和查詢刪除消息;處理停止設(shè)備消息;處理意外刪除消息。Dispatch(分發(fā)例程)主要用來處理應(yīng)用程序和驅(qū)動(dòng)程序之間的通信,包括 Great、Close、Cleanup、Read、Write、Control。分發(fā)例程是可選的,是為設(shè)備的硬件層編程服務(wù)的,通過該例程可以達(dá)到應(yīng)用程序控制設(shè)備的目的。
WDM驅(qū)動(dòng)程序通常由PnP管理器載入內(nèi)存,然后調(diào)用它之中的AddDevice例程來創(chuàng)建設(shè)備。用一個(gè)inf安裝文件來指明該驅(qū)動(dòng)程序的一些參數(shù)[1]。
一般情況下,DriverEntry例程要設(shè)置以下幾個(gè)IRP處理函數(shù):
DriverUnload指向驅(qū)動(dòng)程序的清除例程。I/O管理器會(huì)在卸載驅(qū)動(dòng)程序前調(diào)用該例程。通常,WDM驅(qū)動(dòng)程序的DriverEntry例程一般不分配任何資源,所以DriverUnload例程也沒有什么清除工作要做。
DriverExtension→AddDevice指向驅(qū)動(dòng)程序的AddDevice函數(shù)。PnP管理器將為每個(gè)硬件實(shí)例調(diào)用一次AddDevice例程。這樣將創(chuàng)建一個(gè)該設(shè)備對(duì)象。
DriverStartIo如果驅(qū)動(dòng)程序使用標(biāo)準(zhǔn)的IRP排隊(duì)方式,應(yīng)該設(shè)置該成員,使其指向驅(qū)動(dòng)程序的StartIo例程。
MajorFunction是一個(gè)指針數(shù)組,I/O管理器把每個(gè)數(shù)組元素都初始化成指向一個(gè)空函數(shù),這個(gè)空函數(shù)僅返回失敗。驅(qū)動(dòng)程序可能僅需要處理幾種類型的IRP,所以至少應(yīng)該設(shè)置與那幾種IRP類型相對(duì)應(yīng)的指針元素,使它們指向相應(yīng)的派遣函數(shù)。
用IoCreateDevice創(chuàng)建設(shè)備對(duì)象,并建立一個(gè)私有的設(shè)備擴(kuò)展對(duì)象。
注冊(cè)一個(gè)或多個(gè)設(shè)備接口,以便應(yīng)用程序能夠發(fā)現(xiàn)設(shè)備的存在。另外,還可以給出設(shè)備名并創(chuàng)建符號(hào)連接。
初始化設(shè)備擴(kuò)展對(duì)象和設(shè)備對(duì)象的Flag成員。
調(diào)用IoAttachDeviceToDeviceStack函數(shù),把新設(shè)備對(duì)象放到堆棧中。
Power例程。WDM驅(qū)動(dòng)程序支持電源管理,電源管理器通過IRP指示驅(qū)動(dòng)程序來改變電源狀態(tài),等待并響應(yīng)系統(tǒng)喚醒事件和查詢驅(qū)動(dòng)程序設(shè)備,如果設(shè)備不支持電源管理,僅有一個(gè)默認(rèn)的Power例程即可。
CreatFile:應(yīng)用程序要想和設(shè)備進(jìn)行通信,必須先打開設(shè)備,因此,應(yīng)用程序用CreatFile函數(shù)來打開設(shè)備。
DeviceControl:應(yīng)用程序可以調(diào)用DeviceIoControl函數(shù)與WDM驅(qū)動(dòng)程序進(jìn)行通信。DeviceIoControl函數(shù)分為同步調(diào)用和異步調(diào)用方式,采用同步方式時(shí),應(yīng)用程序調(diào)用DeviceIoControl函數(shù)將被阻塞,直到驅(qū)動(dòng)程序完成響應(yīng)的數(shù)據(jù)傳輸時(shí)才往下執(zhí)行,因此這里采用異步調(diào)用方式,但是通常采用異步方式完成的驅(qū)動(dòng)程序只允許一個(gè)應(yīng)用程序,為了打開多個(gè)應(yīng)用程序,應(yīng)用程序調(diào)用并修改DeviceControl,使得每次只能有一個(gè)IRP處于等待中,這樣可以打開多個(gè)應(yīng)用程序[3]。
ReadFile函數(shù):應(yīng)用程序和驅(qū)動(dòng)程序進(jìn)行通信的目的就是通過驅(qū)動(dòng)程序?qū)υO(shè)備進(jìn)行讀、寫、或控制等操作。在鍵盤驅(qū)動(dòng)程序中,通過調(diào)用ReadFile函數(shù),來讀取鍵盤數(shù)據(jù)。
用DriverWizard創(chuàng)建WDM框架程序之后,將自動(dòng)生成一個(gè)工作區(qū)和兩個(gè)工程文件。在相關(guān)文件添加相關(guān)代碼后,將光標(biāo)定位在Usbkbd file上,點(diǎn)擊右鍵,選擇“Set as Active Project”設(shè)置該工程為當(dāng)前活動(dòng)工程。然后點(diǎn)擊編譯,如果編譯沒有錯(cuò)的情況下,將會(huì)在sys文件夾下生成一些文件,包括一些自由構(gòu)造和檢查構(gòu)造等文件,還生成一個(gè)objfre文件,生成的安裝程序的系統(tǒng)文件Usbkbd.sys就包含在該文件里。
要安裝上面生成的Usbkbd.sys文件,必須用驅(qū)動(dòng)程序安裝文件(inf)來安裝。安裝Usbkbd.sys文件有三種方法,但是在安裝之前都要將sys文件下的Usbkbd.inf復(fù)制到“..sysobjferi386”目錄下。因?yàn)閁sbkbd.inf是在生成工作區(qū)時(shí)生成的,當(dāng)時(shí)并沒有sys文件,因此要將Usbkbd.inf復(fù)制到Usbkbd.sys所在目錄下,Usbkbd.inf文件包含了安裝WDM設(shè)備驅(qū)動(dòng)程序需要的所有必須的信息,例如要復(fù)制的文件列表、創(chuàng)建的注冊(cè)表項(xiàng)等。
從“控制面板”→“系統(tǒng)”→“硬件”→“添加硬件向?qū)А遍_始運(yùn)行,按照向?qū)б徊揭徊秸业経sbkbd.inf文件,完成該USB鍵盤驅(qū)動(dòng)程序的安裝[2]。
驅(qū)動(dòng)程序安裝成功后將在設(shè)備管理器里可以看到安裝的USBKBD設(shè)備的詳細(xì)信息。如果驅(qū)動(dòng)程序安裝不上,可以用DriverStudio提供的Monitor跟蹤測(cè)試。當(dāng)驅(qū)動(dòng)程序可以正常運(yùn)行時(shí),顯示驅(qū)動(dòng)程序的狀態(tài)信息,當(dāng)驅(qū)動(dòng)程序不能運(yùn)行時(shí)顯示錯(cuò)誤信息。
[1]武安河.Windows 2000/XP WDM設(shè)備驅(qū)動(dòng)程序的開發(fā)[M].第2版.北京:電子工業(yè)出版社 ,2005.
[2]張惠娟,周利華,翟鴻鳴.Windows環(huán)境下的設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)[M].西安:西安電子科技大學(xué)出版社,2002.
[3][美]Walter Oney.Windows驅(qū)動(dòng)程序編程[M/OL].馬少華,譯.http://www.driverdevelop.com/2001.