PCI傳輸卡的WDM驅動程序設計
更新時間: 2007-05-08 15:43:03來源: 粵嵌教育瀏覽量:1002
摘要:介紹了在Windows2000操作系統下,使用DriverStudio軟件編寫符合WDM模式的PCI數據傳輸卡驅動程序,并詳細分析了一個應用實例。
關鍵詞:PCI總線 設備驅動程序 WDM模式 DriverStudio
?。校茫煽偩€規范是為提高微機總線的數據傳輸速度而制定的一種局部總線標準。在設計自行開發的基于PCI總線的數據傳輸設備時,需要開發相應的設備驅動程序。通常開發PCI設備驅動程序有多種模式,在Windows2000環境下,主要采用WDM模式。本文針對自行開發的基于PCI總線的CCD視頻信號傳輸控制卡,編寫了符合WDM模式的驅動程序。
1 WDM模式驅動程序
1.1 WDM模式(Windows Driver Model)
?。祝椋睿洌铮鳎螅玻埃埃皩︱寗映绦虻木帉懖辉倩谝酝模祝椋睿常停祝椋睿梗碌模郑模ㄌ摂M設備驅動程序)結構,而是基于一種新的驅動模型——WDM(Windows Driver Model)。
WDM為Windows98/2000/XP操作系統的設備驅動程序的設計提供了統一的框架。WDM來源于Windows NT的分層32位設備驅動程序模型(layered 32-bit device driver model)。它支持更多的特性,如即插即用(PnP)、電源管理、WMI和NT事件。
1.2 設備驅動程序
設備驅動程序是操作系統的一個組成部分,它由I/O管理器(I/O Manager)管理和調動。Windows2000操作系統下的I/O管理器功能描述如圖1所示。
?。桑瞎芾砥髅渴盏揭粋€來自用戶應用程序的請求就創建一個I/O請求包(IRP)的數據結構,并將其作為參數傳遞給驅動程序。驅動程序通過識別IRP中的物理設備對象(PDO)來區別是發送給哪一個設備。IRP結構中存放請求的類型、用戶緩沖區的首地址、用戶請求數據的長度等信息。驅動程序處理完這個請求后,在該結構中填入處理結果的有關信息,調用IoCompleteRequest將其返回給 I/O管理器,用戶應用程序的請求隨即返回。訪問硬件時,驅動程序通過調用硬件抽象層的函數實現。
1.3 DriverStudio工具簡介
?。危酰停澹纾?Lab公司開發的DriverStudio是一整套開發、調試和檢測Windows平臺下設備驅動程序的工具軟件包。它把DDK(Device Development Kit)封裝成完整的C++函數庫,根據具體硬件通過向導生成框架代碼,并且提供了一套完整的調試和性能測試工具SoftICE、DriverMonitor等。
2 應用實例
本文利用PCI專用接口芯片PCI9052設計了一個數據傳輸控制卡。卡上主要的芯片有PCI9052、FIFO(CY7C4221)、CPLD(MAX7064S)和A/D轉換器(MAX1197)。傳輸卡硬件框圖如圖2所示。面陣CCD得到的視頻信號經過調理電路,生成的視頻調理信號通過A/D轉換器進行數字化處理,送入FIFO中。在CPLD的控制下,數據經過PCI9052送入PCI總線,再傳送到計算機內存中,并顯示在監視器上。驅動程序必須實現如下幾個基本功能:(1)硬件中斷;(2)能支持應用程序獲取數據;(3)能根據外部FIFO(CY7C4221)的狀態啟動或停止突發傳輸。
在數據輸入過程中,重要的是對數據進行實時控制,因此需要硬件中斷。在中斷程序中,根據外部FIFO狀態完成數據的讀入。
2.1 用DriverWizard生成驅動程序框架
DriverStudio中的DriverWorks軟件為開發WDM程序提供了一個完整的框架。它包含一個可快速生成WDM驅動程序框架的代碼生成向導工具DriverWizard,而且還帶有許多類庫。在用DriverWizard生成的程序框架中寫入相對于設備的特定代碼,編譯后即可得到所需的驅動程序。
在利用DriverWorks V2.7的向導Driver Wizard完成驅動程序的框架時共有11個步驟,其中關鍵步驟有:
?。ǎ保┰诘谒牟街羞x中PCI,并在VendorID和DeviceID中分別輸入廠商號和設備號,還需填入PCI Subsystem ID和PCI Revision ID。這四項可以用網上的免費軟件PCITree或PCIView瀏覽PCI設備,用這兩個軟件也可以得到BAR0~BAR5的資源分配情況和中斷號。
?。ǎ玻┑谄卟剑桑遥嘘犃信抨牱椒?,它決定了驅動程序檢查設備的方式。本設計選SystemManaged,則所有的IRP排隊都由系統(即I/O管理器)完成。
?。ǎ常┑诰挪绞顷P鍵的一步。首先在Resources中添加資源,在name中輸入變量名,在PCI Base Address中輸入0~5的序列號。0~5和BAR0~BAR5一一對應。在設置中斷對話框中,在name欄寫入中斷服務程序的名稱,選中創建中斷服務程序ISR?穴Create ISR?雪,不選創建延遲程序調用DPC(Create DPC),選中Make ISR/DPC class functions,使ISR/DPC成為設備類的成員函數。
其次選中Buffer以選取讀寫方式,用于描述與I/O操作相關的數據緩沖區。本設計需要快速傳送大量數據,因此采用Direct I/O方式。
(4)在第十步中,需要加入與應用程序或者其他驅動程序通信的I/O控制代碼參量。
2.2 驅動程序模塊框圖和代碼分布
?。校茫稍O備驅動程序模塊包括配置空間的訪問模塊、IO端口模塊、內存讀寫模塊和終端模塊等。各模塊之間是對等的。驅動程序模塊框圖如圖3所示。
驅動程序初始化模塊代碼段放在#pragma code_seg(″INT″)和#pragma code_seg()之間。在系統初始化完成后,這部分代碼從內存中釋放,防止占用系統寶貴的內存資源。#pragma code_seg()之后是驅動程序和系統的許多模塊的實現部分。這部分在驅動程序運行后不會從內存中釋放。
2.3 驅動程序主要模塊的實現
?。?)配置空間的訪問模塊
?。模颍椋觯澹颍祝铮颍耄蟮模耍校悖椋茫铮睿妫椋纾酰颍幔簦椋铮铑惙庋b了訪問PCI設備配置空間的所有操作。首先初始化這個類的實例:
KpciConfiguration PciConfig()m_Lower.TopOfStack());
/?觹m_Lower是 KpnpLowerDevice類的對象。m_LowerTopOfStack()返回當前設備堆棧頂部的設備對象。*/
初始化完后可以直接利用成員函數 ReadHeader/ WriteHeader函數訪問所有的配置寄存器。
為了確定映射空間的類型和大小,先向目標基地址寄存器寫入0Xffffffffh,然后回讀該寄存器的值。如果位為1,表示映射于I/O空間,反之為存儲空間;如果映射于存儲空間,從第四位開始計算0的個數可以確定內存空間的大?。蝗绻牵桑戏绞剑瑥牡诙婚_始計算0的個數可確定I/O空間的大小,為256字節。如果設備的存儲空間超過256字節,要實現設備的整個存儲部分的訪問,就必須采用內存映射。
?。ǎ玻桑喜僮髂K
Driverworks的KIoRange類封裝了I/O端口訪問的操作。部分代碼如下:
{……
KIORange DevIoPort () ;//創建實例
NTSTATUS status= DevIoPort ().Initialize ( pResListTranslated,pResListRaW,PciConfig.BaseAddressIndexToOrdinal(0));
/* 個參數為轉換后的資源列表指針;第二個參數為原始資源列表指針;第三個參數中的0為 I/O口對應的基地址,用來轉換成特定端口資源的序數?*/
If(NT _SUCCESS(status))
{……
DevIoPort.inb(0,LineBuf1,10);
/*成功初始化后可分別用KIoRange類的成員函數inb(/outb)從端口中讀/寫字節 */
}
else{Invalidate();return status;
/*未能初始化成功,錯誤信息在status中*/
{
……}
(3)內存讀寫模塊
DriverWorks的 KMemoryRange類封裝了端口訪問的操作。
status=m_MemoryRange().Initialize(pResListTranslated,pResListRaw, PciConfig.BaseAddressIndexToOrdinal(0));
此函數的參數、意義及具體用法與I/O端口的操作基本相同。
內存對象也用來發送控制字,以控制CPLD的開始和停止等。實際上控制字是通過PCI9052發送的。該控制字地址已被映射成PCI的內存空間。所以定義一個指向內存空間的內存對象,通過該對象即可發送控制字。
?。ǎ矗┲袛嗄K
在中斷模塊,首先要激活PCI9052中斷使能位,然后判斷硬件中斷響應是否產生,如果有,則進行突發傳輸,讀入FIFO中的數據。
BOOLEAN TranCard::Isr_MyIrq(void)
{ if (// 中斷未產生)
{……
return FALSE;}
else
{/* 如果產生硬件中斷,設置命令寄存器,進行突發數據傳輸 */
return TRUE;}
}
為了將硬件中斷與編寫的中斷服務程序連接在一起,采用InitializeAndConnect方法,部分代碼如下:
NTSTATUS TranCardDevice?押?押OnStartDevice(KIrp I )
{……
status=m_MyIrq. InitializeAndConnect(
pResListTranlated,
LinkTo(Isr_MyIrq),
This;)
……}
2.4 驅動程序的調用
編寫驅動程序本身不是終目的,終目的是調用驅動程序管理資源,并為用戶應用程序使用。驅動程序加載以后,它的許多進程處于Idle狀態,實際上需要用戶應用程序去調用激活。應用程序利用Win32 API直接調用驅動程序,實現驅動程序和應用程序的信息交互。
首先用CreateFile()打開設備,獲得一個指向設備對象的句柄。使用CreateFile函數時應注意:由于驅動程序是*.sys,所以個參數應該是這個設備對象的標志連接(symbolic link)。該標志連接名有一個設置數據文件搜索路徑的數字號,而這個數字號通常是零。如果這個連接名是″TranCard″,則傳遞給CreateFile的宇符串就是:″\\\\.\\ TranCard0″。例如:
HANDLE hDevice=CreateFile(″\\\\.\\TranCard0″)GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ, NULL?, OPEN_EXISTING,0,NULL);
然后用 DeviceIoControl()進行數據的傳送。用CloseHandle( )關閉設備句柄。
下面是應用DeviceIoControl()程序片段。
{……
m_b=DeviceIoControl(hDevice,TRANCARD_IOCTL_
RECEIVE(buffer, sizeof,buffer, NULL,0,&buffersize,NULL);
……}
2.5 驅動程序的調試
采用SoftICE、DriverMonitor作為調試工具,基本調試過程如下:(1)使用symbol loader加載驅動程序,然后使用SoftICE跟蹤調試,確認驅動程序正常加載;(2)對核心的中斷響應程序代碼,用SoftICE中的Genint命令產生虛擬中斷,單步跟蹤中斷;(3)硬件發送大量的數據,通過查看內存的數據,確認數據傳輸是否正確。
在驅動程序的調試過程中,經常出現系統“死機”、“藍屏”等現象,這些情況可能因內存訪問分頁錯誤、設備資源和系統資源沖突、I/O使用錯誤、程序中“指針”使用錯誤等因素造成。
上述方案均調試通過。使用WDM模式開發驅動程序,程序結構清晰,開發周期較短,效率高。在PCI從模式條件下,大數據量連續傳輸速度可達28Mbps以上。