<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 高速PCI信號采集卡設計與實(shí)現綜合實(shí)例之:PCI卡的驅動(dòng)程序設計

高速PCI信號采集卡設計與實(shí)現綜合實(shí)例之:PCI卡的驅動(dòng)程序設計

作者: 時(shí)間:2017-06-04 來(lái)源:網(wǎng)絡(luò ) 收藏

本文引用地址:http://dyxdggzs.com/article/201706/348786.htm

13.4PCI卡的設計

13.4.1WDM模型

設計完成的信號采集設備在插入計算機后,在對其進(jìn)行控制之前,需要編寫(xiě)基于操作系統平臺上的。設備驅動(dòng)程序是一個(gè)包含了許多操作系統可調用例程的容器,這些例程可以使硬件設備執行相應的動(dòng)作,它是硬件與上層軟件之間溝通的橋梁。

在本案例中,我們針對最常使用的操作系統Windows98/2000/XP系統,使用了WDM(WindowsDriverModel)驅動(dòng)程序模型進(jìn)行程序開(kāi)發(fā)。

WDM模型是從WinNT3.51和WinNT4的內核模式設備驅動(dòng)程序發(fā)展而來(lái)的。WDM主要的變化是增加了對即插即用、電源管理、WindowsManagementInterface(WMI)、設備接口的支持。WDM模型的主要目標是實(shí)現能夠跨平臺使用、更安全、更靈活、編制更簡(jiǎn)單的Windows設備驅動(dòng)程序。

WDM采用了“基于對象”的技術(shù),建立了一個(gè)分層的驅動(dòng)程序結構。通過(guò)WDM模型的引入,可以減輕設備驅動(dòng)程序的開(kāi)發(fā)難度和周期,逐漸規范設備驅動(dòng)程序的開(kāi)發(fā),應該說(shuō),WDM是當前基于Windows平臺的設備驅動(dòng)程序的主流。

WDM模型主要采用分層的方法,模仿面向對象的技術(shù),先進(jìn)行邏輯上的“分層”,然后將標準的實(shí)現和低層細節“封裝”起來(lái),形成“基類(lèi)”,客戶(hù)程序通過(guò)“繼承”的方式來(lái)擴展“基類(lèi)”的功能,完成所需要的實(shí)現。

13.4.2設備和驅動(dòng)程序的層次結構

在WDM模型中,每個(gè)硬件設備至少有兩個(gè)驅動(dòng)程序:一個(gè)功能驅動(dòng)程序(functiondriver)和一個(gè)總線(xiàn)驅動(dòng)程序(busdriver)。

如圖13.14所示為WDM中設備對象和驅動(dòng)程序的層次結構。

圖13.14WDM中設備對象和驅動(dòng)程序的層次結構

1.

是一個(gè)可選項,當一個(gè)用戶(hù)需要改變或新添一些功能到一個(gè)設備、一類(lèi)設備或一種總線(xiàn)時(shí),就可以編寫(xiě)一個(gè)。在設備棧里,過(guò)濾驅動(dòng)程序安裝在一個(gè)或幾個(gè)設備驅動(dòng)程序的上面或下面。

過(guò)濾驅動(dòng)程序攔截對具體設備、類(lèi)設備、總線(xiàn)的請求,做相應的處理,以改變設備的行為或添加新的功能。但過(guò)濾驅動(dòng)程序只處理那些它所關(guān)心的I/O請求,對于其他的請求可以交給其他的驅動(dòng)程序來(lái)處理,這樣可以非常靈活地改變設備的行為。

2.功能驅動(dòng)程序

功能驅動(dòng)程序是物理設備的主要驅動(dòng)程序,它實(shí)現設備的具體功能,一般由設備的生產(chǎn)商來(lái)編寫(xiě)。功能驅動(dòng)程序的主要功能是:提供對設備的操作接口、操作對設備的讀寫(xiě)、管理設備的電源策略等。

功能驅動(dòng)程序由類(lèi)驅動(dòng)程序和微型驅動(dòng)程序組成。類(lèi)驅動(dòng)程序實(shí)現了某一類(lèi)設備的常用操作,驅動(dòng)程序的開(kāi)發(fā)者可以只編寫(xiě)非常小的微型驅動(dòng)程序,去處理具體設備特殊的操作,而對于其他大量的常規操作,可以調用該類(lèi)的類(lèi)驅動(dòng)程序,這也是的優(yōu)點(diǎn)之一。

