王 煊
(中國空空導彈研究院 河南 洛陽 471009)
一次性指令通信卡通過cPCI接口和PCI總線進行通訊,對外部使用通用的輸入輸出接口。通過一次性指令控制卡,測試設備可以像飛控系統施加激勵信號,同時接受飛控輸出的一次性指令,數據匯總到測試設備的處理器,可以對飛控系統進行分析處理。所以,一次性指令通信卡在飛控系統靜態測試設備中扮演非常重要的角色。
一次性指令通信卡是一個綜合性的設備,對它的設計包括硬件和軟件的部分。硬件設計包括芯片選擇、板卡布線以及控制邏輯。軟件設計包括DLL調用接口、上層應用程序以及在選定平臺下的驅動程序軟件。本文著重研究軟件尤其是驅動程序的設計。
作者所要完成的工作是cPCI一次性指令通信卡在Windows 2K/XP下的驅動程序設計。具體內容有:深入了解Windows NT系列32位操作系統的內部原理,以及開發驅動程序的原理和方法;理解和掌握目標cPCI板卡的內部結構、板上資源和指令;編寫該cPCI一次性指令通信卡的驅動程序,同時開發對應的DLL函數庫;編寫一個簡易的測試程序。
cPCI是CompactPCI的簡稱,是工業計算機的一種互聯總線,是歐標連接方式和PCI信號協議的結合產物。cPCI板卡有3U和6U兩個尺寸標準,多塊板卡通過一塊背板互聯。接口管腳定義由歐美PICMG 組織制定。
cPCI原本上是為了支持PCI信號協議而制定的。和PCI標準相比,cPCI提供兩倍的插槽,并提供熱插拔機制更適合工業應用。從協議上看,cPCI與PCI完全等效,驅動和上層程序完全兼容。

圖1 測試程序界面Fig. 1 Test program interface
PCI9054是美國PLX公司繼PCI9052之后推出的又一低成本PCI總線接口芯片,低功耗,PQFP 172pins封裝,它采用了先進的PLX數據管道結構技術,可以使局部總線快速轉換到PCI總線上[1]。PCI9054的主要特性如下:
1)符合PCI 2.2版本規范,32位,33 MHz總線
2)普通主總線接口,包含兩個DMA引擎
3)支持PCI雙地址周期
4)可編程中斷產生器
5)6個可編程并且零等待突發操作的FIFO
6)串行EEPROM接口
PCI的配置空間是編寫驅動程序的基礎。
PCI9054的許多功能都是通過配置寄存器來控制的。其中的部分寄存器是由系統上電時由EEPROM自動按廠商預定的映射方式填入,主要包括Vender ID、device ID、基本的中斷設置和部分本地配置寄存器。
1)作為重要的控制本地地址空間映射到PCI地址空間的寄存器有3個,以Space 0 為例:
LAS0RR:本地地址空間0大小寄存器,32位
LAS0BA:本地地址空間基地址寄存器,表示映射前的本地地址空間相對于自身的基地址和映射后本地地址空間在PCI總線空間上的物理基地址之間的對應關系。
PCIBAR2:PCI基地址寄存器,在從模式下,用來保存系統加電后BIOS為本地地址空間映射到PCI空間后的總線物理基地址。在驅動程序中,系統會發一個資源分配的數據請求包(IRP)。在響應這個IRP的例程中,可以得到PCI基地址寄存器中的值,經過轉換為內核模式下的系統虛擬地址才能為驅動程序所訪問。
2)中斷先寄存器(PCIILR)
中斷線寄存器為8位,改寄存器的值說明PCI設備的中斷引腳連接到系統中斷控制器的哪個中斷上。該寄存器的值由系統上電期間從EEPROM裝入。
3)中斷引腳寄存器(PCIIPR)
該寄存器說明設備使用PCI總線上的哪一個中斷引腳,PCI總線一共有4個中斷引腳。PCI9054僅支持#INTA,故本設計中該寄存器的值為01H。

