摘要: 文章介紹了USB和WDM驅動程序的基本概念和結構,結合實例闡述了用NuMega 公司的DriverStudio工具包開發Windows 2000環境下WDM USB設備驅動程序的方法,并給出關鍵例程主要代碼。
關鍵詞:USB WDM 設備驅動程序 DriverStudio
引言
隨著微機技術水平的日益提高,傳統的計算接口已經不能滿足當前計算機高速發展的需求,計算機業界迫切需要新的通用型、高速總線接口。通用外設接口標準USB應運而生。USB,全稱為通用串行總線(Universal Serial Bus),它是Compaq、IBM等PC大廠商聯合開發的一種新型的、基于令牌的、高速的串行總線標準。開發者要設計USB設備接口,就必須首先了解USB協議,在此基礎上有針對性的開發USB設備驅動程序。
USB簡介
在眾多的PC機總線中,USB以其突出的優點獨樹一幟:① 使用方便。支持熱拔插,不涉及中斷請求(IRQ)沖突等問題,能真正做到“即插即用”。②傳輸速率高。目前的USB 2.0協議速度高達480Mbps 。③易于擴展。通過使用Hub擴展可連接多達127個外設。④使用靈活。USB共有4種傳輸模式:控制(control)、同步(Synchronization)、中斷(interrupt)、批量(bulk),以適應不同設備的需要。⑤獨立供電。正由于上述優點,開發USB接口的設備已成為一種發展趨勢。
一個完整的USB系統包括主機系統和USB設備。所有的傳輸事務都是由主機發起的。一個主機系統又可以分為以下幾個層次結構,如圖1所示:

圖1 USB 互連通信模型
USB總線接口包括USB主控制器和根集線器,其中USB主控制器負責處理主機與設備之間電氣和協議層的互連,根集線器提供USB設備連接點。USB系統使用USB主控制器來管理主機和USB設備之間的數據傳輸,另外它也負責管理USB資源,如帶寬等。應用軟件不能直接訪問USB設備硬件,而通過USB系統和USB總線接口與USB設備進行交互。
USB設備包含一些向主機軟件提供一系列USB設備的特征和能力的信息的設備描述符,用來配置設備和定位USB設備驅動程序。這些信息確保了主機以正確的方式訪問設備。通常,一個設備有一個或多個配置(Configuration)來控制其行為。配置是接口(Interface)的集合,接口指出軟件應該如何訪問硬件。接口又是端點(endpoint)的集合,每一個與USB交換數據的硬件就為端點,它是作為通信管道的一個終點。圖1顯示了一個多層次結構的通信模型,它表明了端點和管道所扮演的角色。
WDM驅動程序和USB驅動程序的分層結構
設備驅動程序實際上是指一系列控制硬件設備的函數,是操作系統中控制和連接硬件的關鍵模塊。它提供連接到計算機的硬件設備的軟件接口。
1、WDM 驅動程序介紹
WDM(Win32 Driver Model)是Microsoft公司力推的一種符合Windows2k/XP下的內核模式驅動程序的分層體系結構的驅動程序模式。它源于 Windows NT的分層32位設備驅動程序模型,它支持更多的特性,如即插即用( PnP ,Plug and Play )、電源管理( PM ,Power Management )、Windows管理診斷( WMI ,Windows Management Instrumentation )和 NT 事件。它為Windows操作系統的設備驅動程序提供了統一的框架,在Windows平臺上,WDM將成為主流的驅動模式。
WDM引入了功能設備對象FDO(Function Device Object)與物理設備對象PDO(Physical Device Object)兩個新類來描述硬件,一個PDO對應一個真實的硬件。一個硬件只允許有一個PDO,卻可以擁有多個FDO,在驅動程序中直接操作的不是硬件而是相應的PDO和FDO。
WDM是通過一個128位的全局唯一標識符(GUID)實現驅動程序的識別。應用程序與WDM驅動程序通信時,應用程序將每用戶請求形成I/O請求包(IRP)發送到驅動程序。驅動程序識別出IRP請求后指揮硬件執行相應操作。
2、開發WDM驅動程序的方法
目前開發WDM驅動程序的方法有三種:
①使用 Microsoft 的 Windows2000 DDK工具開發。②使用 KRFTech 公司的 WinDriver 。③使用 NuMega 公司的 DriverStudio 。
3、WDM型的USB驅動程序結構
對于USB設備來說,其WDM驅動程序分為USB底層(總線)驅動程序和USB功能(設備)驅動程序。USB驅動程序符合Windows 2000下的內核模式驅動程序的分層體系結構,如圖2所示:

