文獻(xiàn)標(biāo)識(shí)碼: A
文章編號(hào): 0258-7998(2012)11-0143-03
隨著在線高清電影以及實(shí)時(shí)視頻會(huì)議等應(yīng)用的快速發(fā)展,數(shù)據(jù)傳輸呈現(xiàn)速率高、實(shí)時(shí)性強(qiáng),數(shù)據(jù)量大的趨勢,由此產(chǎn)生了高速實(shí)時(shí)數(shù)據(jù)傳輸?shù)膯栴}。在眾多高速實(shí)時(shí)數(shù)據(jù)傳輸?shù)脑O(shè)計(jì)方案中,PCI/PCI-E總線不可比擬的傳輸速率優(yōu)勢成為設(shè)計(jì)高速傳輸設(shè)備時(shí)的首選總線[1-2]。
為了能夠正常使用PCI/PCI-E總線進(jìn)行高速數(shù)據(jù)傳輸,必須開發(fā)相應(yīng)平臺(tái)下的設(shè)備驅(qū)動(dòng)程序。本文以自主研發(fā)的BCS5731芯片為例,介紹了在Windows NT環(huán)境下基于WDM模型的PCI/PCI-E總線設(shè)備驅(qū)動(dòng)開發(fā)方案,著重分析了高速實(shí)時(shí)傳輸系統(tǒng)中驅(qū)動(dòng)部分的設(shè)計(jì)與實(shí)現(xiàn)。
1 WDM驅(qū)動(dòng)程序設(shè)計(jì)
1.1 WDM驅(qū)動(dòng)模型介紹[3]
WDM模型是微軟針對Windows 2000及后續(xù)操作系統(tǒng)制定的驅(qū)動(dòng)開發(fā)模型,具有即插即用和電源管理等方便用戶使用的特性。目前微軟正力推新一代的WDF驅(qū)動(dòng)開發(fā)模型,但從本質(zhì)上來說WDF是對WDM進(jìn)行封裝后的模型;而且WDM模型的驅(qū)動(dòng)開發(fā)實(shí)例眾多,極大地方便了驅(qū)動(dòng)的開發(fā),所以本文采用了WDM驅(qū)動(dòng)開發(fā)模型。
WDM驅(qū)動(dòng)基于分層的模式實(shí)現(xiàn)。完成一個(gè)設(shè)備的操作至少需要兩個(gè)驅(qū)動(dòng)設(shè)備共同完成[4]。其中與系統(tǒng)連接最緊密的是底層總線驅(qū)動(dòng),而總線驅(qū)動(dòng)也是最為復(fù)雜的部分。目前總線驅(qū)動(dòng)通常由操作系統(tǒng)提供,驅(qū)動(dòng)開發(fā)者只需要開發(fā)設(shè)備驅(qū)動(dòng)以及可能需要的過濾驅(qū)動(dòng)。圖1所示為WDM驅(qū)動(dòng)模型層次結(jié)構(gòu)圖。
1.2 驅(qū)動(dòng)實(shí)例設(shè)計(jì)
對于WDM驅(qū)動(dòng)而言,主要的函數(shù)是DriverEntry例程、AddDevice例程、PnP例程以及各個(gè)IRP的派遣例程。對應(yīng)于應(yīng)用程序的main入口函數(shù),Windows驅(qū)動(dòng)程序相應(yīng)的入口函數(shù)為DriverEntry[5]。
DriverEntry例程由內(nèi)核中的I/O管理器負(fù)責(zé)調(diào)用,是驅(qū)動(dòng)第一個(gè)執(zhí)行的例程。在本設(shè)計(jì)中,根據(jù)需要在DriverEntry例子中注冊了以下例程:
pDriverObject->DriverExtension->AddDevice = AddDeviceRoutine
pDriverObject->MajorFunction[IRP_MJ_PNP] = PnpRoutine
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlRoutine
pDriverObject->MajorFunction[IRP_MJ_WRITE] = WriteRoutine
pDriverObject->MajorFunction[IRP_MJ_READ] = ReadRoutine
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = faultRoutine
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DefaultRoutine
下面對上述例程進(jìn)行分析。
(1) AddDeviceRoutine函數(shù)
AddDerice Routine函數(shù)只出現(xiàn)在WDM驅(qū)動(dòng)程序中,在NT式驅(qū)動(dòng)中沒有此回調(diào)函數(shù)。此函數(shù)用于創(chuàng)建設(shè)備對象,并由PnP管理器調(diào)用。具體操作包括:創(chuàng)建設(shè)備對象,創(chuàng)建并注冊設(shè)備接口(為兼容也可創(chuàng)建符號(hào)連接),將創(chuàng)建的設(shè)備掛載到設(shè)備堆棧中,最后設(shè)置相關(guān)標(biāo)志。值得注意的是,標(biāo)志位中的讀寫方式在創(chuàng)建后不能在程序其他方面進(jìn)行修改,且不同的讀寫標(biāo)志位在編寫讀寫部分代碼時(shí)具有著不同的實(shí)現(xiàn)方式。
(2) PnPRoutine函數(shù)
PnPRoutine函數(shù)執(zhí)行即插即用功能,一個(gè)功能完整的PnP函數(shù)需要處理眾多的子IRP, 如IRP_MN_START_
DEVICE、 IRP_MN_STOP_DEVICE、IRP_MN_REMOVE_DE-
VICE等20多個(gè)子類IRP。在實(shí)際的接口驅(qū)動(dòng)開發(fā)中,大部分PnPRoutine的子類IRP不需進(jìn)行逐一編寫,驅(qū)動(dòng)開發(fā)者只需處理必要的子IRP,其余的子類IRP可以統(tǒng)一傳遞給總線驅(qū)動(dòng)處理即可。通常IRP_MN_START_DEVICE和IRP_MN_REMOVE_DEVICE和兩個(gè)子類IRP是WDM驅(qū)動(dòng)必需單獨(dú)處理的IRP。
(3) ControlRoutine函數(shù)
ControlRoutine函數(shù)常用于應(yīng)用程序與驅(qū)動(dòng)程序之間的通信。程序設(shè)計(jì)者首先定義一種I/O控制碼,然后用函數(shù)DeviceIoControl將控制碼和請求一起傳遞給驅(qū)動(dòng)程序。驅(qū)動(dòng)程序則在ControlRoutine中實(shí)現(xiàn)這些控制碼。
控制碼的實(shí)現(xiàn)往往采用Switch(){case:}的形式。在本設(shè)計(jì)中,采用ControlRoutine進(jìn)行DMA分配和寄存器配置。因此需要定義數(shù)種不同的控制碼。
(4) ReadRoutine和WriteRoutine函數(shù)
兩個(gè)函數(shù)分別用于target讀寫操作,當(dāng)應(yīng)用層調(diào)用ReadFile和WriteFile時(shí),I/O管理器生成相應(yīng)的IRP并發(fā)送到對應(yīng)的函數(shù)中。驅(qū)動(dòng)程序創(chuàng)建的設(shè)備通常有三種讀寫方式:緩沖區(qū)方式、直接方式和其他方式。ReadRoutine和WriteRoutine中使用的讀寫方式是由AddDeviceRoutine中設(shè)置的標(biāo)志位決定。因此在驅(qū)動(dòng)創(chuàng)建設(shè)備對象時(shí),需要確定采用哪種讀寫方式。在實(shí)際的開發(fā)過程中,為了保證數(shù)據(jù)的安全盡量不采用第三種實(shí)現(xiàn)讀寫方式(其他方式)。
(5) DefaultRoutine函數(shù)
設(shè)置的默認(rèn)處理例程,程序中簡單地略過當(dāng)前IRP,然后調(diào)用底層總線驅(qū)動(dòng)??偩€驅(qū)動(dòng)處理傳遞來的IRP_MJ_CLOSE和IRP_MJ_CREATE子類IRP。
1.3 高速連續(xù)DMA傳輸設(shè)計(jì)[6]
本設(shè)計(jì)需要解決的一個(gè)難題是高速實(shí)時(shí)數(shù)據(jù)的傳輸。整個(gè)傳輸系統(tǒng)如圖2所示。
系統(tǒng)傳輸流程為:基帶芯片通過有線或無線方式接收到大量高速實(shí)時(shí)數(shù)據(jù),傳遞到PCI Local端。PCI local端將數(shù)據(jù)傳遞到PCI Core與主機(jī)連接端,將數(shù)據(jù)通過PCI接口寫入主機(jī)分配的DMA內(nèi)存中;或者設(shè)備從DMA內(nèi)存中讀取主機(jī)數(shù)據(jù)。在傳輸過程中采用設(shè)備主控DMA方式。
由于硬件基帶的傳輸速率高達(dá)300 Mb/s,且主機(jī)只能分配規(guī)模有限的DMA內(nèi)存,所以在主機(jī)數(shù)據(jù)接收時(shí),若主機(jī)PCI接口端無法設(shè)計(jì)一種高效的數(shù)據(jù)讀取方式以及主機(jī)與硬件實(shí)時(shí)的信息交互渠道,將會(huì)造成大量數(shù)據(jù)的丟失和數(shù)據(jù)讀取的錯(cuò)誤。
本文設(shè)計(jì)了一種高效的同步機(jī)制,該機(jī)制采用DMA傳輸數(shù)據(jù),從而保證了數(shù)據(jù)傳輸?shù)母咝?。此外在?qū)動(dòng)層和PCI接口層進(jìn)行同步驗(yàn)證,保證了數(shù)據(jù)的一致性,如圖3所示。設(shè)計(jì)思路如下:
(1) 驅(qū)動(dòng)采用公共內(nèi)存編寫方式。根據(jù)應(yīng)用層輸入信息分配相應(yīng)大小的DMA內(nèi)存,將該內(nèi)存抽象為1~N個(gè)長度為M字節(jié)的DMA寄存器,并將分配的DMA首地址傳輸給硬件。設(shè)內(nèi)存首地址用指針DMAmemory表示。
(2) 驅(qū)動(dòng)設(shè)備擴(kuò)展中申明一個(gè)整型變量,用于保存上次硬件操作完畢時(shí)的DMA寄存器編號(hào),命名為RegNumber,在驅(qū)動(dòng)初始化階段初始化為0值。
(3) PCI接口中分配一個(gè)長度為N bit的寄存器稱為寄存器R,寄存器R的位數(shù)與DMA寄存器個(gè)數(shù)一一對應(yīng)。將寄存器R初始化為全0。
(4) 硬件實(shí)時(shí)查詢寄存器R,若不為全1,則FPGA向主機(jī)寫入數(shù)據(jù); 若為全1,則暫停數(shù)據(jù)寫入。
(5) 當(dāng)數(shù)據(jù)從基帶傳輸?shù)街鳈C(jī)端的PCI接口時(shí),硬件首先填充DMA內(nèi)存的第一個(gè)寄存器,填充完畢后將寄存器R的首位設(shè)置為1。后續(xù)數(shù)據(jù)依次填充DMA寄存器,并置位寄存器R對應(yīng)的位為1。硬件填充完一個(gè)寄存器后,向主機(jī)發(fā)送一個(gè)電平中斷。
(6) 主機(jī)端驅(qū)動(dòng)檢測到硬件中斷,中斷例程中簡單清除電平中斷后,啟動(dòng)DPC例程。
(7) DPC例程中首先判斷寄存器R是否為全0,若為全0,則表示數(shù)據(jù)未寫入DMA內(nèi)存中。DPC例程直接返回,等待下個(gè)中斷。
(8) 若寄存器R不為全0,則表示已有數(shù)據(jù)寫入。檢查RegNumber值,并從RegNumber+1編號(hào)的DMA寄存器開始讀數(shù)。讀取完一個(gè)寄存器后,向該DMA寄存器對應(yīng)的寄存器R中的bit位發(fā)出寫1命令,將硬件接收PC機(jī)下發(fā)的操作命令對應(yīng)為0。
(9) 更新RegNumber,if(RegNumber < N) {RegNumber++;} else{RegNumber = 0;}。
(10) DPC執(zhí)行完畢,函數(shù)返回。等待下一個(gè)中斷。
2 控制程序設(shè)計(jì)
本文設(shè)計(jì)的驅(qū)動(dòng)實(shí)現(xiàn)了數(shù)據(jù)收發(fā)完整功能,能提供用戶層進(jìn)行可變大小DMA內(nèi)存分配,使能數(shù)據(jù)收發(fā)、接收數(shù)據(jù)校驗(yàn)及提取數(shù)據(jù)幀頭信息等操作。
本設(shè)計(jì)基于MFC實(shí)現(xiàn)了一個(gè)控制界面程序,通過界面操作可實(shí)現(xiàn)用戶定義DMA大小分配,數(shù)據(jù)收發(fā)控制命令、接收數(shù)據(jù)量顯示及幀頭信息顯示等功能,如圖4所示??刂平缑媾c驅(qū)動(dòng)通信采用IOCTL控制碼,步驟如下:
(1) 使用CTL_CODE宏定義控制碼。本例定義的控制碼可簡單歸類為讀/寫寄存器。數(shù)據(jù)在應(yīng)用層進(jìn)行組裝。
(2) 驅(qū)動(dòng)程序中的ControlRoutine例程實(shí)現(xiàn)相應(yīng)控制碼功能。
(3) 編寫一個(gè)DLL,實(shí)現(xiàn)驅(qū)動(dòng)與界面的交互接口。DLL內(nèi)部實(shí)現(xiàn)打開設(shè)備驅(qū)動(dòng),調(diào)用DeviceIoControl發(fā)送命令等操作。在外部向應(yīng)用層提供用于發(fā)送命令的接口函數(shù)。如分配DMA、寫入DMA首地址、使能數(shù)據(jù)收發(fā)等。
(4) 應(yīng)用程序調(diào)用DLL提供的接口函數(shù),實(shí)現(xiàn)對設(shè)備的控制。
本文分析了一般PCI/PCI-E設(shè)備驅(qū)動(dòng)的設(shè)計(jì)要求與設(shè)計(jì)方式,詳細(xì)介紹了重要例程的設(shè)計(jì)需求,重點(diǎn)分析了高速實(shí)時(shí)DMA傳輸系統(tǒng)的設(shè)計(jì)方法,給出了驅(qū)動(dòng)設(shè)計(jì)的詳細(xì)步驟,最后介紹了控制程序的設(shè)計(jì)。提出的高速實(shí)時(shí)DMA傳輸系統(tǒng)的設(shè)計(jì)方法,實(shí)現(xiàn)了高速實(shí)時(shí)數(shù)據(jù)傳輸功能,解決了當(dāng)基帶與PC機(jī)傳輸速率不一致時(shí)。經(jīng)常出現(xiàn)的數(shù)據(jù)丟失和無法高速傳輸?shù)膯栴}。
參考文獻(xiàn)
[1] 尹勇,李宇.PCI總線設(shè)備開發(fā)寶典[M].北京:北京航空航天大學(xué)出版社,2005.
[2] PCI-SIG. PCI Express base specification revision1[S]. PCI_SIG,April 15 2003.
[3] 吳宏鋼,尹愛軍,秦樹人.基于WDM模型的PCI數(shù)據(jù)采集卡驅(qū)動(dòng)程序設(shè)計(jì)[J].中國測試技術(shù),2008,34(3)59-62.
[4] 張帆,史彩成,等.Windows驅(qū)動(dòng)開發(fā)技術(shù)詳解[M].北京:電子工業(yè)出版社,2008.
[5] Microsoft. Microsoft Windows Driver Kits [EB/OL].[2010-2-26]. http//www.micorsoft.com//wdk.
[6] 王招凱,禹衛(wèi)東.基于PCIE總線的雷達(dá)數(shù)據(jù)記錄器驅(qū)動(dòng)程序開發(fā)[J].微計(jì)算機(jī)信息,2008,24(4-2):89-91.