八、 Windows 驅(qū)動(dòng)程序模型
Windows 環(huán)境下驅(qū)動(dòng)程序共有三類,一類是 VxD ( Virtual Device Driver ,虛擬設(shè)備驅(qū)動(dòng)程序),起源于 Windows 3.1 時(shí)代,用于 Windows 95/98/Me 操作系統(tǒng)中;一類是 KMD ( Kernel Mode Driver ,內(nèi)核模式驅(qū)動(dòng)程序),用于 Windows NT 下;還有一類就是 WDM ( Win32 Driver Mode , Win32 驅(qū)動(dòng)程序模型),是微軟從 Windows 98 開始,推出的一個(gè)新的驅(qū)動(dòng)類型,它是一個(gè)跨平臺(tái)的驅(qū)動(dòng)程序模型,不僅如此 WDM 驅(qū)動(dòng)程序還可以在不修改源代碼的情況下經(jīng)過重新編譯后在非 Intel 平臺(tái)上運(yùn)行,毫不夸張地講, WDM 算得上是 21 世紀(jì)的驅(qū)動(dòng)程序框架。
WMD 驅(qū)動(dòng)程序模型
應(yīng)用程序通過 API 函數(shù)調(diào)用 Win32 系統(tǒng)子函數(shù),驅(qū)動(dòng)程序分為設(shè)備驅(qū)動(dòng)程序,總線驅(qū)動(dòng)程序 (USBD) 和主控制器驅(qū)動(dòng)程序 (HCD) 三層,它們均運(yùn)行在系統(tǒng)的內(nèi)核模式。設(shè)備驅(qū)動(dòng)程序使用 IR P(I / ORequest Packet) 通過總線驅(qū)動(dòng)程序提供的軟件接口 (USBDI , USB Driver Interface) 向總線驅(qū)動(dòng)程序發(fā)出 I / O 請(qǐng)求,并根據(jù)數(shù)據(jù)傳輸方向提供一個(gè)或空或滿的 內(nèi)存 緩沖區(qū); USBD 負(fù)責(zé)管理數(shù)據(jù)的總線傳輸,也有設(shè)備驅(qū)動(dòng)程序與其他軟件接口的功能單元進(jìn)行通信,沒有直接調(diào)用 USBD ,但總有一個(gè)更低層的驅(qū)動(dòng)軟件發(fā)生 USBD 調(diào)用。主控制器驅(qū)動(dòng)程序處在 USB 系統(tǒng)軟件的最底層,直接與主控制器的硬件通信,它提供了只有總線驅(qū)動(dòng)程序才能訪問的主控制器驅(qū)動(dòng)程序軟件接口 H CDI (Host C ON TROL Driver Interface) 。其中,總線驅(qū)動(dòng)程序和主控制器驅(qū)動(dòng)程序是系統(tǒng)的底層驅(qū)動(dòng)程序。設(shè)備驅(qū)動(dòng)程序是針對(duì)某一 USB 設(shè)備的專用驅(qū)動(dòng)程序。
Windows 為 USB 設(shè)備提供了底層驅(qū)動(dòng)程序,與底層驅(qū)動(dòng)程序接口的是 I / O 請(qǐng)求包 (IRP) , Windows 為應(yīng)用程序提供的接口則是 API 函數(shù)。因此必須在它們之間建立一個(gè)驅(qū)動(dòng)程序,在底層驅(qū)動(dòng)與 Win32 應(yīng)用程序之間傳遞消息,即設(shè)備驅(qū)動(dòng)程序。 VC++ 、 VB 等軟件開發(fā)的應(yīng)用程序,在設(shè)備驅(qū)動(dòng)程序的支持下,都可以調(diào)用 ReadFile() 、 WriteFile() 、 DeviceIo CONTROL () 等 API 函數(shù)向設(shè)備傳遞主機(jī)請(qǐng)求。 Windows 系統(tǒng)自動(dòng)將 API 調(diào)用轉(zhuǎn)化為 IRP ,設(shè)備驅(qū)動(dòng)程序把它向下層驅(qū)動(dòng)傳遞。直到完成其所指定的功能再沿驅(qū)動(dòng)程序棧返回主機(jī)。
WDM 還引入了功能設(shè)備對(duì)象 FDO ( Functional Device Object )與物理設(shè)備對(duì)象 PDO ( Physical Device Object )兩個(gè)新類來描述硬件,一個(gè) PDO 對(duì)應(yīng)一個(gè)真實(shí)硬件。一個(gè)硬件只允許有一個(gè) PDO ,但卻可以擁有多個(gè) FDO ,而在驅(qū)動(dòng)程序中我們不是直接操作硬件而是操作相應(yīng)的 PDO 與 FDO 。驅(qū)動(dòng)程序和設(shè)備對(duì)象的分層情況如圖所示。
其中總線驅(qū)動(dòng)程序( Bus Driver )位于最底層,控制對(duì)總線上所有設(shè)備的訪問,創(chuàng)建 PDO 代表發(fā)現(xiàn)的設(shè)備。功能驅(qū)動(dòng)程序( Function Driver )控制設(shè)備的主要功能,分層在總線驅(qū)動(dòng)的上面,負(fù)責(zé)創(chuàng)建 FDO 。在 USB 情況下,功能驅(qū)動(dòng)程序必須使用 USB 類驅(qū)動(dòng)程序訪問設(shè)備。
九、 USB 設(shè)備驅(qū)動(dòng)程序開發(fā)工具
開發(fā) USB 設(shè)備驅(qū)動(dòng)程序需要專門的開發(fā)工具,目前應(yīng)用廣泛的工具主要有兩大類。 開發(fā)設(shè)備驅(qū)動(dòng)程序一般采用以下幾種方法: 1) 直接使用 Windows DDK ,這種方法開發(fā)難度較大,設(shè)計(jì)者必須對(duì)整個(gè)體系結(jié)構(gòu)有很好的理解和把握。 2) 使用 Driver Studio ,該 工具 軟件可為設(shè)計(jì)者提供驅(qū)動(dòng)程序的整體框架,設(shè)計(jì)者只需要專心于功能代碼設(shè)計(jì)。 3) 使用 win Driver ,這種方法開發(fā)驅(qū)動(dòng)程序很容易,但工作效率不是很高。
1. Microsoft 公司提供的 Windows DDK(Device Driver Kit) 。
它有 Windows 98 DDK 和 Windows 2000 DDK 兩個(gè)版本。 Windows 98 DDK 能夠開發(fā) Windows 95/98/Me/NT 下的 VxD 、 KMD 和 WDM 驅(qū)動(dòng)程序。 Windows 2000 DDK 能夠開發(fā) Windows 98/Me/NT/2000 下的 KMD 和 WDM 驅(qū)動(dòng)程序。由于 DDK 基于匯編語言的編程方式和內(nèi)核模式的調(diào)用,對(duì)沒有深厚的 OS 原理和編程水平的人員來說,任務(wù)相當(dāng)艱巨。
2. NuMega 公司提供的 DriverStudio 。
它是一個(gè)大的開發(fā)工具包,包含 VtoolsD 、 SoftICE 和 DriverWorks 等開發(fā)工具。 VtoolsD 開發(fā)包提供了對(duì) VxD 編程的 C/C++ 類庫支持,利用 VtoolsD 中的 QuickVxD 工具可以快速生成 VxD 的 C/C++ 代碼框架,開發(fā)者可以在此基礎(chǔ)上根據(jù)各自的需要添加自己的代碼。 DriverWorks 用于開發(fā) KMD 和 WDM 驅(qū)動(dòng)程序,并且對(duì) DDK 函數(shù)進(jìn)行了類的封裝,從而為開發(fā) Windows NT 、 Windows 2000 和 Widnwos98 WDM 設(shè)備驅(qū)動(dòng)程序提供了一個(gè)自動(dòng)化的方法。
DriverWorks ,提供了 VC++ 下的開發(fā)向?qū)? Driver Wizard ,按照它的提示可以迅速地生成驅(qū)動(dòng)程序的框架。這個(gè)框架結(jié)構(gòu)提供可以正確執(zhí)行 WDM 動(dòng)態(tài)環(huán)境中 IRP 的請(qǐng)求,而且,也包含用于簡(jiǎn)化系統(tǒng)提供的標(biāo)準(zhǔn)類驅(qū)動(dòng)程序(如 HID 、流)和總線驅(qū)動(dòng)程序(如 PCI 和 USB )接口的類等。 總之,利用 DriverWorks 開發(fā) WDM 驅(qū)動(dòng)程序,可以大大簡(jiǎn)化開發(fā)人員的工作量、縮短開發(fā)周期以及降低開發(fā)驅(qū)動(dòng)程序的難度。
十、 USB 設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)
使用 DriverStudio3.2 開發(fā) USB 設(shè)備驅(qū)動(dòng)程序。
該驅(qū)動(dòng)程序的主要功能包括:從控制端點(diǎn) 0 讀取規(guī)定個(gè)數(shù)的數(shù)據(jù)、向端點(diǎn) 0 發(fā)出控制命令、從端點(diǎn) 2 批量讀數(shù)據(jù)、向端點(diǎn) 2 批量寫數(shù)據(jù),驅(qū)動(dòng)程序的開發(fā)采用 DriverStudio3.2 驅(qū)動(dòng)程序開發(fā)包及 VC++6.0 ,使用開發(fā)包中的向?qū)С绦? DriverWizard 就可以方便的生成驅(qū)動(dòng)程序框架、模塊及部分程序源代碼,開發(fā)者只需要在功能模塊中加入自己的實(shí)現(xiàn)程序就能完成復(fù)雜的 USB 設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)。
1. DriverWizard 生成一 ISP1581 驅(qū)動(dòng)程序的過程:
(1) 啟動(dòng) DriverWizard ,選擇 DriverWorks Project 創(chuàng)造一個(gè)名為 USBDIO 的 VC++ 項(xiàng)目 ;
(2) 在驅(qū)動(dòng)程序類型中選擇 WDM Driver , WDM Function Driver, 在硬件設(shè)備所支持的總線類型中選擇 USB(WDM Only) ,在 USB Vendor ID( 廠商識(shí)別碼 ) 中填寫 0741 ,在 USB Product ID( 產(chǎn)品識(shí)別碼 ) 中填寫 0821;
(3) 增加 USB 設(shè)備端點(diǎn),設(shè)置端點(diǎn) 2 為批量輸入 / 輸出傳輸方式 ;
(4) 在驅(qū)動(dòng)程序支持的功能項(xiàng)中選擇 Read 、 Write 、 Device Control 、 Cleanup;
(5) 選擇自動(dòng)產(chǎn)生批量讀及批量寫程序代碼 ;
(6) 在 I/O 請(qǐng)求 IRP 處理方式中選擇 None ,即 IRP 不排隊(duì) ;
(7) 在接口的打開方式中選擇 Symbolic link:UsbdioDevice ,即應(yīng)用程序以符號(hào)鏈接名打開設(shè)備 ;
(8) 定義應(yīng)用程序調(diào)用 DeviceIo Control 函數(shù)對(duì) WDM 驅(qū)動(dòng)程序通信的控制命令。
(9) 最后選擇完成并確認(rèn)生成新的項(xiàng)目信息,向?qū)С绦蚓蜁?huì)在 usbdio 目錄中生成一個(gè)名為 USBDIO 的項(xiàng)目文件,其中包括了 ISP1581 驅(qū)動(dòng)程序框架、模塊及部分源代碼。
2 . USB 設(shè)備驅(qū)動(dòng)程序的編程
在使用 DriverWizard 生成驅(qū)動(dòng)程序框架、模塊及部分程序源代碼后,開發(fā)者只需完成三個(gè)控制代碼所對(duì)應(yīng)的三個(gè)功能模塊的編程:模塊 USBDIO_IOCTL_ ID_CODE_Handler 的功能是從控制端點(diǎn) 0 讀取數(shù)據(jù),模塊 USBDIO_IOCTL_ TEST_COMMAND_Handler 的功能是向控制端點(diǎn) 0 發(fā)送一個(gè)控制命令,模塊 USBDIO_IOCTL_DMA_COMMAND _Handler 的功能是向控制端點(diǎn) 0 發(fā)送一個(gè)要求 USB 設(shè)備進(jìn)行 DMA 傳輸?shù)目刂泼睿旅媸堑谝粋€(gè)模塊的編程實(shí)例。
NTSTATUS USBDIODevice::USBDIO_IOCTL_ID_CODE_Handler(KIrp I)
{
NTSTATUS status =STATUS_SUCCESS;
t << "Entering USBDIODevice::USBDIO _IOCTL_ID_ CODE_Handler, " << I << EOL;
PURB pUrb;
ULONG numData;
numData=*(PUCHAR)I.IoctlBuffer();
// 設(shè)置讀取的數(shù)據(jù)個(gè)數(shù)
pUrb=m_Lower.BuildVendorRequest((PUCHAR)I.IoctlBuffer(),// 驅(qū)動(dòng)程序存放讀取的數(shù)據(jù)的內(nèi)存區(qū)
numData,//wLength ,讀取的數(shù)據(jù)個(gè)數(shù)
0,0x0c,//bRequest 0,//wValue
TRUE,//input
TRUE,
NULL,
0x0472,//wIndex, 傳輸?shù)焦碳绦虻淖x數(shù)命令碼
URB_FUNCTION_VENDOR_ENDPOINT,
NULL);
if(pUrb==NULL)
{
I.Information() =0;
status=STATUS_INSUFFICIENT_
RESOURCES;
}
else
{
I.Information() =numData;
tatus=m_Lower.SubmitUrb(pUrb,NULL,NULL,0);
delete pUrb;
}
return status;
}
對(duì)象 I 包含了應(yīng)用程序下傳的 IRP 內(nèi)容,包括命令或數(shù)據(jù)等參數(shù),函數(shù) BuildVendorRequest 用來分配并初始化一個(gè)用于廠商請(qǐng)求的 URB(USB Request Block) ,該 URB 將作為下傳 IRP 的一個(gè)參數(shù),通過函數(shù) SubmitUrb 發(fā)送給總線驅(qū)動(dòng)程序,以便完成與硬件的通信。
在初始化 URB 時(shí)需要了解 USB 的傳輸方式及傳輸協(xié)議,該功能使用了 USB 的控制傳輸方式,該方式包括三個(gè)階段:設(shè)置階段、數(shù)據(jù)階段和狀態(tài)階段,其中數(shù)據(jù)階段可選,開發(fā)者主要關(guān)注設(shè)置階段中的 8 個(gè)關(guān)鍵字節(jié)的定義, 8 字節(jié)分成了 5 個(gè)字段,定義了傳輸請(qǐng)求及相關(guān)信息。
BmRequestType : 1 字節(jié),用來指定數(shù)據(jù)流動(dòng)的方向,請(qǐng)求的類型,以及接收者。
bRequest : 1 字節(jié),用來指定請(qǐng)求。
wValue : 2 字節(jié),主機(jī)用來傳輸信息給設(shè)備,開發(fā)者可以根據(jù)情況自己定義。
wIndex : 2 字節(jié),主機(jī)用來傳輸信息給設(shè)備,開發(fā)者可以根據(jù)情況自己定義。
wLength : 2 字節(jié),包含數(shù)據(jù)階段中接下來要傳輸?shù)臄?shù)據(jù)字節(jié)數(shù)目。
十一、 USB 設(shè)備驅(qū)動(dòng)程序的安裝及調(diào)用
1. USB 設(shè)備驅(qū)動(dòng)程序的安裝
驅(qū)動(dòng)程序編譯完成后會(huì)生成一個(gè)名為 USBDIO.SYS 的文件,即 USB 設(shè)備驅(qū)動(dòng)程序,另外在使用向?qū)С绦? WizardDriver 生成驅(qū)動(dòng)程序時(shí)會(huì)產(chǎn)生一個(gè)名為 USBDIO.INF 的驅(qū)動(dòng)程序安裝程序,對(duì)此程序只需稍做修改就能正常使用,具體是將類改為 USB ,即 Class=USB ,由于本驅(qū)動(dòng)程序使用符號(hào)鏈接名打開設(shè)備,所以刪除 ClassGUID 選項(xiàng),注意設(shè)備標(biāo)識(shí)符必需為: %DeviceDesc%=USBDIO_DDI, USBVID_0471&PID_0821 ,其中 0471 是 USB 控制芯片的廠商識(shí)別碼, 0821 是 USB 設(shè)備標(biāo)識(shí)碼。
驅(qū)動(dòng)程序安裝過程是:將 USB 設(shè)備加電,連入計(jì)算機(jī)的 USB 接口,這時(shí)候會(huì)看到 Windows 操作系統(tǒng)提示發(fā)現(xiàn)新硬件,提問是否安裝驅(qū)動(dòng)程序,選擇是,然后選擇驅(qū)動(dòng)程序所在文件夾,選擇文件 USBDIO.INF 即可完成安裝 .
2. USB 設(shè)備驅(qū)動(dòng)程序的調(diào)用
為了完成對(duì)驅(qū)動(dòng)程序的調(diào)用,使用 VC++6.0 編寫 USB 應(yīng)用程序包,程序包共由五個(gè)功能模塊組成,用戶通過調(diào)用這些模塊即可方便的完成對(duì) USB 外設(shè)的控制及讀寫,這些模塊如下。
int CTRLReadData(unsigned char usbSelect , unsigned char *rbuffer , unsigned char numData) ,主要功能是讀取 ISP1581 控制端點(diǎn) 0 發(fā)來的數(shù)據(jù),數(shù)據(jù)存放在緩沖區(qū) rbuffer 中。
int CTRLSendTestCommand (unsigned char usbSelect , unsigned short int testCommand) ,主要功能是發(fā)送測(cè)試命令,變量 testCommand 定義了測(cè)試命令。
int CTRLSendDMACommand (unsigned char usbSelect , unsigned char dmaDirection , unsigned char ramSelect,unsigned long dmaLength) ,主要功能是發(fā)送 DMA 傳輸命令,變量 dmaDirection 定義數(shù)據(jù)傳輸方向, ramSelect 定義將要操作的 USB 外設(shè)的存儲(chǔ)器, dmaLength 定義了數(shù)據(jù)傳輸總數(shù)。
int DMARead(unsigned char usbSelect , unsigned char *rbuffer , int len , int waitTime) ,主要功能是計(jì)算機(jī)批量讀取 ISP1581 中的數(shù)據(jù),而 ISP1581 以 DMA 方式從外部 RAM 讀取數(shù)據(jù)。
int DMAWrite(unsigned char usbSelect , unsigned char *rbuffer , int len , int waitTime) ,主要功能是計(jì)算機(jī)批量寫數(shù)據(jù)到 ISP1581 ,而 ISP1581 將以 DMA 方式寫數(shù)據(jù)到外部 RAM
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

