新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 如何編寫(xiě)Windows CE.net的usb驅(qū)動(dòng)程序

如何編寫(xiě)Windows CE.net的usb驅(qū)動(dòng)程序

作者: 時(shí)間:2011-02-25 來(lái)源:網(wǎng)絡(luò) 收藏

隨著USB設(shè)備的普及,擺在開(kāi)發(fā)人員面前的驅(qū)動(dòng)開(kāi)發(fā)任務(wù)也是越來(lái)越繁重了,特別是對(duì)于一些開(kāi)發(fā)廠(chǎng)商來(lái)講,由于設(shè)備所采用的操作系統(tǒng)不同,相應(yīng)的硬件接口也是不一樣的,開(kāi)發(fā)相關(guān)的USB 驅(qū)動(dòng)程序更是難上加難。Windows CE.NET 是微軟推出的功能強(qiáng)大的操作系統(tǒng),國(guó)內(nèi)采用此操作系統(tǒng)的廠(chǎng)商已經(jīng)很多了,本文就以windows ce.net為例,簡(jiǎn)單介紹一下如何開(kāi)發(fā)windows ce.net下的USB驅(qū)動(dòng)程序。
  首先要熟悉一些USB的基本概念,當(dāng)然最好把USB 1.1的協(xié)議看一遍,(當(dāng)然現(xiàn)在2。0的協(xié)議都已經(jīng)有了)http://www.usb.org上可以下載,我記得好像有個(gè)中文版的,翻譯的還可以,http://www.driverdevolep.com上有的,具體位置記不太清楚了,中文版的協(xié)議可以快速翻一邊,了解一些基本的概念,但是設(shè)計(jì)到一些關(guān)鍵性的東西最好還是看英文版的心里比較清楚些。
  這里我就不介紹USB的基本協(xié)議了,假設(shè)用戶(hù)已經(jīng)熟悉了USB設(shè)備的一些基本的概念,并且對(duì)Winows CE.NET的開(kāi)發(fā)有一定的了解。
  下面簡(jiǎn)略介紹一下Windows CE.NET中USB設(shè)備驅(qū)動(dòng)開(kāi)發(fā)的一些基礎(chǔ)知識(shí)。
  Windows CE.NET 的USB系統(tǒng)軟件分為兩層: USB Client設(shè)備驅(qū)動(dòng)程序和底層的Windows CE實(shí)現(xiàn)的函數(shù)層。USB設(shè)備驅(qū)動(dòng)程序主要負(fù)責(zé)利用系統(tǒng)提供的底層接口配置設(shè)備,和設(shè)備進(jìn)行通訊。底層的函數(shù)提本身又由兩部分組成,通用串行總線(xiàn)驅(qū)動(dòng)程序(USBD)模塊和較低的主控制器驅(qū)動(dòng)程序(HCD)模塊。HCD負(fù)責(zé)最最底層的處理,USBD模塊實(shí)現(xiàn)較高的USBD函數(shù)接口。USB設(shè)備驅(qū)動(dòng)主要利用 USBD接口函數(shù)和他們的外圍設(shè)備打交道。
  USB設(shè)備驅(qū)動(dòng)程序主要和USBD打交道,所以我們必須詳細(xì)的了解USBD提供的函數(shù)。
  主要的傳輸函數(shù)有:
  AbourtTransfer   IssueControlTransferCloseTransfer    IssueInterrupTransferGetIsochResult   IssueIsochTransferGetTransferStatus  IstransferCompleteIssueBulkTransfer  IssueVendorTransfer主要的用于打開(kāi)和關(guān)閉USBD和USB設(shè)備之間的通信通道的函數(shù)有:
  AbortPipeTransfers  ClosePipeIsDefaultPipeHalted  IsPipeHaltedOpenPipe       ResetDefaultPipeResetPipe相應(yīng)的打包函數(shù)接口有:
  GetFrameLength   GetFrameNumber   ReleaseFrameLengthControlSetFrameLength   TakeFrameLengthControl取得設(shè)置設(shè)備配置函數(shù):
  ClearFeature   SetDescriptorGetDescriptor  SetFeatureGetInterface   SetInterfaceGetStatus    SyncFrame與USB進(jìn)行交互的實(shí)現(xiàn)方法相關(guān)的多任務(wù)函數(shù):
  FindInterface         RegisterClientDeviceIdGetDeviceInfo         RegisterClientSettingsGetUSBDVersion         RegisterNotificationRoutineLoadGenericInterfaceDriver   TranslateStringDescrOpenClientRegisterKey     UnRegisterNotificationRoutine常見(jiàn)的Windows CE.NET下USB的設(shè)備驅(qū)動(dòng)程序的編寫(xiě)有以下幾種方法:
  ● 流式接口函數(shù)這種驅(qū)動(dòng)程序主要呈現(xiàn)流式函數(shù)接口,主要輸出XXX_Init,XXX_Deinit,XXX_Open,XXX_Close,XXX_Open,XXX_Close,XXX_Read,XXX_Write,XXX_Seek, XXX_IOControl,XXX_PowerUp,XXX_PowerDown等流式接口,注意上述的幾個(gè)接口一定都要輸出,另外XXX必須為三個(gè)字符,否則會(huì)出錯(cuò)。但是此類(lèi)的驅(qū)動(dòng)程序不是通過(guò)設(shè)備管理接口來(lái)加載的,所以必須手工的調(diào)用RegisterDevice()和 DeregisterDevice()函數(shù)來(lái)加載和卸載驅(qū)動(dòng)程序。用戶(hù)可以將此類(lèi)的設(shè)備作為標(biāo)準(zhǔn)的文件來(lái)操作,只要調(diào)用相應(yīng)的文件操作就可以和驅(qū)動(dòng)程序打交道。
  ● 使用現(xiàn)有的Window CE.NET的應(yīng)用程序接口此類(lèi)設(shè)備主要是利用Windows CE.NET中已經(jīng)有了現(xiàn)成的函數(shù)接口,例如USB Mass Storage Disk,它主要利用現(xiàn)有的Windows CE.Net中已經(jīng)有的可安裝文件系統(tǒng)接口,呈現(xiàn)給系統(tǒng)可用的文件系統(tǒng),對(duì)于用戶(hù)來(lái)講,它是透明的,用戶(hù)僅僅感覺(jué)在操作一個(gè)文件夾。
  ● 創(chuàng)建指定到特定的USBD的用戶(hù)指定的API這種方法在USBD呈現(xiàn)設(shè)備時(shí)不需要任何限制,主要是特制的提供API給用戶(hù),一般不太常見(jiàn)。
  USB設(shè)備驅(qū)動(dòng)程序必須輸出的函數(shù)有:
  ● USBDeviecAttach當(dāng)USB設(shè)備連接到計(jì)算機(jī)上時(shí),USBD模塊就會(huì)調(diào)用此函數(shù),這個(gè)函數(shù)主要用于初始化USB設(shè)備,取得USB設(shè)備信息,配置USB設(shè)備,并且申請(qǐng)必需的資源。
  ● USBInstallDriver主要用于創(chuàng)建一個(gè)驅(qū)動(dòng)程序加載所需的注冊(cè)表信息,例如讀寫(xiě)超時(shí),設(shè)備名稱(chēng)等。
  ● USBUninstallDriver主要用于釋放驅(qū)動(dòng)程序所占用的資源,以及刪除USBInstallDriver函數(shù)創(chuàng)建的注冊(cè)表等。
  上述的三個(gè)函數(shù)接口是所有的USB驅(qū)動(dòng)程序必須提供的,缺一不可。
  另外比較重要的是USB設(shè)備驅(qū)動(dòng)程序的注冊(cè)表配置,一般的USB設(shè)備驅(qū)動(dòng)程序的注冊(cè)表配置在HKEY_LOCAL_MACHINEDriversUSB LoadClients下,每個(gè)驅(qū)動(dòng)程序的子鍵都有Group1_IDGroup2_IDGroup3_IDDriverName格式,如果注冊(cè)表信息與USB設(shè)備信息符合,USBD就會(huì)加載此驅(qū)動(dòng)程序。否則設(shè)備的子鍵應(yīng)該由供應(yīng)商,設(shè)備類(lèi)和協(xié)議信息通過(guò)下劃線(xiàn)組成。
  具體的配置舉個(gè)例子:
  例如你有個(gè)PDA設(shè)備,它具有一個(gè)USB接口,它的供應(yīng)廠(chǎng)商ID假設(shè)為0x0888,設(shè)備ID為0x0999,沒(méi)有使用特殊的協(xié)議,那么它的加載注冊(cè)表應(yīng)該寫(xiě)為:
  [HKEY_LOCAL_MACHINEDriversUSBLoadClients2184_2457DefaultDefaultPDA] "DLL"="pdausb.dll"需要注意的是注冊(cè)表構(gòu)成都是十進(jìn)制數(shù)值來(lái)標(biāo)識(shí)的,注意一下十進(jìn)制和十六進(jìn)制的轉(zhuǎn)換。
  再舉個(gè)USB鼠標(biāo)的例子,USB鼠標(biāo)是標(biāo)準(zhǔn)的HID設(shè)備,它的協(xié)議為:InterfaceClassCode為3(HID類(lèi)), InterfaceSubclassCode為1(引導(dǎo)接口類(lèi)),InterfaceProtocolCode為2(鼠標(biāo)協(xié)議類(lèi)),所以它的注冊(cè)如下:
  [HKEY_LOCAL_MACHINEDriversUSBLoadClientsDefaultDefault3_1_2USBMouse] "DLL"="usbmouse.dll"到此為止,我們可以看出,其實(shí)驅(qū)動(dòng)開(kāi)發(fā)無(wú)非做兩件事情,一件是和硬件打交道,另外一件是和操作系統(tǒng)打交道。舉個(gè)簡(jiǎn)單的例子,例如:我們需要開(kāi)發(fā)一個(gè)USB鼠標(biāo)驅(qū)動(dòng)程序,我們就需要了解USB鼠標(biāo)硬件上是怎么發(fā)送數(shù)據(jù)的?操作系統(tǒng)怎么才能得到鼠標(biāo)的控制事件?其實(shí)USB鼠標(biāo)是有一個(gè)中斷PIPE的,用于傳送鼠標(biāo)產(chǎn)生的數(shù)據(jù),Windwos CE.NET中有個(gè)接口函數(shù)叫做mouse_event(),專(zhuān)門(mén)用于產(chǎn)生鼠標(biāo)事件,但是它是不關(guān)心具體什么硬件的,甚至我們自己在應(yīng)用程序中調(diào)用這個(gè)函數(shù)都可以實(shí)現(xiàn)模擬鼠標(biāo),對(duì)應(yīng)的有個(gè)keybd_event(),用于產(chǎn)生鍵盤(pán)事件,知道了這個(gè)就好辦多了,只要將相應(yīng)的數(shù)據(jù)轉(zhuǎn)換一下,調(diào)用一下 mouse_event()即可例如我們有個(gè)USB Mouse設(shè)備,設(shè)備信息描述如下:
  Device Descriptor:
  bcdUSB: 0x0100bDeviceClass: 0x00bDeviceSubClass: 0x00bDeviceProtocol: 0x00bMaxPacketSize0: 0x08 (8)idVendor: 0x05E3 (Genesys Logic Inc.)idProduct: 0x0001bcdDevice: 0x0101iManufacturer: 0x00iProduct: 0x01iSerialNumber: 0x00bNumConfigurations: 0x01ConnectionStatus: DeviceConnectedCurrent Config Value: 0x01Device Bus Speed: LowDevice Address: 0x02Open Pipes: 1Endpoint Descriptor:
  bEndpointAddress: 0x81Transfer Type: InterruptwMaxPacketSize: 0x0003 (3)bInterval: 0x0A可以看出上述設(shè)備有一個(gè)中斷PIPE,包的最大值為3??赡苡腥藛?wèn)上述的值怎么得到的,win2k 的DDK中有個(gè)usbview的例程,編譯一下,將你的USB設(shè)備插到PC機(jī)的USB口中,運(yùn)行usbview.exe即可看得相應(yīng)的設(shè)備信息。
  有了這些基本信息,就可以編寫(xiě)USB設(shè)備了,首先聲明一下,下面的代碼取自微軟的USB鼠標(biāo)樣本程序,版權(quán)歸微軟所有,此處僅僅借用來(lái)描述一下USB鼠標(biāo)驅(qū)動(dòng)的開(kāi)發(fā)過(guò)程,讀者如需要引用此代碼,需要得到微軟的同意。
  首先,必須輸出USBD要求調(diào)用的三個(gè)函數(shù),首先到設(shè)備插入到USB端口時(shí),USBD會(huì)調(diào)用USBDeviceAttach()函數(shù),相應(yīng)的代碼如下:
  extern "C" BOOLUSBDeviceAttach(USB_HANDLE hDevice, // USB設(shè)備句柄LPCUSB_FUNCS lpUsbFuncs, // USBDI的函數(shù)集合LPCUSB_INTERFACE lpInterface, // 設(shè)備接口描述信息LPCWSTR szUniqueDriverId, // 設(shè)備ID描述字符串。
  LPBOOL fAcceptControl, // 返回TRUE,標(biāo)識(shí)我們可以控制此設(shè)備, 反之表示不能控制DWORD dwUnused){*fAcceptControl = FALSE;// 我們的鼠標(biāo)設(shè)備有特定的描述信息,要檢測(cè)是否是我們的設(shè)備。
  if (lpInterface == NULL)return FALSE;// 打印相關(guān)的USB設(shè)備接口描述信息。
  DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: DeviceAttach, IF %u, #EP:%u, Class:%u, Sub:%u,Prot:%urn"), lpInterface->Descriptor.bInterfaceNumber,lpInterface->Descriptor.bNumEndpoints, lpInterface->Descriptor.bInterfaceClass,lpInterface->Descriptor.bInterfaceSubClass,lpInterface->Descriptor.bInterfaceProtocol));// 初試數(shù)據(jù)USB鼠標(biāo)類(lèi),產(chǎn)生一個(gè)接受USB鼠標(biāo)數(shù)據(jù)的線(xiàn)程CMouse * pMouse = new CMouse(hDevice, lpUsbFuncs, lpInterface);if (pMouse == NULL)return FALSE;if (!pMouse->Initialize()){delete pMouse;return FALSE;}
  // 注冊(cè)一個(gè)監(jiān)控USB設(shè)備事件的回調(diào)函數(shù),用于監(jiān)控USB設(shè)備是否已經(jīng)拔掉。
  (*lpUsbFuncs->lpRegisterNotificationRoutine)(hDevice,USBDeviceNotifications, pMouse);*fAcceptControl = TRUE;return TRUE;}
  第二個(gè)函數(shù)是 USBInstallDriver()函數(shù),一些基本定義如下:
  const WCHAR gcszRegisterClientDriverId[] = L"RegisterClientDriverID";const WCHAR gcszRegisterClientSettings[] = L"RegisterClientSettings";const WCHAR gcszUnRegisterClientDriverId[] = L"UnRegisterClientDriverID";const WCHAR gcszUnRegisterClientSettmngs[] = L"UnRegisterClientSettings";const WCHAR gcszMouseDriverId[] = L"Generic_Sample_Mouse_Driver";函數(shù)接口如下:
  extern "C" BOOLUSBInstallDriver(LPCWSTR szDriverLibFile) // @parm [IN] - Contains client driver DLL name{BOOL fRet = FALSE;HINSTANCE hInst = LoadLibrary(L"USBD.DLL");// 注冊(cè)USB設(shè)備信息if(hInst){LPREGISTER_CLIENT_DRIVER_ID pRegisterId = (LPREGISTER_CLIENT_DRIVER_ID)GetProcAddress(hInst, gcszRegisterClientDriverId);LPREGISTER_CLIENT_SETTINGS pRegisterSettings =(LPREGISTER_CLIENT_SETTINGS) GetProcAddress(hInst,gcszRegisterClientSettings);if(pRegisterId pRegisterSettings){USB_DRIVER_SETTINGS DriverSettings;DriverSettings.dwCount = sizeof(DriverSettings);// 設(shè)置我們的特定的信息。
  DriverSettings.dwVendorId = USB_NO_INFO;DriverSettings.dwProductId = USB_NO_INFO;DriverSettings.dwReleaseNumber = USB_NO_INFO;DriverSettings.dwDeviceClass = USB_NO_INFO;DriverSettings.dwDeviceSubClass = USB_NO_INFO;DriverSettings.dwDeviceProtocol = USB_NO_INFO;DriverSettings.dwInterfaceClass = 0x03; // HIDDriverSettings.dwInterfaceSubClass = 0x01; // boot deviceDriverSettings.dwInterfaceProtocol = 0x02; // mousefRet = (*pRegisterId)(gcszMouseDriverId);if(fRet){fRet = (*pRegisterSettings)(szDriverLibFile,gcszMouseDriverId, NULL, DriverSettings);if(!fRet){//BUGBUG unregister the Client Driver’s ID}
  }
  }
  else{RETAILMSG(1,(TEXT("!USBMouse: Error getting USBD function pointersrn")));}
  FreeLibrary(hInst);}
  return fRet;}
  上述代碼主要用于產(chǎn)生USB設(shè)備驅(qū)動(dòng)程序需要的注冊(cè)表信息,需要注意的是:USB設(shè)備驅(qū)動(dòng)程序不使用標(biāo)準(zhǔn)的注冊(cè)表函數(shù),而是使用RegisterClientDriverID()和RegisterClientSettings來(lái)注冊(cè)相應(yīng)的設(shè)備信息。
  另外一個(gè)函數(shù)是USBUninstallDriver()函數(shù),具體代碼如下:
  extern "C" BOOLUSBUnInstallDriver(){BOOL fRet = FALSE;HINSTANCE hInst = LoadLibrary(L"USBD.DLL");if(hInst){LPUN_REGISTER_CLIENT_DRIVER_ID pUnRegisterId =(LPUN_REGISTER_CLIENT_DRIVER_ID)GetProcAddress(hInst, gcszUnRegisterClientDriverId);LPUN_REGISTER_CLIENT_SETTINGS pUnRegisterSettings =(LPUN_REGISTER_CLIENT_SETTINGS) GetProcAddress(hInst,gcszUnRegisterClientSettings);if(pUnRegisterSettings){USB_DRIVER_SETTINGS DriverSettings;DriverSettings.dwCount = sizeof(DriverSettings);// 必須填入與注冊(cè)時(shí)相同的信息。
  DriverSettings.dwVendorId = USB_NO_INFO;DriverSettings.dwProductId = USB_NO_INFO;DriverSettings.dwReleaseNumber = USB_NO_INFO;DriverSettings.dwDeviceClass = USB_NO_INFO;DriverSettings.dwDeviceSubClass = USB_NO_INFO;DriverSettings.dwDeviceProtocol = USB_NO_INFO;DriverSettings.dwInterfaceClass = 0x03; // HIDDriverSettings.dwInterfaceSubClass = 0x01; // boot deviceDriverSettings.dwInterfaceProtocol = 0x02; // mousefRet = (*pUnRegisterSettings)(gcszMouseDriverId, NULL,DriverSettings);}
  if(pUnRegisterId){BOOL fRetTemp = (*pUnRegisterId)(gcszMouseDriverId);fRet = fRet ? fRetTemp : fRet;}
  FreeLibrary(hInst);}
  return fRet;}
  此函數(shù)主要用于刪除USBInstallDriver()時(shí)創(chuàng)建的注冊(cè)表信息,同樣的它使用自己的函數(shù)接口UnRegisterClientDriverID()和UnRegisterClientSettings()來(lái)做相應(yīng)的處理。
  另外一個(gè)需要處理的注冊(cè)的監(jiān)控通知函數(shù)USBDeviceNotifications():
  extern "C" BOOL USBDeviceNotifications(LPVOID lpvNotifyParameter, DWORD dwCode,LPDWORD * dwInfo1, LPDWORD * dwInfo2, LPDWORD * dwInfo3,LPDWORD * dwInfo4){CMouse * pMouse = (CMouse *)lpvNotifyParameter;switch(dwCode){case USB_CLOSE_DEVICE:
  //刪除相關(guān)的資源。
  delete pMouse;return TRUE;}
  return FALSE;}
  USB鼠標(biāo)的類(lèi)的定義如下:
  class CMouse{public:
  CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,LPCUSB_INTERFACE lpInterface);~CMouse();BOOL Initialize();private:
  // 傳輸完畢調(diào)用的回調(diào)函數(shù)static DWORD CALLBACK MouseTransferCompleteStub(LPVOID lpvNotifyParameter);// 中斷處理函數(shù)static ULONG CALLBACK CMouse::MouseThreadStub(PVOID context);DWORD MouseTransferComplete();DWORD MouseThread();BOOL SubmitInterrupt();BOOL HandleInterrupt();BOOL m_fClosing;BOOL m_fReadyForMouseEvents;HANDLE m_hEvent;HANDLE m_hThread;USB_HANDLE m_hDevice;USB_PIPE m_hInterruptPipe;USB_TRANSFER m_hInterruptTransfer;LPCUSB_FUNCS m_lpUsbFuncs;LPCUSB_INTERFACE m_pInterface;BOOL m_fPrevButton1;BOOL m_fPrevButton2;BOOL m_fPrevButton3;// 數(shù)據(jù)接受緩沖區(qū)。
  BYTE m_pbDataBuffer[8];};具體實(shí)現(xiàn)如下:
  // 構(gòu)造函數(shù),初始化時(shí)調(diào)用CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,LPCUSB_INTERFACE lpInterface){m_fClosing = FALSE;m_fReadyForMouseEvents = FALSE;m_hEvent = NULL;m_hThread = NULL;m_hDevice = hDevice;m_hInterruptPipe = NULL;m_hInterruptTransfer = NULL;m_lpUsbFuncs = lpUsbFuncs;m_pInterface = lpInterface;m_fPrevButton1 = FALSE;m_fPrevButton2 = FALSE;m_fPrevButton3 = FALSE;memset(m_pbDataBuffer, 0, sizeof(m_pbDataBuffer));}
  // 析構(gòu)函數(shù),用于清除申請(qǐng)的資源。
  CMouse::~CMouse(){// 通知系統(tǒng)去關(guān)閉相關(guān)的函數(shù)接口。
  m_fClosing = TRUE;// Wake up the connection thread again and give it time to die.
  if (m_hEvent != NULL){// 通知關(guān)閉數(shù)據(jù)接受線(xiàn)程。
  SetEvent(m_hEvent);if (m_hThread != NULL){DWORD dwWaitReturn;dwWaitReturn = WaitForSingleObject(m_hThread, 1000);if (dwWaitReturn != WAIT_OBJECT_0){TerminateThread(m_hThread, DWORD(-1));}
  CloseHandle(m_hThread);m_hThread = NULL;}
  CloseHandle(m_hEvent);m_hEvent = NULL;}
  if(m_hInterruptTransfer)(*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer);if(m_hInterruptPipe)(*m_lpUsbFuncs->lpClosePipe)(m_hInterruptPipe);}
  // 初始化USB鼠標(biāo)驅(qū)動(dòng)程序BOOL CMouse::Initialize(){LPCUSB_DEVICE lpDeviceInfo = (*m_lpUsbFuncs->lpGetDeviceInfo)(m_hDevice);// 檢測(cè)配置:USB鼠標(biāo)應(yīng)該只有一個(gè)中斷管道if ((m_pInterface->lpEndpoints[0].Descriptor.bmAttributes USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_INTERRUPT){RETAILMSG(1,(TEXT("!USBMouse: EP 0 wrong type (%u)!rn"),m_pInterface->lpEndpoints[0].Descriptor.bmAttributes));return FALSE;}
  DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: EP 0:MaxPacket: %u, Interval: %urn"),m_pInterface->lpEndpoints[0].Descriptor.wMaxPacketSize,m_pInterface->lpEndpoints[0].Descriptor.bInterval));m_hInterruptPipe = (*m_lpUsbFuncs->lpOpenPipe)(m_hDevice,m_pInterface->lpEndpoints[0].Descriptor);if (m_hInterruptPipe == NULL) {RETAILMSG(1,(TEXT("Mouse: Error opening interrupt pipern")));return (FALSE);}
  m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);if (m_hEvent == NULL){RETAILMSG(1,(TEXT("USBMouse: Error on CreateEvent for connect eventrn")));return(FALSE);}
  // 創(chuàng)建數(shù)據(jù)接受線(xiàn)程m_hThread = CreateThread(0, 0, MouseThreadStub, this, 0, NULL);if (m_hThread == NULL){RETAILMSG(1,(TEXT("USBMouse: Error on CreateThreadrn")));return(FALSE);}
  return(TRUE);}
  // 從USB鼠標(biāo)設(shè)備中讀出數(shù)據(jù),產(chǎn)生相應(yīng)的鼠標(biāo)事件。
  BOOL CMouse::SubmitInterrupt(){if(m_hInterruptTransfer)(*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer);// 從USB鼠標(biāo)PIPE中讀數(shù)據(jù)m_hInterruptTransfer = (*m_lpUsbFuncs->lpIssueInterruptTransfer)(m_hInterruptPipe, MouseTransferCompleteStub, this,USB_IN_TRANSFER | USB_SHORT_TRANSFER_OK, // 表示讀數(shù)據(jù)min(m_pInterface->lpEndpoints[0].Descriptor.wMaxPacketSize,sizeof(m_pbDataBuffer)),m_pbDataBuffer,NULL);if (m_hInterruptTransfer == NULL){DEBUGMSG(ZONE_ERROR,(L "!USBMouse: Error in IssueInterruptTransferrn"));return FALSE;}
  else{DEBUGMSG(ZONE_TRANSFER,(L"USBMouse::SubmitInterrupt,Transfer:0x%Xrn",m_hInterruptTransfer));}
  return TRUE;}
  // 處理鼠標(biāo)中斷傳輸?shù)臄?shù)據(jù)BOOL CMouse::HandleInterrupt(){DWORD dwError;DWORD dwBytes;DWORD dwFlags = 0;INT dx = (signed char)m_pbDataBuffer[1];INT dy = (signed char)m_pbDataBuffer[2];BOOL fButton1 = m_pbDataBuffer[0] 0x01 ? TRUE : FALSE;BOOL fButton2 = m_pbDataBuffer[0] 0x02 ? TRUE : FALSE;BOOL fButton3 = m_pbDataBuffer[0] 0x04 ? TRUE : FALSE;if (!(*m_lpUsbFuncs->lpGetTransferStatus)(m_hInterruptTransfer, dwBytes,dwError)){DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error in GetTransferStatus(0x%X)rn"),m_hInterruptTransfer));return FALSE;}
  else{DEBUGMSG(ZONE_TRANSFER,(TEXT("USBMouse::HandleInterrupt, hTransfer 0x%X complete (%u bytes, Error:%X)rn"),m_hInterruptTransfer,dwBytes,dwError));}
  if (!SubmitInterrupt())return FALSE;if(dwError != USB_NO_ERROR){DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error 0x%X in interrupt transferrn"),dwError));return TRUE;}
  if(dwBytes 3){DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Invalid byte cnt %u from interrupt transferrn"),dwBytes));return TRUE;}
  if(dx || dy)dwFlags |= MOUSEEVENTF_MOVE;if(fButton1 != m_fPrevButton1){if(fButton1)dwFlags |= MOUSEEVENTF_LEFTDOWN;elsedwFlags |= MOUSEEVENTF_LEFTUP;}
  if(fButton2 != m_fPrevButton2){if(fButton2)dwFlags |= MOUSEEVENTF_RIGHTDOWN;elsedwFlags |= MOUSEEVENTF_RIGHTUP;}
  if(fButton3 != m_fPrevButton3){if(fButton3)dwFlags |= MOUSEEVENTF_MIDDLEDOWN;elsedwFlags |= MOUSEEVENTF_MIDDLEUP;}
  m_fPrevButton1 = fButton1;m_fPrevButton2 = fButton2;m_fPrevButton3 = fButton3;DEBUGMSG(ZONE_EVENTS,(TEXT("USBMouse event: dx:%d, dy:%d, dwFlags:0x%X (B1:%u, B2:%u, B3:%u)rn"),dx,dy,dwFlags,fButton1,fButton2,fButton3));// 通知系統(tǒng)產(chǎn)生鼠標(biāo)事件if (m_fReadyForMouseEvents)mouse_event(dwFlags, dx, dy, 0, 0);elsem_fReadyForMouseEvents = IsAPIReady(SH_WMGR);return TRUE;}
  DWORD CALLBACK CMouse::MouseTransferCompleteStub(LPVOID lpvNotifyParameter){CMouse * pMouse = (CMouse *)lpvNotifyParameter;return(pMouse->MouseTransferComplete());}
  // 數(shù)據(jù)傳輸完畢回調(diào)函數(shù)DWORD CMouse::MouseTransferComplete(){if (m_hEvent)SetEvent(m_hEvent);return 0;}
  ULONG CALLBACK CMouse::MouseThreadStub(PVOID context){CMouse * pMouse = (CMouse *)context;return(pMouse->MouseThread());}
  // USB鼠標(biāo)線(xiàn)程DWORD CMouse::MouseThread(){DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: Worker thread startedrn")));SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);if (SubmitInterrupt()){while (!m_fClosing){WaitForSingleObject(m_hEvent, INFINITE);if (m_fClosing)break;if ((*m_lpUsbFuncs->lpIsTransferComplete)(m_hInterruptTransfer)){if (!HandleInterrupt())break;}
  else{RETAILMSG(1,(TEXT("!USBMouse: Event signalled, but transfer not completern")));// The only time this should happen is if we get an error on the transferASSERT(m_fClosing || (m_hInterruptTransfer == NULL));break;}
  }
  }
  RETAILMSG(1,(TEXT("USBMouse: Worker thread exitingrn")));return(0);}
  看到了沒(méi)有,其實(shí)USB的驅(qū)動(dòng)程序編寫(xiě)就這么簡(jiǎn)單,類(lèi)似的其他設(shè)備,例如打印機(jī)設(shè)備,就有Bulk OUT PIPE,需要Bulk傳輸,那就需要了解一下IssueBulkTransfer()的應(yīng)用。當(dāng)然如果是開(kāi)發(fā)USB Mass Storage Disk的驅(qū)動(dòng),那就需要了解更多的協(xié)議,例如Bulk-Only Transport協(xié)議等。
  微軟的Windows CE.NET的Platform Build中已經(jīng)帶有USB Printer和USB Mass Storage Disk的驅(qū)動(dòng)的源代碼了,好好研究一下,你一定回受益非淺的。

linux操作系統(tǒng)文章專(zhuān)題:linux操作系統(tǒng)詳解(linux不再難懂)


評(píng)論


相關(guān)推薦

技術(shù)專(zhuān)區(qū)

關(guān)閉