王 煊
(中國(guó)空空導(dǎo)彈研究院 河南 洛陽(yáng) 471009)
一次性指令通信卡通過(guò)cPCI接口和PCI總線進(jìn)行通訊,對(duì)外部使用通用的輸入輸出接口。通過(guò)一次性指令控制卡,測(cè)試設(shè)備可以像飛控系統(tǒng)施加激勵(lì)信號(hào),同時(shí)接受飛控輸出的一次性指令,數(shù)據(jù)匯總到測(cè)試設(shè)備的處理器,可以對(duì)飛控系統(tǒng)進(jìn)行分析處理。所以,一次性指令通信卡在飛控系統(tǒng)靜態(tài)測(cè)試設(shè)備中扮演非常重要的角色。
一次性指令通信卡是一個(gè)綜合性的設(shè)備,對(duì)它的設(shè)計(jì)包括硬件和軟件的部分。硬件設(shè)計(jì)包括芯片選擇、板卡布線以及控制邏輯。軟件設(shè)計(jì)包括DLL調(diào)用接口、上層應(yīng)用程序以及在選定平臺(tái)下的驅(qū)動(dòng)程序軟件。本文著重研究軟件尤其是驅(qū)動(dòng)程序的設(shè)計(jì)。
作者所要完成的工作是cPCI一次性指令通信卡在Windows 2K/XP下的驅(qū)動(dòng)程序設(shè)計(jì)。具體內(nèi)容有:深入了解Windows NT系列32位操作系統(tǒng)的內(nèi)部原理,以及開(kāi)發(fā)驅(qū)動(dòng)程序的原理和方法;理解和掌握目標(biāo)cPCI板卡的內(nèi)部結(jié)構(gòu)、板上資源和指令;編寫(xiě)該cPCI一次性指令通信卡的驅(qū)動(dòng)程序,同時(shí)開(kāi)發(fā)對(duì)應(yīng)的DLL函數(shù)庫(kù);編寫(xiě)一個(gè)簡(jiǎn)易的測(cè)試程序。
cPCI是CompactPCI的簡(jiǎn)稱,是工業(yè)計(jì)算機(jī)的一種互聯(lián)總線,是歐標(biāo)連接方式和PCI信號(hào)協(xié)議的結(jié)合產(chǎn)物。cPCI板卡有3U和6U兩個(gè)尺寸標(biāo)準(zhǔn),多塊板卡通過(guò)一塊背板互聯(lián)。接口管腳定義由歐美PICMG 組織制定。
cPCI原本上是為了支持PCI信號(hào)協(xié)議而制定的。和PCI標(biāo)準(zhǔn)相比,cPCI提供兩倍的插槽,并提供熱插拔機(jī)制更適合工業(yè)應(yīng)用。從協(xié)議上看,cPCI與PCI完全等效,驅(qū)動(dòng)和上層程序完全兼容。
圖1 測(cè)試程序界面Fig. 1 Test program interface
PCI9054是美國(guó)PLX公司繼PCI9052之后推出的又一低成本PCI總線接口芯片,低功耗,PQFP 172pins封裝,它采用了先進(jìn)的PLX數(shù)據(jù)管道結(jié)構(gòu)技術(shù),可以使局部總線快速轉(zhuǎn)換到PCI總線上[1]。PCI9054的主要特性如下:
1)符合PCI 2.2版本規(guī)范,32位,33 MHz總線
2)普通主總線接口,包含兩個(gè)DMA引擎
3)支持PCI雙地址周期
4)可編程中斷產(chǎn)生器
5)6個(gè)可編程并且零等待突發(fā)操作的FIFO
6)串行EEPROM接口
PCI的配置空間是編寫(xiě)驅(qū)動(dòng)程序的基礎(chǔ)。
PCI9054的許多功能都是通過(guò)配置寄存器來(lái)控制的。其中的部分寄存器是由系統(tǒng)上電時(shí)由EEPROM自動(dòng)按廠商預(yù)定的映射方式填入,主要包括Vender ID、device ID、基本的中斷設(shè)置和部分本地配置寄存器。
1)作為重要的控制本地地址空間映射到PCI地址空間的寄存器有3個(gè),以Space 0 為例:
LAS0RR:本地地址空間0大小寄存器,32位
LAS0BA:本地地址空間基地址寄存器,表示映射前的本地地址空間相對(duì)于自身的基地址和映射后本地地址空間在PCI總線空間上的物理基地址之間的對(duì)應(yīng)關(guān)系。
PCIBAR2:PCI基地址寄存器,在從模式下,用來(lái)保存系統(tǒng)加電后BIOS為本地地址空間映射到PCI空間后的總線物理基地址。在驅(qū)動(dòng)程序中,系統(tǒng)會(huì)發(fā)一個(gè)資源分配的數(shù)據(jù)請(qǐng)求包(IRP)。在響應(yīng)這個(gè)IRP的例程中,可以得到PCI基地址寄存器中的值,經(jīng)過(guò)轉(zhuǎn)換為內(nèi)核模式下的系統(tǒng)虛擬地址才能為驅(qū)動(dòng)程序所訪問(wèn)。
2)中斷先寄存器(PCIILR)
中斷線寄存器為8位,改寄存器的值說(shuō)明PCI設(shè)備的中斷引腳連接到系統(tǒng)中斷控制器的哪個(gè)中斷上。該寄存器的值由系統(tǒng)上電期間從EEPROM裝入。
3)中斷引腳寄存器(PCIIPR)
該寄存器說(shuō)明設(shè)備使用PCI總線上的哪一個(gè)中斷引腳,PCI總線一共有4個(gè)中斷引腳。PCI9054僅支持#INTA,故本設(shè)計(jì)中該寄存器的值為01H。
圖2 Windows 2000 操作系統(tǒng)組件框圖Fig. 2 Windows 2000 OS component diagram
以上這幾個(gè)寄存器才開(kāi)發(fā)PCI板卡時(shí),以及編寫(xiě)PCI板卡驅(qū)動(dòng)時(shí),是十分重要的[2]。可以通過(guò)EEPROM方式事先固化PCI配置寄存器中的值。EEPROM內(nèi)容的固化可以設(shè)計(jì)響應(yīng)的燒寫(xiě)電路并使用通過(guò)PlxMon工具將配置值固化到EEPROM中,燒寫(xiě)之前必須保證EEPROM中的值全為0xFFFFFFFF,否則燒寫(xiě)電路驅(qū)動(dòng)程序?qū)⒉荒茏R(shí)別該硬件。
內(nèi)核模式環(huán)境實(shí)際上已經(jīng)實(shí)現(xiàn)了一個(gè)通用操作系統(tǒng)的底層軟件平臺(tái)。內(nèi)核模式環(huán)境主要由3個(gè)代碼模塊組成[3]。
1)硬件抽象層(HAL, Hardware Abstract Layer)
硬件抽象層是一個(gè)薄層軟件,它是硬件與操作系統(tǒng)其他部分的接口,是物理硬件資源的一種抽象。硬件抽象層通過(guò)動(dòng)態(tài)鏈接庫(kù)實(shí)現(xiàn),使用硬件抽象層例程的設(shè)備驅(qū)動(dòng)程序可以在有相同CPU體系的平臺(tái)上實(shí)現(xiàn)二進(jìn)制代碼兼容。
2)內(nèi)核(Kernel)
如果說(shuō)硬件抽象層代表了硬件平臺(tái)的抽象化,那么內(nèi)核便是整個(gè)操作系統(tǒng)的神經(jīng)中樞。它提供管理以下功能的機(jī)制:中斷和異常處理、線程調(diào)度和同步、多處理機(jī)同步、定時(shí)控制、內(nèi)核對(duì)象。通過(guò)這些內(nèi)核服務(wù),操作系統(tǒng)的上層部分可以忽略底層CPU的體系結(jié)構(gòu)[4]。內(nèi)核提供了一個(gè)基于對(duì)象的界面。內(nèi)核對(duì)象可以分為調(diào)度者對(duì)象和控制對(duì)象兩大類。內(nèi)核提供了一個(gè)基于對(duì)象的界面。由于調(diào)度者對(duì)象主要負(fù)責(zé)同步性能并改變或影響線程調(diào)度,故設(shè)備很少使用到這類對(duì)象。但是卻經(jīng)常用到以某種方式控制操作系統(tǒng)的行為控制對(duì)象。
3)執(zhí)行體(Executive)
執(zhí)行體由幾個(gè)不同的軟件模塊組成,它們是完全獨(dú)立的,只通過(guò)定義好的接口來(lái)通訊。執(zhí)行體為用戶模式進(jìn)程及它們之間的通信提供服務(wù)。執(zhí)行體包含的重要的模塊有:系統(tǒng)服務(wù)接口、進(jìn)程管理器、I/O管理器、即插即用管理器、電源管理器。
1)初始化例程
和動(dòng)態(tài)鏈接庫(kù)類似,它向操作系統(tǒng)顯露一個(gè)名為DriverEntry的例程,每次啟動(dòng)驅(qū)動(dòng)程序[5]的時(shí)候,操作系統(tǒng)將調(diào)用這個(gè)入口。DriverEntry除了做一些必要的設(shè)備初始化工作外,還初始化一些Dispatch例程入口。使I/O管理器能知道當(dāng)用戶的打開(kāi)、關(guān)閉、讀寫(xiě)等請(qǐng)求到來(lái)時(shí)各應(yīng)調(diào)用哪些過(guò)程來(lái)處理。同時(shí)要初始化設(shè)備對(duì)象,申請(qǐng)軟硬件資源。
2)調(diào)度例程
調(diào)度例程(Dispatch)是設(shè)備驅(qū)動(dòng)程序提供的主要函數(shù),可以完成打開(kāi)、關(guān)閉、讀取、寫(xiě)入以及設(shè)備文件系統(tǒng)或網(wǎng)絡(luò)支持的任何其它功能。當(dāng)被調(diào)用去執(zhí)行一個(gè)I/O操作時(shí),I/O管理器產(chǎn)生一個(gè)I/O請(qǐng)求包(IRQ),并且通過(guò)某個(gè)驅(qū)動(dòng)程序的調(diào)度例程調(diào)用驅(qū)動(dòng)程序。
3)Start I/O例程
串行化處理I/O請(qǐng)求,提高程序執(zhí)行效率。驅(qū)動(dòng)程序可以使用Start I/O例程來(lái)初始化與設(shè)備之間的數(shù)據(jù)傳輸。在開(kāi)始設(shè)備操作時(shí),I/O管理器調(diào)用驅(qū)動(dòng)程序的Start I/O例程,分配處理該請(qǐng)求所需的任何資源,并設(shè)置設(shè)備運(yùn)行。
4)中斷服務(wù)例程(ISR)
當(dāng)一個(gè)設(shè)備中斷時(shí),內(nèi)核的中斷調(diào)度程序把控制權(quán)轉(zhuǎn)交給這個(gè)例程。ISR例程運(yùn)行在高級(jí)別的IRQL上,所以他越簡(jiǎn)單越好,以避免對(duì)低優(yōu)先級(jí)中斷產(chǎn)生不希望的阻塞。ISR可以把剩余的大多數(shù)工作推遲到低中斷優(yōu)先級(jí)的延遲過(guò)程調(diào)用(DPC)中實(shí)現(xiàn)。
5)延遲過(guò)程調(diào)用(DPC)
用于處理中斷響應(yīng)的大多數(shù)工作,在ISR例程用排隊(duì)并得到調(diào)用。
1)設(shè)備的總線結(jié)構(gòu)。設(shè)備采用什么樣的總線結(jié)構(gòu)非常關(guān)鍵,因?yàn)椴煌目偩€在硬件工作機(jī)制上存在很大的不同,所以驅(qū)動(dòng)程序的設(shè)計(jì)也不同。
2)要了解設(shè)置的控制寄存器、狀態(tài)寄存器和數(shù)據(jù)寄存器,以及這些寄存器工作的特性。
3)要了解設(shè)備寄存器返回的狀態(tài)和錯(cuò)誤信號(hào),這些信號(hào)要通過(guò)驅(qū)動(dòng)程序返回用戶。
4)要了解設(shè)備產(chǎn)生中斷的調(diào)節(jié)和中斷是數(shù)量
5)數(shù)據(jù)傳輸機(jī)制:最常用的數(shù)據(jù)傳輸機(jī)制,是通過(guò)IO指令和硬件設(shè)備進(jìn)行數(shù)據(jù)讀寫(xiě)。
6)許多設(shè)備帶有內(nèi)存,PCI設(shè)備大多采用內(nèi)存映射的方式映射到系統(tǒng)的物理內(nèi)存。有的設(shè)備還要通過(guò)驅(qū)動(dòng)程序來(lái)設(shè)置接口的寄存器。
NuMega公司的DriverStudio是一套簡(jiǎn)化Windows驅(qū)動(dòng)程序開(kāi)發(fā)、調(diào)試及測(cè)試的工具包。其中包括:開(kāi)發(fā)普通設(shè)備WDM驅(qū)動(dòng)程序的DriverWorks、創(chuàng)建DDK支持的純C語(yǔ)言的WDM驅(qū)動(dòng)程序框架、支持網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)的DriverNetWorks及Windows內(nèi)核單擊調(diào)試工具SoftICE。DriverWorks以面向?qū)ο蟮姆绞綄⒕帉?xiě)WDM驅(qū)動(dòng)程序所需要的內(nèi)核及訪問(wèn)硬件的函數(shù)封裝成類。這樣,驅(qū)動(dòng)開(kāi)發(fā)者只要在工程向?qū)У闹敢轮鸩皆O(shè)置必要的參數(shù),最后就可以得到WDM驅(qū)動(dòng)程序框架。然后根據(jù)特定設(shè)備的訪問(wèn)請(qǐng)求,想類中添加新的類對(duì)象和代碼即可。DriverWorks是基于VC或者VC.net工程的,經(jīng)過(guò)編譯以后即可以得到設(shè)備驅(qū)動(dòng)程序。它所用到的函數(shù)只不過(guò)是對(duì)DDK提供的庫(kù)函數(shù)的封裝,不會(huì)影響代碼的執(zhí)行效率。
使用DriverStudio驅(qū)動(dòng)生成向?qū)ЫⅡ?qū)動(dòng)程序的步驟是[6]:
1)輸入路徑和工程名;
2)選擇要生成的驅(qū)動(dòng)程序框架的類型,這里選擇WDM Driver;
3)選擇WDM驅(qū)動(dòng)程序的類型,這里選擇WDM Function Driver;
4)選擇驅(qū)動(dòng)程序所對(duì)應(yīng)的硬件設(shè)備類型,選擇PCI,并填入對(duì)應(yīng)的廠商編號(hào)和設(shè)備編號(hào);
5)添加硬件資源,并選中“Use Interrupts”;
6)選擇驅(qū)動(dòng)程序支持的功能項(xiàng);
7)添加I/O控制;
8)添加注冊(cè)表中裝載的標(biāo)志參數(shù),這里不需要添加;
9)選擇電源管理選項(xiàng);
10)選擇是否添加WMI屬性;
11)選擇安裝選項(xiàng);
12)選擇其他選項(xiàng)。
前面講過(guò)PCI設(shè)備實(shí)現(xiàn)硬件操作時(shí)是將設(shè)備空間映射到計(jì)算機(jī)系統(tǒng)空間中實(shí)現(xiàn)的,因此一個(gè)很重要的設(shè)計(jì)就是在系統(tǒng)啟動(dòng)時(shí),保存系統(tǒng)給板卡分配的基地址空間,因?yàn)閷?duì)硬件板卡的全部操作將會(huì)依賴于這些基地址。當(dāng)然這些基地址是根據(jù)總線上的設(shè)備以及設(shè)備資源要求來(lái)分配的。由于系統(tǒng)啟動(dòng)發(fā)現(xiàn)硬件板卡并給其分派好資源后,操作系統(tǒng)會(huì)給驅(qū)動(dòng)程序發(fā)送一個(gè)代碼為IRP_MN_START_DEVICE的IRP,該IRP保函了系統(tǒng)分配的資源信息列表,因此在驅(qū)動(dòng)程序中需要設(shè)計(jì)相應(yīng)的例程來(lái)解析該資源列表。KIoRange和KMemoryRange兩個(gè)類分別用來(lái)實(shí)現(xiàn)對(duì)IO映射芯片的訪問(wèn)和對(duì)內(nèi)存映射芯片的訪問(wèn)。根據(jù)得到的資源來(lái)調(diào)用者兩個(gè)類的成員函數(shù)即可實(shí)現(xiàn)對(duì)PCI9054寄存器和本地空間的訪問(wèn)。
PCI板卡對(duì)軟件產(chǎn)生中斷,該中斷在DriverStudio生成的框架中會(huì)調(diào)用Irp()函數(shù)??梢栽贒evice類中定義一個(gè)KEvent成員變量。首先注冊(cè)事件變量,獲取應(yīng)用程序傳入的事件句柄后,對(duì)KEvent事件變量進(jìn)行注冊(cè)。在Irp()中可以關(guān)閉中斷,以免中斷多次響應(yīng)。然后在Isr_dpc()函數(shù)中開(kāi)啟中斷,并且記錄中斷源,清除中斷,并對(duì)KEvent對(duì)象進(jìn)行Set()操作。
DriverStudio向?qū)傻墓こ炭蚣軐?duì)每個(gè)IO控制接口都專門(mén)生成一個(gè)單獨(dú)的函數(shù),在對(duì)應(yīng)的函數(shù)中取出緩沖區(qū)數(shù)據(jù),寫(xiě)入對(duì)應(yīng)Memory Resource或IO Resource的自定義地址中,或者從資源地址中取出數(shù)據(jù),寫(xiě)入輸出緩沖區(qū),并報(bào)告數(shù)據(jù)區(qū)在緩沖區(qū)的長(zhǎng)度。
驅(qū)動(dòng)程序僅僅實(shí)現(xiàn)對(duì)硬件設(shè)備的操作,那么要實(shí)現(xiàn)人為的控制對(duì)設(shè)備的操作應(yīng)該實(shí)現(xiàn)用戶程序和內(nèi)核驅(qū)動(dòng)程序的某種連接,這樣才會(huì)有更大的實(shí)際價(jià)值。
通常的板卡控制流程如下:使用CreateFile去打開(kāi)板卡,然后使用DeviceIOControl去和驅(qū)動(dòng)程序進(jìn)行通信或者利用其讀寫(xiě)少量的數(shù)據(jù),進(jìn)行大數(shù)據(jù)量連續(xù)的數(shù)據(jù)傳輸則考慮使用ReadFile和WriteFile的DMA方式去實(shí)現(xiàn),當(dāng)操作完成以后,直接使用CloseHandle去關(guān)閉設(shè)備。這種對(duì)應(yīng)關(guān)系如表1所示。
表1 Win32函數(shù)與IRP例程關(guān)系對(duì)應(yīng)表Tab.1 Correspondence between Win32 function and IRP routine
經(jīng)過(guò)了艱苦的努力,這套一次性指令卡的驅(qū)動(dòng)終于開(kāi)發(fā)完成。在開(kāi)發(fā)測(cè)試過(guò)程中,綜合使用了驅(qū)動(dòng)設(shè)計(jì)過(guò)程中的各種技術(shù)。無(wú)論從理論上還是實(shí)踐上都有極為重要的研究意義。
[1]PCI 9054 Data Book Version 2.1,PCI 9054 Data Book[S].U.S:PLX, 2000.
[2]孟楠, 劉文怡. 基于PXI總線的數(shù)字量IO卡設(shè)計(jì)[J].科學(xué)技術(shù)與工程, 2013, 13(2):507-511.
MENG Nan, LIU Wen-yi.A Design of Digital IO Card Based on PXI Bus[J]. Science Technology and Engineering, 2013,13(2)):507-511.
[3]DDK,Microsoft Driver Development Kits[S].U.S:Microsoft Press,1997.
[4]吳海箐, 吳江, 吳瑛. Windows NT4.0環(huán)境下數(shù)據(jù)采集卡設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)[J]. 信息工程大學(xué)學(xué)報(bào), 2001, 2(3)):19-23.
WU Hai-jing, WU Jiang, WU Ying. The Design of Data Acquisition Card' s Driving Program in Windows NT4.0[J].JournalofInformation EngineeringUniversity, 2001, 2(3):19-23.
[5]Oney.W Programming the Microsoft Windows Driver Model[M].U.S:Microsoft Press,1999.
[6]武安河.Windows2000/XP WDM設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)[M].2版.北京:電子工業(yè)出版社,2005.