国产久操视频-国产久草视频-国产久热精品-国产久热香蕉在线观看-青青青青娱乐-青青青青在线成人视99

  • 正文
    • 13.4  PCI卡的驅動程序設計
  • 相關推薦
申請入駐 產(chǎn)業(yè)圖譜

高速PCI信號采集卡設計與實現(xiàn)綜合實例之:PCI卡的驅動程序設計

2013/08/30
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

?

13.4??PCI卡的驅動程序設計

13.4.1??WDM驅動程序模型

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

在本案例中,我們針對最常使用的操作系統(tǒng)Windows?98/2000/XP系統(tǒng),使用了WDM(Windows?Driver?Model)驅動程序模型進行程序開發(fā)。

WDM模型是從WinNT?3.51和WinNT?4的內核模式設備驅動程序發(fā)展而來的。WDM主要的變化是增加了對即插即用、電源管理、Windows?Management?Interface(WMI)、設備接口的支持。WDM模型的主要目標是實現(xiàn)能夠跨平臺使用、更安全、更靈活、編制更簡單的Windows設備驅動程序。

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

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

13.4.2??設備和驅動程序的層次結構

在WDM模型中,每個硬件設備至少有兩個驅動程序:一個功能驅動程序(function?driver)和一個總線驅動程序(bus?driver)。

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

圖13.14??WDM中設備對象和驅動程序的層次結構

?

1.過濾驅動程序

過濾驅動程序是一個可選項,當一個用戶需要改變或新添一些功能到一個設備、一類設備或一種總線時,就可以編寫一個過濾驅動程序。在設備棧里,過濾驅動程序安裝在一個或幾個設備驅動程序的上面或下面。

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

2.功能驅動程序

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

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

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

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

如果某一類設備存在著工業(yè)標準,微軟公司就會提供一個該類設備的WDM類驅動程序。這個類驅動程序實現(xiàn)了該類設備所有必須的任務,但不實現(xiàn)任何具體設備所特有的東西。

3.總線驅動程序

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

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

?

13.4.3??PCI設備驅動程序例程

PCI設備的WDM驅動程序一般需要使用Windows?DDK(Drivers?Develop?Kits)及C語言進行開發(fā)。下面介紹一些PCI設備最常見的例程,這些例程將告訴我們如何對PCI設備進行控制。

1.DriverEntry例程

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

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

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

·??通過聲明另一個驅動程序入口點,初始化驅動程序對象。通過把函數(shù)指針直接保存到驅動程序對象中完成聲明工作。

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

DriverEntry的函數(shù)原型為:

NTSTATUS?DriverEntry?(

PDRIVER_OBJECT?pDriverObject,?

PUNICODE_STRING?pRegistryPath

)

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

HKEY_LOCAL_MACHINESystemCurrentControlSetServicesDriverName

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

NTSTATUS?DriverEntry?(

????PDRIVER_OBJECT???pDriverObject,

????PUNICODE_STRING???pRegistryPath

????)

{ …

????//?回調函數(shù)

????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;

????…

????return?STATUS_SUCCESS;

}

?

2.AddDevice例程

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

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

其函數(shù)原型為:

NTSTATUS?AddDevice?(PDRIVER_OBJECT?pDriverObject,?PDEVICE_OBJECT?pdo)

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

NTSTATUS?AddDevice?(

????PDRIVER_OBJECT?pDriverObject,

????PDEVICE_OBJECT?pdo

????)