圖2 Windows 2000 操作系統組件框圖Fig. 2 Windows 2000 OS component diagram
以上這幾個寄存器才開發PCI板卡時,以及編寫PCI板卡驅動時,是十分重要的[2]。可以通過EEPROM方式事先固化PCI配置寄存器中的值。EEPROM內容的固化可以設計響應的燒寫電路并使用通過PlxMon工具將配置值固化到EEPROM中,燒寫之前必須保證EEPROM中的值全為0xFFFFFFFF,否則燒寫電路驅動程序將不能識別該硬件。
內核模式環境實際上已經實現了一個通用操作系統的底層軟件平臺。內核模式環境主要由3個代碼模塊組成[3]。
1)硬件抽象層(HAL, Hardware Abstract Layer)
硬件抽象層是一個薄層軟件,它是硬件與操作系統其他部分的接口,是物理硬件資源的一種抽象。硬件抽象層通過動態鏈接庫實現,使用硬件抽象層例程的設備驅動程序可以在有相同CPU體系的平臺上實現二進制代碼兼容。
2)內核(Kernel)
如果說硬件抽象層代表了硬件平臺的抽象化,那么內核便是整個操作系統的神經中樞。它提供管理以下功能的機制:中斷和異常處理、線程調度和同步、多處理機同步、定時控制、內核對象。通過這些內核服務,操作系統的上層部分可以忽略底層CPU的體系結構[4]。內核提供了一個基于對象的界面。內核對象可以分為調度者對象和控制對象兩大類。內核提供了一個基于對象的界面。由于調度者對象主要負責同步性能并改變或影響線程調度,故設備很少使用到這類對象。但是卻經常用到以某種方式控制操作系統的行為控制對象。
3)執行體(Executive)
執行體由幾個不同的軟件模塊組成,它們是完全獨立的,只通過定義好的接口來通訊。執行體為用戶模式進程及它們之間的通信提供服務。執行體包含的重要的模塊有:系統服務接口、進程管理器、I/O管理器、即插即用管理器、電源管理器。
1)初始化例程
和動態鏈接庫類似,它向操作系統顯露一個名為DriverEntry的例程,每次啟動驅動程序[5]的時候,操作系統將調用這個入口。DriverEntry除了做一些必要的設備初始化工作外,還初始化一些Dispatch例程入口。使I/O管理器能知道當用戶的打開、關閉、讀寫等請求到來時各應調用哪些過程來處理。同時要初始化設備對象,申請軟硬件資源。
2)調度例程
調度例程(Dispatch)是設備驅動程序提供的主要函數,可以完成打開、關閉、讀取、寫入以及設備文件系統或網絡支持的任何其它功能。當被調用去執行一個I/O操作時,I/O管理器產生一個I/O請求包(IRQ),并且通過某個驅動程序的調度例程調用驅動程序。
3)Start I/O例程
串行化處理I/O請求,提高程序執行效率。驅動程序可以使用Start I/O例程來初始化與設備之間的數據傳輸。在開始設備操作時,I/O管理器調用驅動程序的Start I/O例程,分配處理該請求所需的任何資源,并設置設備運行。
4)中斷服務例程(ISR)
當一個設備中斷時,內核的中斷調度程序把控制權轉交給這個例程。ISR例程運行在高級別的IRQL上,所以他越簡單越好,以避免對低優先級中斷產生不希望的阻塞。ISR可以把剩余的大多數工作推遲到低中斷優先級的延遲過程調用(DPC)中實現。
5)延遲過程調用(DPC)
用于處理中斷響應的大多數工作,在ISR例程用排隊并得到調用。
1)設備的總線結構。設備采用什么樣的總線結構非常關鍵,因為不同的總線在硬件工作機制上存在很大的不同,所以驅動程序的設計也不同。
2)要了解設置的控制寄存器、狀態寄存器和數據寄存器,以及這些寄存器工作的特性。
3)要了解設備寄存器返回的狀態和錯誤信號,這些信號要通過驅動程序返回用戶。
4)要了解設備產生中斷的調節和中斷是數量
5)數據傳輸機制:最常用的數據傳輸機制,是通過IO指令和硬件設備進行數據讀寫。
6)許多設備帶有內存,PCI設備大多采用內存映射的方式映射到系統的物理內存。有的設備還要通過驅動程序來設置接口的寄存器。
NuMega公司的DriverStudio是一套簡化Windows驅動程序開發、調試及測試的工具包。其中包括:開發普通設備WDM驅動程序的DriverWorks、創建DDK支持的純C語言的WDM驅動程序框架、支持網絡設備驅動程序開發的DriverNetWorks及Windows內核單擊調試工具SoftICE。DriverWorks以面向對象的方式將編寫WDM驅動程序所需要的內核及訪問硬件的函數封裝成類。這樣,驅動開發者只要在工程向導的指引下逐步設置必要的參數,最后就可以得到WDM驅動程序框架。然后根據特定設備的訪問請求,想類中添加新的類對象和代碼即可。DriverWorks是基于VC或者VC.net工程的,經過編譯以后即可以得到設備驅動程序。它所用到的函數只不過是對DDK提供的庫函數的封裝,不會影響代碼的執行效率。
使用DriverStudio驅動生成向導建立驅動程序的步驟是[6]:
1)輸入路徑和工程名;
2)選擇要生成的驅動程序框架的類型,這里選擇WDM Driver;
3)選擇WDM驅動程序的類型,這里選擇WDM Function Driver;
4)選擇驅動程序所對應的硬件設備類型,選擇PCI,并填入對應的廠商編號和設備編號;
5)添加硬件資源,并選中“Use Interrupts”;
6)選擇驅動程序支持的功能項;
7)添加I/O控制;
8)添加注冊表中裝載的標志參數,這里不需要添加;
9)選擇電源管理選項;
10)選擇是否添加WMI屬性;
11)選擇安裝選項;
12)選擇其他選項。
前面講過PCI設備實現硬件操作時是將設備空間映射到計算機系統空間中實現的,因此一個很重要的設計就是在系統啟動時,保存系統給板卡分配的基地址空間,因為對硬件板卡的全部操作將會依賴于這些基地址。當然這些基地址是根據總線上的設備以及設備資源要求來分配的。由于系統啟動發現硬件板卡并給其分派好資源后,操作系統會給驅動程序發送一個代碼為IRP_MN_START_DEVICE的IRP,該IRP保函了系統分配的資源信息列表,因此在驅動程序中需要設計相應的例程來解析該資源列表。KIoRange和KMemoryRange兩個類分別用來實現對IO映射芯片的訪問和對內存映射芯片的訪問。根據得到的資源來調用者兩個類的成員函數即可實現對PCI9054寄存器和本地空間的訪問。
PCI板卡對軟件產生中斷,該中斷在DriverStudio生成的框架中會調用Irp()函數。可以在Device類中定義一個KEvent成員變量。首先注冊事件變量,獲取應用程序傳入的事件句柄后,對KEvent事件變量進行注冊。在Irp()中可以關閉中斷,以免中斷多次響應。然后在Isr_dpc()函數中開啟中斷,并且記錄中斷源,清除中斷,并對KEvent對象進行Set()操作。
DriverStudio向導生成的工程框架對每個IO控制接口都專門生成一個單獨的函數,在對應的函數中取出緩沖區數據,寫入對應Memory Resource或IO Resource的自定義地址中,或者從資源地址中取出數據,寫入輸出緩沖區,并報告數據區在緩沖區的長度。
驅動程序僅僅實現對硬件設備的操作,那么要實現人為的控制對設備的操作應該實現用戶程序和內核驅動程序的某種連接,這樣才會有更大的實際價值。
通常的板卡控制流程如下:使用CreateFile去打開板卡,然后使用DeviceIOControl去和驅動程序進行通信或者利用其讀寫少量的數據,進行大數據量連續的數據傳輸則考慮使用ReadFile和WriteFile的DMA方式去實現,當操作完成以后,直接使用CloseHandle去關閉設備。這種對應關系如表1所示。

表1 Win32函數與IRP例程關系對應表Tab.1 Correspondence between Win32 function and IRP routine
經過了艱苦的努力,這套一次性指令卡的驅動終于開發完成。在開發測試過程中,綜合使用了驅動設計過程中的各種技術。無論從理論上還是實踐上都有極為重要的研究意義。
[1]PCI 9054 Data Book Version 2.1,PCI 9054 Data Book[S].U.S:PLX, 2000.
[2]孟楠, 劉文怡. 基于PXI總線的數字量IO卡設計[J].科學技術與工程, 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環境下數據采集卡設備驅動程序的設計[J]. 信息工程大學學報, 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設備驅動程序開發[M].2版.北京:電子工業出版社,2005.