圖2 WDM型的USB驅動程序體系結構
USB底層驅動程序由操作系統提供,負責與實際的硬件打交道,實現煩瑣的底層通信。USB功能驅動程序由設備開發者編寫,不對實際的硬件進行操作,而是通過向USB底層驅動程序發送包含URB(USB Request Block,請求塊)的IRP,來實現對USB設備信息的發送和接收。采用這種分層驅動程序的設計方法有兩個優點:(1)多個USB設備可以通過USB底層驅動程序來協調它們的工作。(2)編寫分層驅動程序較之編寫單一驅動程序相對簡單,且可以節省內存和資源,不易出錯。
USB驅動程序工作簡述如下:當應用程序想對USB設備進行I/O操作,它需調用Windows API函數,I/O管理器將此請求構造成一個合適的I/O請求包(IRP)并把它傳遞給USB功能驅動程序。USB功能驅動程序接收到這個IRP后,根據IPR中包含的具體操作代碼構造相應USB請求塊(URB),并把此URB放到一個新的IRP中,然后把它傳遞給USB底層驅動程序。USB底層驅動程序根據IRP中所含的URB執行相應的操作,并把操作的結果返回給USB功能驅動程序。USB功能驅動程序接收到此返回的IRP后,將操作結果通過IRP返還給I/O管理器,最后I/O管理器將此IRP操作結果傳回給應用程序,至此應用程序對設備的一次I/O操作完成。
用Driver Studio工具包開發WDM型的USB設備驅動程序
前文所提及的WDM驅動程序開發方法,筆者都曾嘗試過。個人認為用DriverStudio開發工具包來開發USB驅動程序行之有效。其中的Driver Wizard是創建WDM驅動程序框架的一個很好的工具,后文將介紹用它來創建USB設備驅動程序的基本框架。
1、搭建開發平臺
由于利用 DriverStudio 開發WDM驅動程序在搭建開發平臺的過程中對軟件的安裝順序要求頗高,在開發過程中我也曾因為安裝順序的顛倒而失敗。在實踐中總結了以下的安裝步驟,有必要在此作以介紹。
①在已裝了Windows 2000 操作系統的機子上安裝 Microsoft Visual C++6.0。 ②安裝 Win2000 DDK 。③安裝 NuMega DriverStudio 2.0 ( or 2.6 ) 驅動程序開發工具包。它包含DriverWorks( 用于開發內核模式WDM驅動程序 )、SoftICE( 用于調試WDM驅動程序 )等開發工具。④由于DriverWorks 所用的類庫是對 DDK 函數的封裝,必須在 VC中編譯,創建自己的庫文件。⑤設置 DDK 路徑。
2、利用DriverStudio 的DriverWorks生成USB設備驅動程序框架
驅動程序開發平臺搭建成功后,我們可利用驅動程序生成向導Driver Wizard,根據硬件設置較為容易的生成USB設備驅動程序的大體框架。本人的設置如下:①選擇WDM的驅動程序類型和Windows 2000運行平臺。②選擇USB總線類型,系統選擇的USB芯片是Philip公司的ISP1581,填寫它的VID(供應商ID)和PID(設備ID),這些信息由芯片的供應商提供。③增加端點1和端點2,它們分別具有IN和OUT屬性。④根據需要選擇對設備的操作有:Read、Write、Device Control和CleanUp。⑤選擇給端點2產生BULK Read和Write的代碼, 向導會自動產生一套對端點2進行讀、寫的代碼。⑥設置驅動程序的屬性,采用WDM接口;在選取讀寫方式時應遵循一條原則:需要快速傳送大量數據時,用 Direct I/O ,反之用 Buffer I/O ,這里選擇BufferI/O;由于無特殊的電源需求,故選用系統默認的Manage Power For This Device。⑧增加IOCTL接口,在其生成的代碼框架中加入自己的操作,以實現一個完整的USB設備驅動程序。最后就生成了一個WDM型的USB設備驅動程序框架和一個測試該驅動程序的測試程序大體框架。然后在其中添加需要的功能代碼。
3、USB設備驅動程序中的關鍵例程代碼實現
下面以我們的驅動程序為例,介紹USB驅動程序開發中的幾個關鍵例程的實現。本驅動程序的主要功能是控制USB設備上LED燈通斷并且對設備進行讀寫。
1) 初始化例程 DriverEntry()
設備驅動程序與應用程序不同,它沒有main()或WinMain()函數,而是有一個名為DriverEntry()的入口函數,它通常完成一些初始化工作。當設備驅動程序被加載時,操作系統調用這個入口。在使用DriverWizard 創建的驅動程序基本框架中,DriverEntry()函數已經寫好了,無需添寫代碼。在該例程中,驅動程序要向操作系統登記并注冊一些消息處理器,通過RegistryPath來找到位于注冊表中的驅動程序參數,當驅動程序正確安裝后,在注冊表KEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Service 下可以找到MyUSB 項。而用DDK編寫該入口函數還需初始化Dispatch(分派)例程入口。
2) 創建設備例程 AddDevice()
大多數的PDO 都是在 PnP 管理器調用該程序入口點時被創建的。插入新設備后,系統啟動時,總線枚舉器會發現總線上的所有設備,會自動尋找并安裝設備的驅動程序,并由驅動程序中的處理 PnP 功能模塊自動處理 AddDevice() 例程及其他PnP消息。此例程使用IoCreateDevice() 函數創建設備對象,再使用 IoRegisterDeviceInterface() 函數將設備組成為一個特定的設備接口,然后使用IoAttachDeviceToDeviceStack() 函數關聯設備棧。
| NTSTATUS MyUSBDevice::AddDevice( PDEVICE_OBJECT Pdo ) { // 產生一個DDK中KDevice類新的設備對象 MyUSBDevice *pDevice = new ( static cast<PCWSTR>( KUnitizedName(L“MyUSBDevice”,m_Unit) ),// 設備名 FILE_DEVICE_UNKNOWN, // 設備類型 NULL, // 指針鏈接名 0, // 設備特征標志位 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) ) // 不成功,返回錯誤狀態并刪除指針 { delete pDevice; } else // 如果成功,向系統報考設備的電源狀態變化為PowerDeviceD0 { m_Unit++; pDevice -> ReportNewDevicePowerState( PowerDeviceD0 ); } return status; } |
3) LED控制處理例程 MyUSB_IOCTL_LED_Handler()
該例程是實現本驅動程序功能的關鍵例程,它是用來控制設備上的LED燈通斷,主要利用USB Vendor Request來向設備傳送。其中,request=1的時候表示讓LED亮,request=0的時候讓LED滅。它是通過DeviceControl由上層應用程序傳下來。實現代碼如下:
| NTSTATUS MyUSBDevice::MyUSB_IOCTL_LED_Handler(KIrp I) { NTSTATUS status = STATUS_INVALID_PARAMETER; //檢查輸入參數是否正確,如果不正確,返回STATUS_INVALID_PARAMETER if(I.IoctlOutputBufferSize() || !I.IoctlBuffer() ||(I.IoctlInputBufferSize() != sizeof(UCHAR))) return status; //處理MyUSB_IOCTL_LED_ON請求 PURB pUrb = m_Lower.BuildVendorRequest(NULL, // 傳輸緩沖區 0, // 傳輸緩沖區大小 0, // 請求保留位 (UCHAR)(*(PUCHAR)I.IoctlBuffer()), // 請求1=LED_ON ,0=LED_OFF 0 ); // 值 //向下傳送URB status = m_Lower.SubmitUrb(pUrb, NULL, NULL, 5000L); //若請求在此處理,設置I.Information指示多少數據拷貝回用戶 I.Information()=0; I.Status()=status; return status; } |
4) 訪問硬件例程 DeviceControl()
上層應用軟件程序就是通過此例程來將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 控制請求 status = STATUS_INVALID_PARAMETER; break; } } |
限于篇幅,這里僅介紹本驅動程序中的部分例程實現代碼。編寫完驅動程序后,首先在Visual C++ 中編譯通過,然后連接硬件,用DriverStudio 工具包中的SoftICE調試器調試該驅動程序,并且修改編譯DriverStudio產生的該驅動程序的測試程序,就通過命令行來測試我們的驅動程序。最后對于LED的控制,我們可以直觀的在設備上看到。
結束語
USB技術的不斷發展和完善,已經使其逐漸成為先進總線接口技術的標志和方向,如今USB OTG標準已經發布,那么USB的應用領域也將越發的廣泛。開發一些特定功能的USB接口并設計其設備驅動程序也將成為應用USB技術的關鍵。通過對USB的學習和Windows 2000下的WDM驅動程序的研究,本文已經給出了編寫WDM型USB設備驅動程序的一般方法,讀者可以在實際應用中逐步提高對USB和驅動程序的認識,取得事半功倍的效果。

