學了兩個多星期了,對USB驅動程序的有一小小的理解。現在總結如下!!!!!!!! 1、每個設備對應一個PDO,每個PDO又對應多個FDO,在驅動程序中直接操作的不是硬件而是相應的PDO和FDO。在USER和KERNEL通信方面,系統將每一個用戶請求打包成IRP結構,將其發送至驅動程序,並通過識別IRP中的PDO來區別是發送給哪個設備的。另外,在驅動程序加載方面,WDM不通過驅動程序名稱識別,而是通過一個128位的全局唯一的標識符GUID來實現驅動程序的識別,即每一個固件都有一個GUID,你通過GUID來區分是哪個固件。 2、USB主機驅動符合WDM驅動體系結構也使用IRP(I/O請求包)的機制。但實際的USB驅動程序使用URB(USB請求塊)結構向其硬件設備發送請求。USB驅動程序高度依賴其總線驅動程序(USBD.SYS),而不直接使用硬件抽象層(HAL)函數與硬件通信。 3、USBD是USB系統軟件中最關鍵的一層,它負責控制全部USB協議的操作和中斷處理控制。主要功能有:設備設置、資源管理、數據傳輸(管道層次)以及公共數據定義等。管道機制和命令機制。管道機制:管道是設備和主機之間的邏輯連接,分爲標準管道和邏輯管道,標準管道用語完成一些客戶通過命令接口所傳遞的請求,如設置設備的地址等,但USBD不允許客戶直接訪問設備的標準管道。客戶管道則有客戶進行管理,並提供相應的數據緩衝區。命令機制允許客戶以讀寫的方式對設備的數據及其控制部分進行訪問,客戶所要做的,僅僅是向USBD提供設備的地址及相關的數據緩衝區的指針。命令機制所提供的功能主要是USB總線管理相關的內容,如設備設置管理、設備數據訪問、總線設備管理以及電流分配等。 4、USB設備驅動程序設計 2000DDK+VC6.0(只能用C,不能用C++) 三個關鍵的例程:DriverEntry、AddDevice、ReadWrite (1)DriverEntry,完成某些全局初始化操作,它是內核模式驅動程序主入口點。 extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) 通過PDRIVER_OBJECT這一重要的數據結構,I/O管理器使用它來定義每一個設備驅動程序,DriverEntry主要工作是各種函數指針填入驅動程序對象的各個域中,這些指針爲操作系統指明瞭驅動程序容器中各種子例程,重要包括下面指針成員: 1、DriverUnload 2、DriverExtension->AddDevice指向驅動程序的AddDevice函數 3、DriverStartIo指向驅動程序處理串行I/O請求的函數。如果驅動程序採用標準的IRP排隊的方式,應該設置該成員,使得指向驅動程序的StartIo例程。 4、MajorFunction是一個指針數組,指向存在於驅動程序中的多種IRP處理函數。 DriverObject->DriverUnload = DriverUnload; DriverObject->DriverExtension->AddDevice =AddDevice; DriverObject->MajorFunction[IRP_MJ_CREATE]= DispatchCreate; ~~~~~~~~~~~~~~ (2)AddDevice 一個驅動程序可以被多個設備使用。WDM驅動程序有一個特殊的AddDevice函數,PnP管理器爲每個實例調用該函數。原形如下: NTSTATUS AddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject); AddDevice函數的基本職責是創建一個設備對象並把它連接到以PDO爲底的設備棧中。 具體步驟如下: 1) 用IoCreateDevice創建設備對象,並建立一個私有的設備擴展對象。 PDEVICE_OBJECT fdo; NTSTATUS status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &fdo); 2) 初始化設備擴展和設備對象的Flag成員。 PDEVICE_EXTENSION pdc = (PDEVICE_EXTENSION)fdo->DeviceExtension; fdo->DeviceExtension; fdo->Flag2|=DO_BUFFERED_IO; 3) 調用IoAttachDeviceToDeviceStace函數把新設備對象放到堆棧上。 pdx->LowerDeviceObject=IoAttachDeviceToDeviceStack(fdo,pfo); 設備對象(DEVICE_OBJECT或*PDEVICE_OBJECT)也是DDK定義的一個重要結構。它可以在其設備名稱(DeviceName)域中(第三個參數)爲設備對象進行命名。 設備對象另一個關鍵的域爲擴展設備對象(DeviceExtension)大小,I/O管理器爲設備對象分配一塊內存,該指針指向一個用戶定義的數據結構,用於保存每個設備實例的信息 typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT DeviceObject; //device object this extension //belongs to PDEVICE_OBJECT LowerDeviceObject; //next lower driver in//same stack PDEVICE_OBJECT Pdo; //the PDO IO_REMOVE_LOCK RemoveLock; //removal control locking structure UNICODE_STRING ifname; //interface name DEVSTATE state //current state of device DEVSTATE prevstate; //state prior to removal query DEVICE_POWER_STATE devpower; //current device power state SYSTEM_POWER_STATE syspower; //currnet system power state DEVICE_CAPABILITIES devcaps; //copy of most recent device capabilities LONG handles; //#open handle USBD_DEVICE_DESCRIPTOR dd; //device descriptor USBD_CONFIGURATION_HANDLE hconfig; //selected configuration handle PUSB_CONFIGURATION_DESCRIPTOR pcd; //Configuration descriptor; LANGID langid; //default language id for strings USBD_PIPE_HANDLE hPipe; USBD_PIPE_HANDLE hPipe_WriteCode; }DEVICE_EXTENSION,*PDEVICE_EXTENSION; AddDevice爲設備對象註冊一個接口,以便應用程序能通過註冊接口來訪問該設備。一個設備接口被一個128位的GUID唯一標識。 status = IoRegisterDeviceInferface(pdo,&GUID_INTERFACE_USB,NULL,&pdx->ifname);得到GUID後,當響應PnP請求IRP_MN_START_DEVICE時,驅動程序調用下面函數使其可用,IoSetDeviceInterfacestate(&pdx->ifname,TRUE); 在響應這個調用過程中,I/O管理器將創建一個指向設備的PDO符號連接對象。因爲接口名最終指向PDO,所以PDO的安全描述符將最終控制設備的訪問權限。(3)ReadWrite實現設備驅動程序功能的各個派遣函數,並實現總線枚舉和管理函數,用於設備初始化以及錯誤恢復。是整個驅動最重要部分,以讀數據請求爲例子,即主機要求設備向其傳輸數據。 1)建立並提交一個URB,USB驅動從不直接和硬件對話,通過創建URB並把URB提交到總線驅動程序就可以完成硬件操作,USBD.SYS是接受URB的實體,向USBD的調用被轉化爲帶有主功能代碼爲IRP_MJ_XXX的IRP。然後USBD再調度總線時間,發出URB中指定的操作。 創建一個URB是USB驅動最基本的工作,首先應該爲URB分配內存,然後調用初始化例程把URB結構中的各個域填入請求要求的內容。最後通過創建併發送一個內部I/O控制(IOCTL)請求到USBD驅動程序來發送這個URB包,從而完成USB請求。 2)創建併發送IOCTL請求 創建完URB後,我們創建併發送一個IOCTL(內部I/O控制)請求到USBD,然後等待設備迴應,相應的函數爲SendAwaitUrb 3) 返回設備完成狀態 |