{…

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

????for?(i=0;?i?<?20;?i++)

????{

????//轉成String格式

????????Swprintf?(DeviceName,?L"\Device\"?PLX_DRIVER_NAME_UNICODE?L"-%d",?i);

????//初始化DeviceName_Unicode

????????RtlInitUnicodeString?(&DeviceName_Unicode,?DeviceName);

????//?創(chuàng)建設備

????????status?=?IoCreateDevice(

????????????????pDriverObject,

????????????????sizeof(DEVICE_EXTENSION),

????????????????&DeviceName_Unicode,

????????????????FILE_DEVICE_UNKNOWN,

????????????????0,

????????????????FALSE,?

????????????????&fdo

????????????????);

????…

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

????//轉成String格式

????swprintf?(DeviceLinkName,?L"\DosDevices\"?PLX_DRIVER_NAME_UNICODE?L"-%d",?i);

????//初始化DeviceLinkName_Unicode

????RtlInitUnicodeString?(

????????&DeviceLinkName_Unicode,

????????DeviceLinkName

????????);

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

????status?=?IoCreateSymbolicLink?(

????????????&DeviceLinkName_Unicode,

????????????&DeviceName_Unicode

????????????);

????…

????return?STATUS_SUCCESS;

}

3.DispatchPnp例程

支持即插即用主要是指實現(xiàn)一個AddDevice例程和一個IRP_MJ_PNP處理程序。這個PnP?IRP有8個主要次功能代碼,大多數(shù)的WDM驅動程序需要支持這些次功能代碼。

·??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,這里就不再一一介紹,下面是這部分驅動的部分代碼。

NTSTATUS?Dispatch_Pnp(

????PDEVICE_OBJECT?fdo,

????PIRP???????????pIrp

????)

{ …

????//?檢查次功能代碼

????switch?(stack?->?MinorFunction)

????{

????????case?IRP_MN_START_DEVICE:????????????????????? //配置并初始化設備

????????????status?=?HandleStartDevice(fdo,?pIrp);

????????????break;

????????case?IRP_MN_STOP_DEVICE: ????????????????????? //關閉設備

????????????status?=?HandleStopDevice(fdo,?pIrp);

????????????break;

????????case?IRP_MN_REMOVE_DEVICE:????????????????? //關閉并刪除設備

????????????Unlock?=?FALSE;

????????????status?=?HandleRemoveDevice(fdo,?pIrp);

????????????break;

????????case?IRP_MN_QUERY_REMOVE_DEVICE: ??????????? //查詢設備是否可被安全刪除

????????????status?=?DefaultPnpHandler(fdo,?pIrp);

????????????break;

????????case?IRP_MN_CANCEL_REMOVE_DEVICE:?????????? //忽略以前的QUERY_REMOVE

????????????status?=?DefaultPnpHandler(fdo,?pIrp);

????????????break;

????????case?IRP_MN_QUERY_STOP_DEVICE:?????????????? //查詢設備是否可被安全關閉

????????????status?=?DefaultPnpHandler(fdo,?pIrp);

????????????break;

????????case?IRP_MN_CANCEL_STOP_DEVICE:???????????? //忽略以前的QUERY_STOP

????????????status?=?DefaultPnpHandler(fdo,?pIrp);

????????????break;

????????case?IRP_MN_QUERY_CAPABILITIES:???????????? //取設備能力

????????????status?=?DefaultPnpHandler(fdo,?pIrp);

????????????break;

????…?}

????return?status;

}

這些功能代碼函數(shù)都在DriverEntry()入口函數(shù)中進行了聲明。?

?

4.DispatchPower例程

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

驅動程序的電源管理例程圍繞電源IRP_MJ_POWER?IRP?進行處理,這些例程處理這個IRP,并在需要時產(chǎn)生這個IRP。這個IRP有4個電源管理次功能代碼。

·??IRP_MN_WAIT_WAKE。

·??IRP_MN_POWER_SEQUENCE。

·??IRP_MN_SET_POWER。

·??IRP_MN_QUERY_POWER。

這部分的代碼如下:

NTSTATUS?Dispatch_Power(

????PDEVICE_OBJECT?fdo,

????PIRP???????????pIrp

????)

{

????NTSTATUS???????????status;

????PIO_STACK_LOCATION?stack;

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

????stack?=?IoGetCurrentIrpStackLocation(pIrp);

????switch?(stack->MinorFunction)

????{

????????case?IRP_MN_WAIT_WAKE:??????????????? //喚醒計算機,響應一個外部事件

????????????status?=?DefaultPowerHandler(fdo,?pIrp);

????????????break;

????????case?IRP_MN_POWER_SEQUENCE:????????? //確定設備是否真正進入特定的電源狀態(tài)

????????????status?=?DefaultPowerHandler(fdo,?pIrp);

????????????break;

????????case?IRP_MN_SET_POWER:??????????????? //設置系統(tǒng)或設備電源狀態(tài)

????????????status?=?HandleSetPower(fdo,?pIrp);

????????????break;

????????case?IRP_MN_QUERY_POWER:???????????? //查詢系統(tǒng)或設備狀態(tài)變化是否可行

????????????status?=?HandleQueryPower(fdo,?pIrp);

????????????break;

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

????????????status?=?DefaultPowerHandler(fdo,?pIrp);

????????????break;

????}

????return?status;

}

5.Unload例程

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

該例程函數(shù)原型為:

VOID?Unload?(?PDRIVER_OBJECT?pDriverObject?)

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

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

·??如果啟動了設備中斷,Unload例程必須僅用它們,并斷開它們與中斷對象的連接。

·??必須釋放屬于驅動程式的硬件。

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

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

·??釋放驅動程序占據(jù)的任何池內存。

驅動中的部分代碼如下:

VOID?DriverUnload(PDRIVER_OBJECT?pDriverObject)

{

????//?釋放公共緩沖區(qū)

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

????{

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

????????if?(Gbl_CommonBuffer.pMdl?!=?NULL)

????????{

????????????IoFreeMdl(Gbl_CommonBuffer.pMdl);

????????????Gbl_CommonBuffer.pMdl?=?NULL;

????????}

????????//?釋放公共緩沖區(qū)

????????if?(Gbl_CommonBuffer.pKernelVa?!=?NULL)

????????{

????????????MmFreeContiguousMemory(Gbl_CommonBuffer.pKernelVa);

????????????Gbl_CommonBuffer.pKernelVa?=?NULL;

????????}

????}

//釋放DMA使用的緩沖區(qū)

#if?defined(DMA_SUPPORT)

????DriverBufferTerminate();

#endif

}

?

6.Dispatch例程

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

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

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

所有驅動程序必須支持函數(shù)代碼IRP_MJ_CREATE,因為編寫此代碼的目的是響應Win32?CreateFile調用。如果不支持該代碼,Win32應用程序將無法獲取設備的句柄。同樣也必須支持IRP_MJ_CLOSE,以處理Win32?CloserHandle調用。

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

表13.3 Dispatch例程表

Win32函數(shù)

IRP主功能代碼

驅動程序例程的名稱

說????明

CreateFile

IRP_MJ_CREATE

Dispatch_Create

請求一個句柄

CloseHandle

IRP_MJ_CLEANUP

Dispatch_Cleanup

關閉句柄

CloseHandle

IRP_MJ_CLOSE

Dispatch_Close

取消掛起的IRP

ReadFile

IRP_MJ_READ

Dispatch_Read

從設備獲取數(shù)據(jù)

WriteFile

IRP_MJ_WRITE

Dispatch_Write

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

DeviceIoControl

IRP_MJ_DEVICE_CONTROL

Dispatch_IoControl

控制操作

相關推薦

登錄即可解鎖
  • 海量技術文章
  • 設計資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

華清遠見(www.farsight.com.cn)是國內領先嵌入師培訓機構,2004年注冊于中國北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營分公司。華清遠見除提供嵌入式相關的長期就業(yè)培訓、短期高端培訓、師資培訓及企業(yè)員工內訓等業(yè)務外,其下屬研發(fā)中心還負責嵌入式、Android及物聯(lián)網(wǎng)方向的教學實驗平臺的研發(fā)及培訓教材的出版,截止目前為止已公開出版70余本嵌入式/移動開發(fā)/物聯(lián)網(wǎng)相關圖書。企業(yè)理念:專業(yè)始于專注 卓識源于遠見。企業(yè)價值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。

西充县| 普宁市| 稻城县| 缙云县| 达孜县| 彰化县| 治县。| 凌云县| 郓城县| 莱芜市| 香港| 蒙城县| 南宁市| 西和县| 徐州市| 泾阳县| 金华市| 石台县| 龙口市| 星座| 金华市| 嘉定区| 乌拉特后旗| 左贡县| 玉树县| 南郑县| 中方县| 商丘市| 平昌县| 中宁县| 漳州市| 丹寨县| 垦利县| 西盟| 阜城县| 建平县| 怀来县| 九龙坡区| 磴口县| 雷波县| 南通市|