微軟公司提供的類(lèi)驅動(dòng)程序處理常用的系統任務(wù),比如,即插即用功能和電源管理。類(lèi)驅動(dòng)程序保證了操作系統在處理類(lèi)似的任務(wù)時(shí)的一致性,從而提高了系統的穩定性。

設備生產(chǎn)商提供微型驅動(dòng)程序,以實(shí)現自己設備的特殊功能,同時(shí)調用合適的類(lèi)驅動(dòng)程序完成其他的通用工作。將大量的標準操作的代碼通過(guò)各種類(lèi)驅動(dòng)程序來(lái)實(shí)現,并集成在操作系統中,這樣的方式可以有效地減少具體設備的微型驅動(dòng)程序的大小,也就減小了程序出錯的可能。

如果某一類(lèi)設備存在著(zhù)工業(yè)標準,微軟公司就會(huì )提供一個(gè)該類(lèi)設備的WDM類(lèi)驅動(dòng)程序。這個(gè)類(lèi)驅動(dòng)程序實(shí)現了該類(lèi)設備所有必須的任務(wù),但不實(shí)現任何具體設備所特有的東西。

3.總線(xiàn)驅動(dòng)程序

總線(xiàn)驅動(dòng)程序為實(shí)際的I/O總線(xiàn)服務(wù)。在WDM的定義中,總線(xiàn)是用來(lái)連接其他的物理的、邏輯的、虛擬的設備??偩€(xiàn)包括傳統的總線(xiàn)SCSI和PCI,也包括并口、串口以及i8042端口。微軟公司已經(jīng)為Windows操作系統提供了總線(xiàn)驅動(dòng)程序??偩€(xiàn)驅動(dòng)程序已經(jīng)包含在操作系統里了,用戶(hù)不必安裝。

一個(gè)總線(xiàn)驅動(dòng)程序負責以下的工作:枚舉總線(xiàn)上的設備,向操作系統報告總線(xiàn)上的動(dòng)態(tài)事件,響應即插即用和電源管理的I/O請求,提供總線(xiàn)的多路存取,管理總線(xiàn)上的設備等。

13.4.3PCI設備驅動(dòng)程序例程

PCI設備的一般需要使用WindowsDDK(DriversDevelopKits)及C語(yǔ)言進(jìn)行開(kāi)發(fā)。下面介紹一些PCI設備最常見(jiàn)的例程,這些例程將告訴我們如何對PCI設備進(jìn)行控制。

1.DriverEntry例程

每個(gè),不管它的用途是什么,都要對外界顯示一個(gè)名字為DriverEntry的例程。該例程初始化各種驅動(dòng)程序數據結構,并為所有其他驅動(dòng)程序組件準備好執行環(huán)境。主要的工作是在傳遞的DriverObject中存儲一系列的回調例程指針。DRIVER_OBJECT結構有操作系統用于存儲與驅動(dòng)程序有關(guān)的任何信息。

在DriverEntry例程中通常要完成如下步驟。

·DriverEntry找到它將要控制的硬件。那個(gè)硬件是經(jīng)過(guò)分配的,即被標志為由該驅動(dòng)程序控制。

·通過(guò)聲明另一個(gè)驅動(dòng)程序入口點(diǎn),初始化驅動(dòng)程序對象。通過(guò)把函數指針直接保存到驅動(dòng)程序對象中完成聲明工作。

·如果成功,DriverEntry應該把STATUS_SUCCESS返回給I/O管理程序。

DriverEntry的函數原型為:

NTSTATUSDriverEntry(

PDRIVER_OBJECTpDriverObject,

PUNICODE_STRINGpRegistryPath

)

它接收一個(gè)指向它本身的驅動(dòng)程序對象的指針,DriverEntry例程必須對它(指針)初始化。它還接收一個(gè)UNICODE_STRING,它包含注冊表中驅動(dòng)程序服務(wù)鍵的路徑。內核模式驅動(dòng)程序根據該字符串從系統注冊表中提取任何驅動(dòng)程序專(zhuān)有的參數。注冊表字符串采用如下形式:

