1 引言
隨著微機(jī)技術(shù)水平的日益提高,,傳統(tǒng)的計(jì)算接口已經(jīng)不能滿足當(dāng)前計(jì)算機(jī)高速發(fā)展的需求,,計(jì)算機(jī)業(yè)界迫切需要新的通用型、高速總線接口,。通用外設(shè)接口標(biāo)準(zhǔn) USB 應(yīng)運(yùn)而生,。 USB, 全稱為通用串行總線( Universal Serial Bus ),它是 Compaq ,、 IBM 等 PC 大廠商聯(lián)合開(kāi)發(fā)的一種新型的,、基于令牌的、高速的串行總線標(biāo)準(zhǔn),。開(kāi)發(fā)者要設(shè)計(jì) USB 設(shè)備接口,,就必須首先了解 USB 協(xié)議,在此基礎(chǔ)上有針對(duì)性的開(kāi)發(fā) USB 設(shè)備驅(qū)動(dòng)程序,。
2 USB 簡(jiǎn)介
在眾多的 PC 機(jī)總線中,, USB 以其突出的優(yōu)點(diǎn)獨(dú)樹(shù)一幟: ① 使用方便。支持熱拔插,,不涉及中斷請(qǐng)求( IRQ )沖突等問(wèn)題,,能真正做到 “ 即插即用 ” ,。 ② 傳輸速率高。目前的 USB 2.0 協(xié)議速度高達(dá) 480Mbps ,。 ③ 易于擴(kuò)展,。通過(guò)使用 Hub 擴(kuò)展可連接多達(dá) 127 個(gè)外設(shè)。 ④ 使用靈活,。 USB 共有4種傳輸模式:控制 (control) ,、同步 (Synchronization) 、中斷 (interrupt) ,、批量 (bulk) ,,以適應(yīng)不同設(shè)備的需要。 ⑤ 獨(dú)立供電,。正由于上述優(yōu)點(diǎn),,開(kāi)發(fā) USB 接口的設(shè)備已成為一種發(fā)展趨勢(shì)。
一個(gè)完整的 USB 系統(tǒng)包括主機(jī)系統(tǒng)和 USB 設(shè)備,。所有的傳輸事務(wù)都是由主機(jī)發(fā)起的,。一個(gè)主機(jī)系統(tǒng)又可以分為以下幾個(gè)層次結(jié)構(gòu),如圖 1 所示:
圖 1 USB 互連通信模型
USB 總線接口包括 USB 主控制器和根集線器,,其中 USB 主控制器負(fù)責(zé)處理主機(jī)與設(shè)備之間電氣和協(xié)議層的互連,,根集線器提供 USB 設(shè)備連接點(diǎn)。 USB 系統(tǒng)使用 USB 主控制器來(lái)管理主機(jī)和 USB 設(shè)備之間的數(shù)據(jù)傳輸,,另外它也負(fù)責(zé)管理 USB 資源 , 如帶寬等,。應(yīng)用
軟件不能直接訪問(wèn) USB 設(shè)備硬件,而通過(guò) USB 系統(tǒng)和 USB 總線接口與 USB 設(shè)備進(jìn)行交互,。
USB 設(shè)備包含一些向主機(jī)軟件提供一系列 USB 設(shè)備的特征和能力的信息的設(shè)備描述符,,用來(lái)配置設(shè)備和定位 USB 設(shè)備驅(qū)動(dòng)程序。這些信息確保了主機(jī)以正確的方式訪問(wèn)設(shè)備,。通常,,一個(gè)設(shè)備有一個(gè)或多個(gè)配置 (Configuration) 來(lái)控制其行為。配置是接口 (Interface) 的集合,,接口指出軟件應(yīng)該如何訪問(wèn)硬件,。接口又是端點(diǎn) (endpoint) 的集合,每一個(gè)與 USB 交換數(shù)據(jù)的硬件就為端點(diǎn),,它是作為通信管道的一個(gè)終點(diǎn),。圖 1 顯示了一個(gè)多層次結(jié)構(gòu)的通信模型,它表明了端點(diǎn)和管道所扮演的角色,。
3 WDM 驅(qū)動(dòng)程序和 USB 驅(qū)動(dòng)程序的分層結(jié)構(gòu)
設(shè)備驅(qū)動(dòng)程序?qū)嶋H上是指一系列控制硬件設(shè)備的函數(shù),,是操作系統(tǒng)中控制和連接硬件的關(guān)鍵模塊。它提供連接到計(jì)算機(jī)的硬件設(shè)備的軟件接口,。
3.1 WDM 驅(qū)動(dòng)程序介紹
WDM(Win32 Driver Model) 是 Microsoft 公司力推的一種符合 Windows2k/XP 下的內(nèi)核模式驅(qū)動(dòng)程序的分層體系結(jié)構(gòu)的驅(qū)動(dòng)程序模式,。它源于 Windows NT 的分層 32 位設(shè)備驅(qū)動(dòng)程序模型,,它支持更多的特性,如即插即用( PnP ,, Plug and Play ),、電源管理( PM , Power Management ),、 Windows 管理診斷( WMI ,, Windows Management Instrumentation )和 NT 事件。它為 Windows 操作系統(tǒng)的設(shè)備驅(qū)動(dòng)程序提供了統(tǒng)一的框架,,在 Windows 平臺(tái)上, WDM 將成為主流的驅(qū)動(dòng)模式,。
WDM 引入了功能設(shè)備對(duì)象 FDO(Function Device Object) 與物理設(shè)備對(duì)象 PDO(Physical Device Object) 兩個(gè)新類來(lái)描述硬件,,一個(gè) PDO 對(duì)應(yīng)一個(gè)真實(shí)的硬件。一個(gè)硬件只允許有一個(gè) PDO ,,卻可以擁有多個(gè) FDO ,,在驅(qū)動(dòng)程序中直接操作的不是硬件而是相應(yīng)的 PDO 和 FDO 。 WDM 是通過(guò)一個(gè) 128 位的全局唯一標(biāo)識(shí)符 (GUID) 實(shí)現(xiàn)驅(qū)動(dòng)程序的識(shí)別,。應(yīng)用程序與 WDM 驅(qū)動(dòng)程序通信時(shí),,應(yīng)用程序?qū)⒚坑脩粽?qǐng)求形成 I/O 請(qǐng)求包 (IRP) 發(fā)送到驅(qū)動(dòng)程序。驅(qū)動(dòng)程序識(shí)別出 IRP 請(qǐng)求后指揮硬件執(zhí)行相應(yīng)操作,。
3.2 開(kāi)發(fā) WDM 驅(qū)動(dòng)程序的方法
目前開(kāi)發(fā) WDM 驅(qū)動(dòng)程序的方法有三種:
① 使用 Microsoft 的 Windows2000 DDK 工具開(kāi)發(fā),。 ② 使用 KRFTech 公司的 WinDriver 。 ③ 使用 NuMega 公司的 DriverStudio ,。
3.3 WDM 型的 USB 驅(qū)動(dòng)程序結(jié)構(gòu)
對(duì)于 USB 設(shè)備來(lái)說(shuō),,其 WDM 驅(qū)動(dòng)程序分為 USB 底層(總線)驅(qū)動(dòng)程序和 USB 功能 ( 設(shè)備 ) 驅(qū)動(dòng)程序。 USB 驅(qū)動(dòng)程序符合 Windows 2000 下的內(nèi)核模式驅(qū)動(dòng)程序的分層體系結(jié)構(gòu),,如圖 2 所示:
圖 2 WDM 型的 USB 驅(qū)動(dòng)程序體系結(jié)構(gòu)
USB 底層驅(qū)動(dòng)程序由操作系統(tǒng)提供,,負(fù)責(zé)與實(shí)際的硬件打交道,實(shí)現(xiàn)煩瑣的底層通信,。 USB 功能驅(qū)動(dòng)程序由設(shè)備開(kāi)發(fā)者編寫(xiě),,不對(duì)實(shí)際的硬件進(jìn)行操作,而是通過(guò)向 USB 底層驅(qū)動(dòng)程序發(fā)送包含 URB ( USB Request Block ,,請(qǐng)求塊)的 IRP ,,來(lái)實(shí)現(xiàn)對(duì) USB 設(shè)備信息的發(fā)送和接收。采用這種分層驅(qū)動(dòng)程序的設(shè)計(jì)方法有兩個(gè)優(yōu)點(diǎn): (1) 多個(gè) USB 設(shè)備可以通過(guò) USB 底層驅(qū)動(dòng)程序來(lái)協(xié)調(diào)它們的工作,。 (2) 編寫(xiě)分層驅(qū)動(dòng)程序較之編寫(xiě)單一驅(qū)動(dòng)程序相對(duì)簡(jiǎn)單,,且可以節(jié)省內(nèi)存和資源,不易出錯(cuò),。
USB 驅(qū)動(dòng)程序工作簡(jiǎn)述如下:當(dāng)應(yīng)用程序想對(duì) USB 設(shè)備進(jìn)行 I/O 操作,,它需調(diào)用 Windows API 函數(shù),, I/O 管理器將此請(qǐng)求構(gòu)造成一個(gè)合適的 I/O 請(qǐng)求包( IRP )并把它傳遞給 USB 功能驅(qū)動(dòng)程序。 USB 功能驅(qū)動(dòng)程序接收到這個(gè) IRP 后,,根據(jù) IPR 中包含的具體操作代碼構(gòu)造相應(yīng) USB 請(qǐng)求塊( URB ),,并把此 URB 放到一個(gè)新的 IRP 中,然后把它傳遞給 USB 底層驅(qū)動(dòng)程序,。 USB 底層驅(qū)動(dòng)程序根據(jù) IRP 中所含的 URB 執(zhí)行相應(yīng)的操作,,并把操作的結(jié)果返回給 USB 功能驅(qū)動(dòng)程序。 USB 功能驅(qū)動(dòng)程序接收到此返回的 IRP 后,,將操作結(jié)果通過(guò) IRP 返還給 I/O 管理器,,最后 I/O 管理器將此 IRP 操作結(jié)果傳回給應(yīng)用程序,至此應(yīng)用程序?qū)υO(shè)備的一次 I/O 操作完成,。
4 用 Driver Studio 工具包開(kāi)發(fā) WDM 型的 USB 設(shè)備驅(qū)動(dòng)程序
前文所提及的 WDM 驅(qū)動(dòng)程序開(kāi)發(fā)方法,,筆者都曾嘗試過(guò)。個(gè)人認(rèn)為用 DriverStudio 開(kāi)發(fā)工具包來(lái)開(kāi)發(fā) USB 驅(qū)動(dòng)程序行之有效,。其中的 Driver Wizard 是創(chuàng)建 WDM 驅(qū)動(dòng)程序框架的一個(gè)很好的工具,,后文將介紹用它來(lái)創(chuàng)建 USB 設(shè)備驅(qū)動(dòng)程序的基本框架。
4.1 搭建開(kāi)發(fā)平臺(tái)
由于利用 DriverStudio 開(kāi)發(fā) WDM 驅(qū)動(dòng)程序在搭建開(kāi)發(fā)平臺(tái)的過(guò)程中對(duì)軟件的安裝順序要求頗高,,在開(kāi)發(fā)過(guò)程中我也曾因?yàn)榘惭b順序的顛倒而失敗,。在實(shí)踐中總結(jié)了以下的安裝步驟,有必要在此作以介紹,。
① 在已裝了 Windows 2000 操作系統(tǒng)的機(jī)子上安裝 Microsoft Visual C++6.0 ,。 ② 安裝 Win2000 DDK 。 ③ 安裝 NuMega DriverStudio 2.0 ( or 2.6 ) 驅(qū)動(dòng)程序開(kāi)發(fā)工具包,。它包含 DriverWorks ( 用于開(kāi)發(fā)內(nèi)核模式 WDM 驅(qū)動(dòng)程序 ),、 SoftICE ( 用于調(diào)試 WDM 驅(qū)動(dòng)程序 )等開(kāi)發(fā)工具。 ④ 由于 DriverWorks 所用的類庫(kù)是對(duì) DDK 函數(shù)的封裝,,必須在 VC 中編譯,,創(chuàng)建自己的庫(kù)文件。 ⑤ 設(shè)置 DDK 路徑,。
4.2 利用 DriverStudio 的 DriverWorks 生成 USB 設(shè)備驅(qū)動(dòng)程序框架
驅(qū)動(dòng)程序開(kāi)發(fā)平臺(tái)搭建成功后,,我們可利用驅(qū)動(dòng)程序生成向?qū)?/span>Driver Wizard ,根據(jù)硬件設(shè)置較為容易的生成 USB 設(shè)備驅(qū)動(dòng)程序的大體框架,。本人的設(shè)置如下: ① 選擇 WDM 的驅(qū)動(dòng)程序類型和 Windows 2000 運(yùn)行平臺(tái),。 ② 選擇 USB 總線類型,系統(tǒng)選擇的 USB 芯片是 Philip 公司的 ISP1581 ,,填寫(xiě)它的 VID (供應(yīng)商 ID )和 PID (設(shè)備 ID ),,這些信息由芯片的供應(yīng)商提供。 ③ 增加端點(diǎn) 1 和端點(diǎn) 2 ,,它們分別具有 IN 和 OUT 屬性,。 ④ 根據(jù)需要選擇對(duì)設(shè)備的操作有: Read ,、 Write 、 Device Control 和 CleanUp ,。 ⑤ 選擇給端點(diǎn) 2 產(chǎn)生 BULK Read 和 Write 的代碼 , 向?qū)?huì)自動(dòng)產(chǎn)生一套對(duì)端點(diǎn) 2 進(jìn)行讀,、寫(xiě)的代碼。 ⑥ 設(shè)置驅(qū)動(dòng)程序的屬性,,采用 WDM 接口,;在選取讀寫(xiě)方式時(shí)應(yīng)遵循一條原則:需要快速傳送大量數(shù)據(jù)時(shí),用 Direct I/O ,,反之用 Buffer I/O , 這里選擇 BufferI/O ,;由于無(wú)特殊的電源需求,故選用系統(tǒng)默認(rèn)的 Manage Power For This Device ,。 ⑧ 增加 IOCTL 接口,,在其生成的代碼框架中加入自己的操作,以實(shí)現(xiàn)一個(gè)完整的 USB 設(shè)備驅(qū)動(dòng)程序,。最后就生成了一個(gè) WDM 型的 USB 設(shè)備驅(qū)動(dòng)程序框架和一個(gè)測(cè)試該驅(qū)動(dòng)程序的測(cè)試程序大體框架,。然后在其中添加需要的功能代碼,。
4.3 USB 設(shè)備驅(qū)動(dòng)程序中的關(guān)鍵例程代碼實(shí)現(xiàn)
下面以我們的驅(qū)動(dòng)程序?yàn)槔榻B USB 驅(qū)動(dòng)程序開(kāi)發(fā)中的幾個(gè)關(guān)鍵例程的實(shí)現(xiàn),。本驅(qū)動(dòng)程序的主要功能是控制 USB 設(shè)備上 LED 燈通斷并且對(duì)設(shè)備進(jìn)行讀寫(xiě),。
4.3.1 初始化例程 DriverEntry ()
設(shè)備驅(qū)動(dòng)程序與應(yīng)用程序不同,,它沒(méi)有 main() 或 WinMain ()函數(shù),而是有一個(gè)名為 DriverEntry ()的入口函數(shù),,它通常完成一些初始化工作,。當(dāng)設(shè)備驅(qū)動(dòng)程序被加載時(shí),操作系統(tǒng)調(diào)用這個(gè)入口,。在使用 DriverWizard 創(chuàng)建的驅(qū)動(dòng)程序基本框架中,, DriverEntry ()函數(shù)已經(jīng)寫(xiě)好了,無(wú)需添寫(xiě)代碼,。在該例程中,,驅(qū)動(dòng)程序要向操作系統(tǒng)登記并注冊(cè)一些消息處理器,通過(guò) RegistryPath 來(lái)找到位于注冊(cè)表中的驅(qū)動(dòng)程序參數(shù),,當(dāng)驅(qū)動(dòng)程序正確安裝后,,在注冊(cè)表 KEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Service 下可以找到 MyUSB 項(xiàng)。而用 DDK 編寫(xiě)該入口函數(shù)還需初始化 Dispatch (分派)例程入口,。
4.3.2 創(chuàng)建設(shè)備例程 AddDevice ()
大多數(shù)的 PDO 都是在 PnP 管理器調(diào)用該程序入口點(diǎn)時(shí)被創(chuàng)建的,。插入新設(shè)備后,系統(tǒng)啟動(dòng)時(shí),,總線枚舉器會(huì)發(fā)現(xiàn)總線上的所有設(shè)備,,會(huì)自動(dòng)尋找并安裝設(shè)備的驅(qū)動(dòng)程序,,并由驅(qū)動(dòng)程序中的處理 PnP 功能模塊自動(dòng)處理 AddDevice() 例程及其他 PnP 消息。此例程使用 IoCreateDevice() 函數(shù)創(chuàng)建設(shè)備對(duì)象,,再使用 IoRegisterDeviceInterface() 函數(shù)將設(shè)備組成為一個(gè)特定的設(shè)備接口,,然后使用 IoAttachDeviceToDeviceStack() 函數(shù)關(guān)聯(lián)設(shè)備棧。
NTSTATUS MyUSBDevice::AddDevice( PDEVICE_OBJECT Pdo )
{ // 產(chǎn)生一個(gè) DDK 中 KDevice 類新的設(shè)備對(duì)象
MyUSBDevice *pDevice = new (
static cast( KUnitizedName(L“MyUSBDevice” ,, m_Unit) ),// 設(shè)備名
FILE_DEVICE_UNKNOWN ,, // 設(shè)備類型
NULL , // 指針鏈接名
0 ,, // 設(shè)備特征標(biāo)志位
DO_BUFFERED_IO| DO_POWER_PAGABLE ),; // I/O 傳輸方式
MyUSBDevice(Pdo, m_Unit) ;
if ( pDevice == NULL )
{
return STATUS_INSUFFICIENT_RESOURCES ,;
}
NTSTATUS status = devices -> ConstructorStatus() ,;
if ( !NT_SUCCESS(status) ) // 不成功,返回錯(cuò)誤狀態(tài)并刪除指針
{
delete pDevice ,;
}
else // 如果成功,,向系統(tǒng)報(bào)考設(shè)備的電源狀態(tài)變化為 PowerDeviceD0
{
m_Unit++ ;
pDevice -> ReportNewDevicePowerState( PowerDeviceD0 ) ,;
}
return status ,;
}
4.3.3 LED 控制處理例程 MyUSB_IOCTL_LED_Handler()
該例程是實(shí)現(xiàn)本驅(qū)動(dòng)程序功能的關(guān)鍵例程,它是用來(lái)控制設(shè)備上的 LED 燈通斷,,主要利用 USB Vendor Request 來(lái)向設(shè)備傳送,。其中, request=1 的時(shí)候表示讓 LED 亮,, request=0 的時(shí)候讓 LED 滅,。它是通過(guò) DeviceControl 由上層應(yīng)用程序傳下來(lái)。實(shí)現(xiàn)代碼如下:
NTSTATUS MyUSBDevice::MyUSB_IOCTL_LED_Handler(KIrp I)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
// 檢查輸入?yún)?shù)是否正確,,如果不正確,返回 STATUS_INVALID_PARAMETER
if(I.IoctlOutputBufferSize() || !I.IoctlBuffer() ||(I.IoctlInputBufferSize() != sizeof(UCHAR)))
return status;
// 處理 MyUSB_IOCTL_LED_ON 請(qǐng)求
PURB pUrb = m_Lower.BuildVendorRequest(
NULL, // 傳輸緩沖區(qū) 0, // 傳輸緩沖區(qū)大小 0, // 請(qǐng)求保留位 (UCHAR)(*(PUCHAR)I.IoctlBuffer()), // 請(qǐng)求 1 = LED_ON ,0=LED_OFF 0 ); // 值
// 向下傳送 URB
status = m_Lower.SubmitUrb(pUrb, NULL, NULL, 5000L);
// 若請(qǐng)求在此處理,,設(shè)置 I.Information 指示多少數(shù)據(jù)拷貝回用戶
I.Information ()= 0 ,;
I.Status ()= status ;
return status;
}
4.3.4 訪問(wèn)硬件例程 DeviceControl()
上層應(yīng)用軟件程序就是通過(guò)此例程來(lái)將 IRP 傳到下層,。
NTSTATUS MyUSBDevice::DeviceControl(KIrp I)
{
NTSTATUS status;
switch (I.IoctlCode())
{
case MyUSB_IOCTL_LED:
status = MyUSB_IOCTL_LED_Handler(I);
break;
default: // 未被聲明的 I/O 控制請(qǐng)求
status = STATUS_INVALID_PARAMETER;
break;
}
}
限于篇幅,,這里僅介紹本驅(qū)動(dòng)程序中的部分例程實(shí)現(xiàn)代碼。編寫(xiě)完驅(qū)動(dòng)程序后,,首先在 Visual C++ 中編譯通過(guò),,然后連接硬件,用 DriverStudio 工具包中的 SoftICE 調(diào)試器調(diào)試該驅(qū)動(dòng)程序,并且修改編譯 DriverStudio 產(chǎn)生的該驅(qū)動(dòng)程序的測(cè)試程序,,就通過(guò)命令行來(lái)測(cè)試我們的驅(qū)動(dòng)程序,。最后對(duì)于 LED 的控制,我們可以直觀的在設(shè)備上看到,。
5 結(jié)束語(yǔ)
USB 技術(shù)的不斷發(fā)展和完善,,已經(jīng)使其逐漸成為先進(jìn)總線接口技術(shù)的標(biāo)志和方向,如今 USB OTG 標(biāo)準(zhǔn)已經(jīng)發(fā)布,,那么 USB 的應(yīng)用領(lǐng)域也將越發(fā)的廣泛,。開(kāi)發(fā)一些特定功能的 USB 接口并設(shè)計(jì)其設(shè)備驅(qū)動(dòng)程序也將成為應(yīng)用 USB 技術(shù)的關(guān)鍵。通過(guò)對(duì) USB 的學(xué)習(xí)和 Windows 2000 下的 WDM 驅(qū)動(dòng)程序的研究,,本文已經(jīng)給出了編寫(xiě) WDM 型 USB 設(shè)備驅(qū)動(dòng)程序的一般方法,,讀者可以在實(shí)際應(yīng)用中逐步提高對(duì) USB 和驅(qū)動(dòng)程序的認(rèn)識(shí),取得事半功倍的效果,。