引言
如果把PC機作為控制系統的操作平臺,PCI總線作為一種先進的高性能32/64位局部總線正迅速取代原來的ISA總線的主導地位,以用于高速外設,并成為微型計算機系統的主流系統,因而也成為工程開發人員用于工業控制的首選。為了縮短開發周期,一般都采用專用的接口器件。本文就是采用PLX公司的PCI9052來把PCI總線上的操作轉換為對局部總線的操作,同時通過雙口RAM實現和下位機的存儲轉接。針對一般PCI總線開發時由于軟硬件分離使開發的軟硬件不能很好結合的現象,本文結合實例介紹了應用程序并給出了如何通過DriverStudio開發的PCI設備驅動程序來訪問PCI設備卡硬件資源的具體程序。
1、 PCI的配置空間及其配置
PCI總線支持存儲器地址空間、I/O地址空間和配置空間等三個物理空間。其中,配置空間是PCI總線所特有的一個空間,PCI總線能實現即插即用的功能,正是通過它特有的配置空間來實現的。PCI配置空間的大小為256字節,分為頭標區和設備有關區。直接影響設備特性的配置寄存器在頭標區,其他部分則因設備而異。PCI總線的配置空間通常與PCI接口芯片相關。該配置空間包括一系列的PCI配置寄存器。本文采用的PCI9052芯片的配置寄存器分為PCI配置寄存器和局部配置寄存器,二者都可以由PCI總線和串行EEPROM訪問。
在PCI配置寄存器中的設備ID、制造商ID、版本號、首區類代碼、類別代碼、指令寄存器和狀態寄存器等寄存器在所有的PCI設備中都必須實現,通常情況下,操作系統可使用這些寄存器的內容來決定該PCI設備的加載其驅動程序。
PCI總線最重要的功能之一是通過基地址寄存器和局部配置寄存器在地址空間重定位PCI設備。系統上電時,通過上層應用軟件能判斷系統中存在那些設備,并建立協調的地址映射。所以,基地址寄存器和局部配置寄存器是實現驅動程序的關鍵。
PCI配置寄存器提供有6個基地址寄存器(BASE0~BASE5)這些基地址都是系統中的物理地址,其中BASE0和BASE1是用來訪問局部配置寄存器的基地址,BASE0是映射到內存的基地址,BASE1是映射到I/O的基地址,可用于通過內存和I/O來訪問局部配置寄存器。這兩個基地址可固定用于PCI9052芯片的寄存器操作。
通過BASE2~BASE5四個空間最多可以訪問局部端所接的4個芯片,實現4個局部地址空間(局部空間0~3)的PCI總線訪問。PCI總線對局部端所接芯片的局部地址映射是通過4個寄存器組(PCI基地址寄存器,局部范圍寄存器,局部基地址寄存器,局部總線區域描述符)來實現的。這個組定義了每個空間以及相應局部空間的特性。它們將局部端的芯片通過局部端地址(在局部配置寄存器中設置)翻譯成PCI總線地址,也就是將本地的芯片映射到系統的內存或I/O口。而片選信號寄存器則是用來選定這些局部端所接的芯片的。這樣,用程序操作這一段內存(或I/O)實際上就是對本地芯片的操作。其映射關系如圖1所示。這些寄存器的內容必須在芯片復位時通過串行E2PROM進行加載,而正確配置E2PROM的內容則是使用PCI9052的關鍵。
本設計選取LAS0(Local Address Space 0)來訪問局部端的雙口RAM芯片中的2 KB尋址空間,與其有關的寄存器有四個:LAS0范圍寄存器、LAS0局部基址寄存器、LAS0局部總線區域描述符和片選0基址寄存器。LAS0范圍寄存器規定了地址空間的大小。由于需要2 KB的內存空間,而計算機預留了32 KB空間(即8000H),所以其寄存器值為0xFFFF8000H,而類型則是不可預取的;LAS0局部基地址寄存器定義了設備卡資源上所占用的基地址,它的最終目的是將這個基地址重新映射到PCI地址空間。由于基地址必須是32KB的整數倍,因此,為方便起見,可以將基地址定為00000000H,又由于位0為空間使能位,所以,寄存器的值為00000001H;LAS0局部總線區域描述符用來定義地址空間0的具體工作特性。
該總線采用16位總線寬度,工作方式定義為不使能突發和不預取,因此,該寄存器的數值初步確定為4043A1C0H,最終的值則需要不斷測試才能確定;片選0基址寄存器使用PCI9052的CS0#作為雙口RAM的片選信號,CS0#片選信號的起始地址和地址范圍由片選0基址寄存器設置,局部總線的容量是2 KB,第11位為1,基地址是該范圍的16倍,一般將倍數放置在范圍位之后,所以寄存器值設置為0xO008401。當從局部空間0基址開始的2 KB空間范圍落在CS0基地址寄存器所設置的范圍內,CS0端有效,這種方式可減少地址譯碼得到的片選邏輯。
用PLX9052可將PCI總線上的操作轉換為對局部總線的操作,即通過LAD0~LAD7、RD、WR、CS等對局部端芯片訪問。如果系統分配給本卡的存儲空間為FFFF0000H~FFFF7FFFFH。那么,當系統通過PCI總線訪問這個區域時,PLX9052就會應答,并將其轉換為局部地址0x0000H~0x07FFH,另外,PLX9052自身也有一些內部寄存器,它們被自動映射到另一片內存區域,可通過PCI總線直接訪問。
PCI9052提供了兩種類型的中斷源(硬件中斷和軟件中斷)。中斷可通過PCI9052中斷控制/狀態寄存器來(INTCSR)允許和禁止。PCI9052通過2個局部中斷引腳來實現硬件中斷,它們支持邊緣和電平觸發中斷,可以通過對INTCSR寄存器的編程來實現局部中斷,然后產生PCI中斷(INTA),并生成PCI中斷INTA#方式。PCI9052可以軟件方式產生中斷,設計時只需要將INTCSR寄存器的軟件中斷位設置為1即可。
2、 驅動程序的開發
在開發PCI板卡功能驅動程序之前,首先要明白所需的PCI硬件資源,并針對設備卡的硬件資源來處理PCI設備的內存、端口的讀寫,以及中斷處理,從而實現PCI設備功能。
2.1 驅動程序在操作系統體系結構中的位置
操作系統結構可分為五層模型:
(1)用戶應用程序;
(2)IO管理層;
(3)驅動程序;
(4)HAL(硬件抽象層);
(5)硬件。
圖2給出了Windows2000操作系統驅動程序開發者所關心的特征,一般情況下,軟件要么在用戶模式中執行,要么在內核模式下執行。從驅動開發的角度上看,WDM模型為存在于Win-dows2000系統中的驅動程序提供了一個參考框架。作為Windows2000系統結構開發人員,由于操作系統為應用程序,而在驅動程序和硬件之間提供有系統服務接口和平臺相關操作,因此,設計時只需要關注應用程序和設備驅動程序的開發。
2.2 設備資源
PCI設備的硬件資源分配與管理是驅動程序很重要的部分,設備的硬件資源包括內存空間、I/O空間和中斷。由于PCI總線為PnP總線,PCI設備的硬件資源是由PCI配置機構動態分配給PCI配置寄存器的,因此,驅動程序首先需要取得這些資源才能操作硬件。當PnP管理器檢測到PCI設備時,系統就會發送IRP_MN_START_DEVICE的IRP給驅動程序,驅動程序調用OnStartDevice以啟動例程處理,并在啟動例程里獲取該IRP棧,同時把它包含的系統分配給該設備的資源信息。
用DriverStudio開發驅動程序時,應在Wizard中設置好PCI設備的資源。對于實際的PCI9052設備卡,其基地址寄存器0和1分別固定用于PCI9052局部寄存器的內存映射地址和I/O映射地址,基地址寄存器2則用于設備卡的內存映射地址,并使用局部中斷引腳來產生PCI中斷,以分別生成對應的KIoRange類、KMemoryRange類和KInterrupt類。這些配置信息由配置管理器發送到OnStartDevice中重載該成員函數,而開發者則不必再處理。在一般情況下,驅動程序無需再訪問PCI設備的配置空間,如果需要訪問,則可通過類KPciConfiguration,該類包含了通過向PCI總線發送瀆寫配置空間的IRP操作。也可定義類KRe-sourceAssignment來獲取PCI的端口地址和中斷號以及內存地址和大小,并把得到的資源放在用戶自己定義的變量中。
2.3 WDM驅動程序對硬件資源的訪問
獲取設備的硬件資源以后,就可以對硬件資源進行訪問了。對硬件的訪問一般包括I/O端口訪問和內存訪問,它們分別對應PCI配置空間的I/O空間和內存空間。從圖2可以看出,當應用程序需要訪問設備時,它就會調用Win32API函數(如ReadFile)。Win32子系統模塊通過調用平臺相關的系統服務接口實現該API,而平臺相關的系統服務則調用內核模式來支持例程。即在調用ReadFile函數時,首先到達系統的人口點,然后調用系統服務接口,最后由系統調用內核模式的服務例程。執行時首先檢查傳遞給它們的參數,然后創建一個“I/O請求包(IRP)”的數據結構,并把這個數據結構送到某個驅動程序的入口點執行IRP設備驅動程序,最后再訪問硬件。對于PIO方式的設備,一個IRP_MJ_READ操作將直接讀取設備的端口或設備的內存寄存器。一般會使用硬件抽象層(HAL)來訪問硬件。IRP貫穿于驅動程序之間,它在應用程序、驅動程序和設備之間起著橋梁作用,可稱之為內核態的“消息”。驅動程序完成一個I/O操作后,可通過調用一個特殊內核模式服務例程來完成該IRP,完成操作時再處理IRP的最后工作,以它使等待的應用程序恢復運行。
用DriverStudio開發驅動程序時,可根據配置聲明KIoRange類、KMemoryRange類和KInterrupt類來實現對內存空間、I/O空間、中斷的操作。在本例中,基地址寄存器0和1固定用于PCI9052芯片的操作寄存器內存映射地址和I/O映射地址,基地址寄存器2則用于雙口RAM的內存映射。通過一個外部引腳即可產生中斷。標識兩個KMem-oryRange類實例、一個KIoRange類實例和一個KInterrupt類實例的具體實現細節如下:
(1) I/O端口的訪問
I/O端口的訪問流程如圖3所示,應用程序通過API函數DeviceIoControl的調用,并調用驅動程序的分發例程DeviceControl,同時通過KIoRange類來實現對I/O映射空間的訪問。需要注意的是,當DeviceloControl異步調用的時候,必須在驅動程序中添加取消例程,并在DeviceControl例程中阻止一個應用程序對其的多次調用。KIoRange類的成員函數outb、inb、outw、inw、ind、outd可分別用于從端口讀或寫一個字節、字和雙字數據。在WDM中,對于I/O端口,系統可將其看成寄存器,一般用于數字傳輸量比較小的地方。在對PCI設備的訪問中,I/O端口的訪問通常比較頻繁。
(2) 內存的訪問
在基于DriverStudio開發的驅動程序中,向存儲器空間讀寫大量數據一般選用Write/Read函數,但對于一個實際存在的物理設備的訪問,在某一時刻只能進行一個操作,因而在訪問內存對象的時候,一般都要求一個IRP排隊的隊列,可通過設備類的成員函數QueueIrp將IRP插入隊列。DriverWorks提供有KDeviceQueue類,其成員函數StartIo用于處理設備對象的IRP隊列。具體的操作是通過KMemoryRange類來實現對設備內存映射空間的訪問。其訪問流程見圖4所示。需要注意的是,當IRP隊列為空時,調用QueueIrp時,系統將同步調用StartIo函數。
(3) 中斷處理
驅動程序的中斷處理編程涉及到內核機制比較多的一種驅動程序,因而相對復雜。首先用中斷服務程序提升系統的IRQL,但不能進行大多數有用的內核調用。另外,提升IRQL運行代碼需要盡可能快地運行。所以,中斷處理一般和在DIS-PATCH_LEVEL級運行的延遲調用(DPC)例程相配合可解決以上兩個問題。在DriverWorks中,通常通過KInterrupt類和KDeferredCall類來實現,并通過向導來在中斷服務例程和DPC中增加功能代碼。KDeferredCall類封裝有DPC的操作。KInter-rupt類用于實現硬件中斷的處理,其成員函數包括中斷初始化,以及將一個中斷服務例程連接到另一個中斷和解除其連接等。在中斷服務例程中把IRP交給DPC例程,可在DPC處理完后結束該IRP。需要注意的是,中斷服務例程不是KInter-rupt類的成員函數,它的主要作用是減少中斷延遲時間。
3、 結束語
本文主要從訪問設備硬件資源的角度介紹了PCI配置空間的配置和驅動程序的開發方法。利用該方法可對PCI板卡的配置空間和所需的硬件資源進行正確設置,然后通過DriverStudio的驅動程序向導生成工具在程序框架里添加適當的代碼,最后借助于DriverStudio開發包提供的調試工具SoftICE和DriverMonitor以及由Wizard產生的控制臺應用程序,來快速開發出基于PCI總線的設備驅動程序。
責任編輯:gt
評論
查看更多