HKEY_LOCAL_MACHINESystemCurrentControlSetServicesDriverName

下面是驅動(dòng)程序的DriverEntry例程的部分代碼,里面定義了將要用到的回調函數。

NTSTATUSDriverEntry(

PDRIVER_OBJECTpDriverObject,

PUNICODE_STRINGpRegistryPath

)

{ …

//回調函數

pDriverObject->DriverUnload =DriverUnload;

pDriverObject->MajorFunction[IRP_MJ_CREATE] =Dispatch_Create;

pDriverObject->MajorFunction[IRP_MJ_CLOSE] =Dispatch_Close;

pDriverObject->MajorFunction[IRP_MJ_READ] =Dispatch_Read;

pDriverObject->MajorFunction[IRP_MJ_WRITE] =Dispatch_Write;

pDriverObject->MajorFunction[IRP_MJ_CLEANUP] =Dispatch_Cleanup;

pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]

=Dispatch_IoControl;

pDriverObject->MajorFunction[IRP_MJ_PNP] =Dispatch_Pnp;

pDriverObject->MajorFunction[IRP_MJ_POWER] =Dispatch_Power;

pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]

=Dispatch_System Control;

pDriverObject->DriverExtension->AddDevice =AddDevice;

returnSTATUS_SUCCESS;

}

2.AddDevice例程

大多數的WDMPDO都是在PnP管理器調用該程序入口點(diǎn)時(shí)被創(chuàng )建的。插入新設備后,系統啟動(dòng)時(shí),總線(xiàn)枚舉器會(huì )發(fā)現總線(xiàn)上的所有設備會(huì )自動(dòng)尋找并安裝設備的驅動(dòng)程序,并由驅動(dòng)程序中的處理PnP功能模塊自動(dòng)處理AddDevice例程及其他的PnP消息。

AddDevice例程使用IoCreateDevice函數創(chuàng )建設備對象,再使用IoCreateSymbolicLink函數將設備組成為一個(gè)特定的設備接口,供Win32使用。

其函數原型為:

NTSTATUSAddDevice(PDRIVER_OBJECTpDriverObject,PDEVICE_OBJECTpdo)

必須在DriverEntry入口函數中進(jìn)行聲明,下面是該函數的部分代碼:

NTSTATUSAddDevice(

PDRIVER_OBJECTpDriverObject,

PDEVICE_OBJECTpdo

)

