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