摘要:為了在Windows下實現USB網卡驅動程序,本文根據NDIS_WDM驅動模型,分析了NDIS_WDM模型的內在運行機制,提出了一個USB網卡驅動的設計方案,并重點討論了NDIS和USB設備棧的交互過程,圍繞這個過程,使用Windows DDK 2003開發包及VC開發工具,寫出了USB網卡驅動程序的初始化和發送接收過程的關鍵代碼。實現了對CY3681評估板的發送接收操作。
關鍵詞:WDM;NDIS;WDM-NDIS;usb類驅動;網卡驅動
1 引言
USB(Universal Serial Bus)即通用串行總線,正在成為各種新型設備的標準總線,USB的傳輸速度已由USB1.0的12Mbps提高到了USB2.0的480Mbps,同時USB設備具有即插即用的特點,所以它越來越受到業界的重視。
基于PCI總線的網卡一般符合NDIS體系結構,在臺式機上應用廣泛。隨著計算機的微型化發展,要求設備具即插即用的特點,這種傳統PCI的網卡已不能適應新的需要,因此開發一種基于USB的網卡便有重大的意義。這種網卡驅動程序遵循NDIS_WDMW體系結構。它結合了NDIS(Network Driver Interface Specification)和WDM(Win32 Driver Model)兩種體系結構的特點。本文將探討NDIS_WDM驅動程序體系結構特點,及USB網卡驅動實現的有關問題。
2 基于WDM-NDIS體系的USB網卡的設計原理
2.1 系統結構
NDIS體系結構獨立于硬件,用戶可以將不同的協議和不同的網卡綁定進而完成不同的功能。使網絡協議更具有通用性[3]。
NDIS支持三種類型的驅動程序,從下往上向看,他們分別是微端口驅動程序、中間層驅動程序和協議驅動程序。傳統的PCI網卡驅動程序位于NDIS的第三層,屬于微端口驅動程序(Miniport Driver) ,它有兩個基本功能:
管理一個網絡接口卡NIC(Network Interface Card),包括通過NIC發送和接收數據。與高層驅動程序相接[1]。
但是基于USB的網卡驅動程序和傳統PCI網卡驅動最大的差別是NDIS下層的基礎不同。PCI網卡驅動的下層是硬件抽象層HAL,USB網卡驅動的下層是USB設備棧。如圖1所示:
基于USB的網卡驅動向上要和NDIS體系結構交互,本身屬于NDIS的一部分,也要完成微端口驅動程序的收發數據功能。但是它不通過HAL而通過符合WDM模型的USB類驅動程序的接口完成,為此,基于USB網卡驅動必須自己構造USB請求包URB(Usb Requet Block)請求下層USB設備棧完成數據收發功能。這種驅動程序和傳統的NDIS的微端口驅動程序有異有同,和WDM下的USB棧中的客戶驅動程序也有異同。
2.2 收發數據過程
每當NDIS上層協議或中間驅動請求發送數據時,NDIS_WDM微端口驅動程序的收發函數將被調用,因為它下層是USB設備棧,所以不能直接調用NDIS庫里的中斷或DMA操作硬件。而是重新在內核的不分頁內存中重建一個請求包URB,把上層的請求包轉化為URB, 下傳給USB設備棧,然后把包標志為pending,等待下層USB設備完成相關的操作后返回,此時,NDIS_WDM驅動程序收到下層的結果后再把原來標志為Pending 的包重新處理,回收在內存中分配的URB空間[3]。返回上層程序。如圖2所示:
3 基于WDM-NDIS體系的USB網卡設計的實現
3.1 網卡初始化過程
NDIS_WDM驅動程序完成對驅動程序對象的注冊后,系統探測到硬件設備后,將對網卡進行初始化。通常初始化主要完成網卡的注冊及發送和接收資源的分配,NDIS_WDM還要探索USB設備及配置USB設備。
3.1.1 注冊自定義網卡對象
由于NDIS_WDM Miniport Driver要將上層的協議驅動程序或是中間驅動程序的請求包轉交給下層的USB設備棧完成,因此,在自定義的網卡對象中除了有通常網卡對象中的接收鏈表,發送鏈表,網卡地址信息,和狀態統計信息外,還必須有如下關鍵結構:
PIRP StatusIndicationIrpNDIS_WDM Miniport Driver在不分頁內存中分配的URB請求包,表示當前驅動程序正要處理或正在處理的請求。
DEVICE_OBJECT TargetDeviceObject表示在整個設備棧體系中NDIS_WDM Miniport 設備對象的下層第一個設備對象。當NDIS_WDM 驅動要要完成收發數據時,構造一個StatusIndicationIrp下傳給它。
除了這兩個結構外,網卡對象還包括其他信息,具體如下:
typedef struct _MP_ADAPTER
{
網址名稱及地址信息
發送隊資源及操作信息
接收隊資源及操作信息
PIRP StatusIndicationIrp
DEVICE_OBJECT TargetDeviceObject
網卡狀態統計信息
}
通過StatusIndicationIrp TargetDeviceObject 這兩個數據結構完成了NDIS和USB設備棧的連接。網卡可以通過StatusIndicationIrp保存當前處理的IRP(IO Request Packet),并且能跟蹤IRP的去向。
3.1.2 自定義請求轉換函數
正如圖2所示,上層的驅動程序請求不能直接下傳給下層USB設備棧,必須要把上層的NDIS請求轉化為IRP請求,下去才能接收并處理。NDIS請求中包括如下信息:請求的操作類型,輸入緩沖區,輸出緩沖區,NDIS_WDM驅動程序必須把這些信息轉化為IRP請求包發送到下層的USB設備棧中,并報告下下層設備的執行結果。據此自定義一個轉換函數。
NICMakeSynchronousIoctl
(
INPDEVICE_OBJECT TopOfDeviceStack,INPFILE_OBJECT FileObject,IN ULONG IoctlControlCode,INOUT PVOIDInputBuffer, INULONG InputBufferLength, IN OUT PVOID OutputBuffer,INULONG OutputBufferLength,OUT PULONG BytesReadOrWritten
)
其中,TopOfDeviceStack指明下層的第一個設備棧,BytesReadOrWritten 返回下層的執行結果。
該函數的實現過程的關鍵例程如下:
調用IoAllocateIrp在內核的不分頁內存之中分配一個空白的IRP請求包。
利用NICMakeSynchronousIoctl的參數對剛創建的IRP初始化
設置完成例程IoSetCompletionRoutine,這個完成例程在下層設備完成IRP后捕捉它,以完成報告執行結果及回收IRP的工作。
把初始化后的IRP下傳到下層設備棧 IoCallDriver(TopOfDeviceStack, irp)
等待下層設備棧完成,調用KeWaitForSingleObject函數,與下層設備棧同步。
這個自定義函數很重要,上層的每個一個請求最終都會調用它來完成。
3.1.3探索下層的設備棧接口
NDIS_WDM微端口驅動程序必須要知道其下層的類驅動程序接口(USBI),才能確定IRP的去向,因此在初始化函數之中,必須找到下層的USB設備棧接口(USBDI)。為此調用一個關鍵的函數:
NdisMGetDeviceProperty(
MiniportAdapterHandle,Adapter->Pdo,Adapter->Fdo,
Adapter->NextDeviceObject, NULL,NULL
);
第三個參數Adapter->NextDeviceObject返回的就是下層的USB設備對象,用Adapter->TargetDeviceObject指向這個對象。作為以后IRP的去向。
3.1.4配置USB設備
USB設備對象有多個配置,每一個配置有多個接口,每一個接口又有多個端點,每一個端點又有控制傳輸、批量傳輸、中斷傳輸、等時傳輸方式[4]。 因此在上層的NDIS_WDM Miniport 微端口驅動程序和下層的USB設備交互前,也就是初始化函數中,必須要對USB設備進行適當的配置。
其關鍵過程如下:
1、 獲得設備并設置設備描述符
ReadandSelectDescriptors(
IN PDEVICE_OBJECT DeviceObject)
2、讀取第一個配置描述符
ConfigureDevice(
IN PDEVICE_OBJECT DeviceObject)
3、設置配置描述符
SelectInterfaces(
IN PDEVICE_OBJECT DeviceObject,
IN PUSB_CONFIGURATION_DESCRIPTOR
onfigurationDescriptor)
這三個函數的實現過程大體相同,都是構造URB,但使用不同的構造函數構建的USR。UsbBuildGetDescriptorRequest創造一個獲得配置描述符的USR,USBD_CreateConfigurationRequestEx創建一個配置設備描述符的USR,將這些不同的URB通過自定義函數NICMakeSynchronousIoctl下傳到設備棧。以完成對USB設備的配置。
3.2接收/發送函數
在ndis網卡驅動程序中,發送數據包過程是驅動程序通過調用發送函數完成,而接收過程是通過中斷方式完成,兩者差別很大,但在NDIS_WDM驅動程序的下層是USB設備棧,不能使用中斷,發送和接收過程都是通過向下層的USB設備棧發送URP來完成[5]。兩都的處理過程原理相同。只是發送和接收過程中URP的位域設置不同。
其關鍵過程如下:
UsbBuildInterruptOrBulkTransferRequest(
urb,sizeof(struct(_URB_BULK_OR_INTERRUPT_T RANSFER),
pipeInformation->PipeHandle, NULL, mdl,, stageLength,
urbFlags, NULL
)
該函數作用是在非分頁內存中構造一個_URB_BULK_OR_INTERRUPT_TANSFER類型的URB。
填充URP的各個域。
IoSetCompletionRoutine為URP設置完成例程,待URP處理完成以后繼續處理這個請求。
IoCallDriver(TargetDeviceObject, URB)把構建的帶有收發請求的URB通過USBDI下傳給USB設備棧。并等待這個USR請求的完成。
4 實驗結果
由于網卡由硬件和軟件組成,本工程采用符USB2.0標準的CY3681評估板作為是硬件測試工具。使用winpcap作為網絡軟件測試工具。
pcap_open在數據鏈路層上打開USB網絡接口,pcap_sendpacket向打開的網口發送數據包,以完成對CY3681評估板進行發送操作。發送速度可達35.8M。
結束語
本文采用與傳統PCI網卡驅動設計相對比的方法,介紹了NDIS_WDM的結構特點,并提出一個USB網卡驅動程序運行機制和它的設計方案,寫出了實現這個網卡的關鍵代碼。但是它不是一個完整的網卡設計方案,沒有涉及到硬件部分,還希望讀者能夠完善它。
參考文獻
[1] 陳向群、馬洪兵,Windows 內核實驗教程[M],第一版 北京:機械工業出版社。2002
[2] Windows IFS Kit and DDK 3790 Document[M], Microsoft Corporatino,20003
[3] Chris Cant .Windows WDM設備驅動開發指南[M]. 北京:機械工業出版社2001
[4] Art Baker1W indow s 2000 設備驅動程序設計指南[M ]. 第2 版. 北京: 機械工業出版社, 2001
[5] Walter Oney. Programming the Windows DriverModel [M ] . Microsoft Press, 19991