{…

//建立設備名稱(chēng)并創(chuàng )建它

for(i=0;i20;i++)

{

//轉成String格式

Swprintf(DeviceName,L\Device\PLX_DRIVER_NAME_UNICODEL-%d,i);

//初始化DeviceName_Unicode

RtlInitUnicodeString(DeviceName_Unicode,DeviceName);

//創(chuàng )建設備

status=IoCreateDevice(

pDriverObject,

sizeof(DEVICE_EXTENSION),

DeviceName_Unicode,

FILE_DEVICE_UNKNOWN,

0,

FALSE,

fdo

);

//為用戶(hù)應用程序創(chuàng )建Win32關(guān)聯(lián)名

//轉成String格式

swprintf(DeviceLinkName,L\DosDevices\PLX_DRIVER_NAME_UNICODEL-%d,i);

//初始化DeviceLinkName_Unicode

RtlInitUnicodeString(

DeviceLinkName_Unicode,

DeviceLinkName

);

//建立設備關(guān)聯(lián)符號

status=IoCreateSymbolicLink(

DeviceLinkName_Unicode,

DeviceName_Unicode

);

returnSTATUS_SUCCESS;

}

3.DispatchPnp例程

支持即插即用主要是指實(shí)現一個(gè)AddDevice例程和一個(gè)IRP_MJ_PNP處理程序。這個(gè)PnPIRP有8個(gè)主要次功能代碼,大多數的WDM驅動(dòng)程序需要支持這些次功能代碼。

·IRP_MN_START_DEVICE。

·IRP_MN_QUERY_REMOVE_DEVICE。

·IRP_MN_REMOVE_DEVICE。

·IRP_MN_CANCLE_REMOVE_DEVICE。

·IRP_MN_STOP_DEVICE。

·IRP_MN_QUERY_STOP_DEVICE。

·IRP_MN_CANCLE_STOP_DEVICE。

·IRP_MN_QUERY_CAPABILITIES。

還有一些不太常用的IRP,這里就不再一一介紹,下面是這部分驅動(dòng)的部分代碼。

NTSTATUSDispatch_Pnp(

PDEVICE_OBJECTfdo,

PIRPpIrp

)

{ …

//檢查次功能代碼

switch(stack->MinorFunction)

{

caseIRP_MN_START_DEVICE: //配置并初始化設備

status=HandleStartDevice(fdo,pIrp);

break;

caseIRP_MN_STOP_DEVICE: //關(guān)閉設備

status=HandleStopDevice(fdo,pIrp);

break;

caseIRP_MN_REMOVE_DEVICE: //關(guān)閉并刪除設備

Unlock=FALSE;

status=HandleRemoveDevice(fdo,pIrp);

break;

caseIRP_MN_QUERY_REMOVE_DEVICE: //查詢(xún)設備是否可被安全刪除

status=DefaultPnpHandler(fdo,pIrp);

break;

caseIRP_MN_CANCEL_REMOVE_DEVICE: //忽略以前的QUERY_REMOVE

status=DefaultPnpHandler(fdo,pIrp);

break;

caseIRP_MN_QUERY_STOP_DEVICE: //查詢(xún)設備是否可被安全關(guān)閉

status=DefaultPnpHandler(fdo,pIrp);

break;

caseIRP_MN_CANCEL_STOP_DEVICE: //忽略以前的QUERY_STOP

status=DefaultPnpHandler(fdo,pIrp);

break;

caseIRP_MN_QUERY_CAPABILITIES: //取設備能力

status=DefaultPnpHandler(fdo,pIrp);

break;

…}

returnstatus;

}

這些功能代碼函數都在DriverEntry()入口函數中進(jìn)行了聲明。

4.DispatchPower例程

WDM設備驅動(dòng)程序支持電源管理,一個(gè)設備可以改變它的電源使用來(lái)響應系統電源狀態(tài)變化,且在處于空閑狀態(tài)時(shí)可以減少它自己的電源使用。一個(gè)休眠的設備可以喚醒系統,如當調制解調器收到到達的呼叫時(shí)。

驅動(dòng)程序的電源管理例程圍繞電源IRP_MJ_POWERIRP進(jìn)行處理,這些例程處理這個(gè)IRP,并在需要時(shí)產(chǎn)生這個(gè)IRP。這個(gè)IRP有4個(gè)電源管理次功能代碼。

·IRP_MN_WAIT_WAKE。

·IRP_MN_POWER_SEQUENCE。

·IRP_MN_SET_POWER。

·IRP_MN_QUERY_POWER。

這部分的代碼如下:

NTSTATUSDispatch_Power(

PDEVICE_OBJECTfdo,

PIRPpIrp

)

{

NTSTATUSstatus;

PIO_STACK_LOCATIONstack;

//獲取指向被調用的Irp的棧位置的指針

stack=IoGetCurrentIrpStackLocation(pIrp);

switch(stack->MinorFunction)

{

caseIRP_MN_WAIT_WAKE: //喚醒計算機,響應一個(gè)外部事件

status=DefaultPowerHandler(fdo,pIrp);

break;

caseIRP_MN_POWER_SEQUENCE: //確定設備是否真正進(jìn)入特定的電源狀態(tài)

status=DefaultPowerHandler(fdo,pIrp);

break;

caseIRP_MN_SET_POWER: //設置系統或設備電源狀態(tài)

status=HandleSetPower(fdo,pIrp);

break;

caseIRP_MN_QUERY_POWER: //查詢(xún)系統或設備狀態(tài)變化是否可行

status=HandleQueryPower(fdo,pIrp);

break;

default: //確定設備是否真正進(jìn)入特定的電源狀態(tài)

status=DefaultPowerHandler(fdo,pIrp);

break;

}

returnstatus;

}

5.Unload例程

在默認情況下,驅動(dòng)程序裝入之后,在重新引導之前就一直保持在系統中。要使系統可卸載,必須有一個(gè)Unload例程。Uload例程在DriverEntry期間聲明,然后,每當驅動(dòng)程序被手動(dòng)或自動(dòng)卸載時(shí),I/O管理程序就調用該例程。

該例程函數原型為:

VOIDUnload(PDRIVER_OBJECTpDriverObject)

通常一個(gè)Uload例程執行如下工作。

·對于某些種類(lèi)的硬件,設備狀態(tài)應當保存在注冊表中。那樣,在DriverEntry下一次執行時(shí),設備能夠恢復到最近已知的狀態(tài)。

·如果啟動(dòng)了設備中斷,Unload例程必須僅用它們,并斷開(kāi)它們與中斷對象的連接。

·必須釋放屬于驅動(dòng)程式的硬件。

·必須從Win32名字空間中刪除符號鏈接名字,這可以用IoDeleteSymbolicLink完成。

·必須用IoDeleteDevice刪除設備對象自身。

·釋放驅動(dòng)程序占據的任何池內存。

驅動(dòng)中的部分代碼如下:

VOIDDriverUnload(PDRIVER_OBJECTpDriverObject)

{

//釋放公共緩沖區

if(Gbl_CommonBuffer.PciMem.PhysicalAddr!=(U32)NULL)

{

//釋放內存描述列表(MDL)

if(Gbl_CommonBuffer.pMdl!=NULL)

{

IoFreeMdl(Gbl_CommonBuffer.pMdl);

Gbl_CommonBuffer.pMdl=NULL;

}

//釋放公共緩沖區

if(Gbl_CommonBuffer.pKernelVa!=NULL)

{

MmFreeContiguousMemory(Gbl_CommonBuffer.pKernelVa);

Gbl_CommonBuffer.pKernelVa=NULL;

}

}

//釋放DMA使用的緩沖區

#ifdefined(DMA_SUPPORT)

DriverBufferTerminate();

#endif

}

6.Dispatch例程

驅動(dòng)程序裝載是第一步工作,但是最終驅動(dòng)程序的作業(yè)是響應I/O請求——來(lái)自用戶(hù)模式應用程序的請求或者來(lái)自系統其他地方的請求。Windows2000驅動(dòng)程序通過(guò)Dispatch例程來(lái)處理這些請求。I/O管理程序調用這些例程以響應請求。

要啟用特定的I/O函數代碼,驅動(dòng)函數必須首先“聲明”響應這樣一個(gè)請求的Dispatch例程。聲明機制是DriverEntry執行的工作,它把Dispatch例程函數地址保存在驅動(dòng)程序對象的MajorFunction表的合適位置上。

I/O函數代碼是用于表的索引。其中,每個(gè)I/O函數代碼(表索引)由一個(gè)IRP_MJ_XXX形式的惟一符號標示,在NTDDK.h(或WDM.h)包含文件中定義。

所有驅動(dòng)程序必須支持函數代碼IRP_MJ_CREATE,因為編寫(xiě)此代碼的目的是響應Win32CreateFile調用。如果不支持該代碼,Win32應用程序將無(wú)法獲取設備的句柄。同樣也必須支持IRP_MJ_CLOSE,以處理Win32CloserHandle調用。

驅動(dòng)程序應當支持的其他函數代碼取決它控制的設備的本質(zhì)。表13.3將用到的I/O函數代碼與產(chǎn)生它們的Win32調用相關(guān)聯(lián)。

表13.3 Dispatch例程表

Win32函數

IRP主功能代碼

驅動(dòng)程序例程的名稱(chēng)

說(shuō)明

CreateFile

IRP_MJ_CREATE

Dispatch_Create

請求一個(gè)句柄

CloseHandle

IRP_MJ_CLEANUP

Dispatch_Cleanup

關(guān)閉句柄

CloseHandle

IRP_MJ_CLOSE

Dispatch_Close

取消掛起的IRP

ReadFile

IRP_MJ_READ

Dispatch_Read

從設備獲取數據

WriteFile

IRP_MJ_WRITE

Dispatch_Write

將數據發(fā)送到設備

DeviceIoControl

IRP_MJ_DEVICE_CONTROL

Dispatch_IoControl

控制操作



評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>