windowsce.net:如何编写Windows CE.net的usb驱动程序(2)来源: 发布时间:星期五, 2008年12月12日 浏览:48次 评论:0
例如我们有个USB Mouse设备设备信息描述如下: Device Descriptor: bcdUSB: 0x0100 bDeviceClass: 0x00 bDeviceSubClass: 0x00 bDeviceProtocol: 0x00 bMaxPacketSize0: 0x08 (8) idVendor: 0x05E3 (Genesys Logic Inc.) idProduct: 0x0001 bcdDevice: 0x0101 iManufacturer: 0x00 iProduct: 0x01 iSerialNumber: 0x00 bNumConfigurations: 0x01 ConnectionStatus: DeviceConnected Current Config value: 0x01 Device Bus Speed: Low Device Address: 0x02 Open Pipes: 1 Endpo Descriptor: bEndpoAddress: 0x81 Transfer Type: Interrupt wMaxPacketSize: 0x0003 (3) bInterval: 0x0A 可以看出上述设备有个中断PIPE包最大值为3可能有人问上述值怎么得到win2k DDK中有个usbview例程编译下将你USB设备插到PC机USB口中运行usbview.exe即可看得相应设备信息 有了这些基本信息就可以编写USB设备了首先声明下下面代码取自微软USB鼠标样本版权归微软所有此处仅仅借用来描述下USB鼠标驱动开发过程读者如需要引用此代码需要得到微软同意 首先必须输出USBD要求三个首先到设备插入到USB端口时USBD会USBDeviceAttach相应代码如下: extern "C" BOOL USBDeviceAttach( USB_HANDLE hDevice, // USB设备句柄 LPCUSB_FUNCS lpUsbFuncs, // USBDI集合 LPCUSB_INTERFACE lpInterface, // 设备接口描述信息 LPCWSTR szUniqueDriverId, // 设备ID描述串 LPBOOL fAcceptControl, // 返回TRUE标识我们可以控制此设备 反之表示不能控制 DWORD dwUnused) { *fAcceptControl = FALSE; // 我们鼠标设备有特定描述信息要检测是否是我们设备 (lpInterface NULL) FALSE; // 打印相关USB设备接口描述信息 DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: DeviceAttach, IF %u, #EP:%u, Class:%u, Sub:%u,Prot:%u\r\n"), lpInterface->Descriptor.bInterfaceNumber,lpInterface->Descriptor.bNumEndpos, lpInterface->Descriptor.bInterfaceClass,lpInterface->Descriptor.bInterfaceSubClass,lpInterface->Descriptor.bInterfaceProtocol)); // 初试数据USB鼠标类产生个接受USB鼠标数据线程 CMouse * pMouse = CMouse(hDevice, lpUsbFuncs, lpInterface); (pMouse NULL) FALSE; (!pMouse->Initialize) { delete pMouse; FALSE; } // 注册个监控USB设备事件回调用于监控USB设备是否已经拔掉 (*lpUsbFuncs->lpRegisterNoticationRoutine)(hDevice, USBDeviceNotications, pMouse); *fAcceptControl = TRUE; TRUE; } 第二个是 USBInstallDriver() 些基本定义如下: const WCHAR gcszRegisterClientDriverId = L"RegisterClientDriverID"; const WCHAR gcszRegisterClientSettings = L"RegisterClientSettings"; const WCHAR gcszUnRegisterClientDriverId = L"UnRegisterClientDriverID"; const WCHAR gcszUnRegisterClientSettings = L"UnRegisterClientSettings"; const WCHAR gcszMouseDriverId = L"Generic_Sample_Mouse_Driver"; 接口如下: extern "C" BOOL USBInstallDriver( LPCWSTR szDriverLibFile) // @parm [IN] - Contains client driver DLL name { BOOL fRet = FALSE; HINSTANCE hInst = LoadLibrary(L"USBD.DLL"); // 注册USB设备信息 (hInst) { LPREGISTER_CLIENT_DRIVER_ID pRegisterId = (LPREGISTER_CLIENT_DRIVER_ID) GetProcAddress(hInst, gcszRegisterClientDriverId); LPREGISTER_CLIENT_SETTINGS pRegisterSettings = (LPREGISTER_CLIENT_SETTINGS) GetProcAddress(hInst, gcszRegisterClientSettings); (pRegisterId && pRegisterSettings) { USB_DRIVER_SETTINGS DriverSettings; DriverSettings.dwCount = (DriverSettings); // 设置我们特定信息 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; // HID DriverSettings.dwInterfaceSubClass = 0x01; // boot device DriverSettings.dwInterfaceProtocol = 0x02; // mouse fRet = (*pRegisterId)(gcszMouseDriverId); (fRet) { fRet = (*pRegisterSettings)(szDriverLibFile, gcszMouseDriverId, NULL, &DriverSettings); (!fRet) { //BUGBUG unregister the Client Driver’s ID } } } { RETAILMSG(1,(TEXT("!USBMouse: Error getting USBD function poers\r\n"))); } FreeLibrary(hInst); } fRet; } 上述代码主要用于产生USB设备驱动需要注册表信息需要注意是:USB设备驱动不使用标准注册表而是使用RegisterClientDriverID()和RegisterClientSettings来注册相应设备信息 另外个是USBUnDriver具体代码如下: extern "C" BOOL USBUnInstallDriver { BOOL fRet = FALSE; HINSTANCE hInst = LoadLibrary(L"USBD.DLL"); (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); (pUnRegisterSettings) { USB_DRIVER_SETTINGS DriverSettings; DriverSettings.dwCount = (DriverSettings); // 必须填入与注册时相同信息 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; // HID DriverSettings.dwInterfaceSubClass = 0x01; // boot device DriverSettings.dwInterfaceProtocol = 0x02; // mouse fRet = (*pUnRegisterSettings)(gcszMouseDriverId, NULL, &DriverSettings); } (pUnRegisterId) { BOOL fRetTemp = (*pUnRegisterId)(gcszMouseDriverId); fRet = fRet ? fRetTemp : fRet; } FreeLibrary(hInst); } fRet; } 此主要用于删除USBInstallDriver时创建注册表信息同样它使用自己接口UnRegisterClientDriverID()和UnRegisterClientSettings()来做相应处理 另外个需要处理注册监控通知USBDeviceNotications(): extern "C" BOOL USBDeviceNotications(LPVOID lpvNotyParameter, DWORD dwCode, LPDWORD * dwInfo1, LPDWORD * dwInfo2, LPDWORD * dwInfo3, LPDWORD * dwInfo4) { CMouse * pMouse = (CMouse *)lpvNotyParameter; switch(dwCode) { USB_CLOSE_DEVICE: //删除相关资源 delete pMouse; TRUE; } FALSE; } USB鼠标类定义如下: CMouse { public: CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs, LPCUSB_INTERFACE lpInterface); ~CMouse; BOOL Initialize; private: // 传输完毕回调 DWORD CALLBACK MouseTransferCompleteStub(LPVOID lpvNotyParameter); // 中断处理 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; // 数据接受缓冲区 BYTE m_pbDataBuffer[8]; }; 具体实现如下: // 构造化时 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; mem(m_pbDataBuffer, 0, (m_pbDataBuffer)); } // 析构用于清除申请资源 CMouse::~CMouse { // 通知系统去关闭相关接口 m_fClosing = TRUE; // Wake up the connection thread again and give it time to die. (m_hEvent != NULL) { // 通知关闭数据接受线程 SetEvent(m_hEvent); (m_hThread != NULL) { DWORD dwWaitReturn; dwWaitReturn = WaitForSingleObject(m_hThread, 1000); (dwWaitReturn != WAIT_OBJECT_0) { TerminateThread(m_hThread, DWORD(-1)); } CloseHandle(m_hThread); m_hThread = NULL; } CloseHandle(m_hEvent); m_hEvent = NULL; } (m_hInterruptTransfer) (*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer); (m_hInterruptPipe) (*m_lpUsbFuncs->lpClosePipe)(m_hInterruptPipe); } // 化USB鼠标驱动 BOOL CMouse::Initialize { LPCUSB_DEVICE lpDeviceInfo = (*m_lpUsbFuncs->lpGetDeviceInfo)(m_hDevice); // 检测配置:USB鼠标应该只有个中断管道 ((m_pInterface->lpEndpos[0].Descriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_INTERRUPT) { RETAILMSG(1,(TEXT("!USBMouse: EP 0 wrong type (%u)!\r\n"), m_pInterface->lpEndpos[0].Descriptor.bmAttributes)); FALSE; } DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: EP 0:MaxPacket: %u, Interval: %u\r\n"), m_pInterface->lpEndpos[0].Descriptor.wMaxPacketSize, m_pInterface->lpEndpos[0].Descriptor.bInterval)); m_hInterruptPipe = (*m_lpUsbFuncs->lpOpenPipe)(m_hDevice, &m_pInterface->lpEndpos[0].Descriptor); (m_hInterruptPipe NULL) { RETAILMSG(1,(TEXT("Mouse: Error opening errupt pipe\r\n"))); (FALSE); } m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); (m_hEvent NULL) { RETAILMSG(1,(TEXT("USBMouse: Error on CreateEvent for connect event\r\n"))); (FALSE); } // 创建数据接受线程 m_hThread = CreateThread(0, 0, MouseThreadStub, this, 0, NULL); (m_hThread NULL) { RETAILMSG(1,(TEXT("USBMouse: Error on CreateThread\r\n"))); (FALSE); } (TRUE); } // 从USB鼠标设备中读出数据产生相应鼠标事件 BOOL CMouse::SubmitInterrupt { (m_hInterruptTransfer) (*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer); // 从USB鼠标PIPE中读数据 m_hInterruptTransfer = (*m_lpUsbFuncs->lpIssueInterruptTransfer) (m_hInterruptPipe, MouseTransferCompleteStub, this, USB_IN_TRANSFER | USB_SHORT_TRANSFER_OK, // 表示读数据 min(m_pInterface->lpEndpos[0].Descriptor.wMaxPacketSize, (m_pbDataBuffer)), m_pbDataBuffer, NULL); (m_hInterruptTransfer NULL) { DEBUGMSG(ZONE_ERROR(L "!USBMouse: Error in IssueInterruptTransfer\r\n")); FALSE; } { DEBUGMSG(ZONE_TRANSFER,(L"USBMouse::SubmitInterrupt,Transfer:0x%X\r\n", m_hInterruptTransfer)); } TRUE; } // 处理鼠标中断传输数据 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; (!(*m_lpUsbFuncs->lpGetTransferStatus)(m_hInterruptTransfer, &dwBytes,&dwError)) { DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error in GetTransferStatus(0x%X)\r\n"), m_hInterruptTransfer)); FALSE; } { DEBUGMSG(ZONE_TRANSFER,(TEXT("USBMouse::HandleInterrupt, hTransfer 0x%X complete (%u s, Error:%X)\r\n"), m_hInterruptTransfer,dwBytes,dwError)); } (!SubmitInterrupt) FALSE; (dwError != USB_NO_ERROR) { DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error 0x%X in errupt transfer\r\n"),dwError)); TRUE; } (dwBytes < 3) { DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Invalid cnt %u from errupt transfer\r\n"),dwBytes)); TRUE; } (dx || dy) dwFlags |= MOUSEEVENTF_MOVE; (fButton1 != m_fPrevButton1) { (fButton1) dwFlags |= MOUSEEVENTF_LEFTDOWN; dwFlags |= MOUSEEVENTF_LEFTUP; } (fButton2 != m_fPrevButton2) { (fButton2) dwFlags |= MOUSEEVENTF_RIGHTDOWN; dwFlags |= MOUSEEVENTF_RIGHTUP; } (fButton3 != m_fPrevButton3) { (fButton3) dwFlags |= MOUSEEVENTF_MIDDLEDOWN; dwFlags |= 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)\r\n"), dx,dy,dwFlags,fButton1,fButton2,fButton3)); // 通知系统产生鼠标事件 (m_fReadyForMouseEvents) mouse_event(dwFlags, dx, dy, 0, 0); m_fReadyForMouseEvents = IsAPIReady(SH_WMGR); TRUE; } DWORD CALLBACK CMouse::MouseTransferCompleteStub(LPVOID lpvNotyParameter) { CMouse * pMouse = (CMouse *)lpvNotyParameter; (pMouse->MouseTransferComplete); } // 数据传输完毕回调 DWORD CMouse::MouseTransferComplete { (m_hEvent) SetEvent(m_hEvent); 0; } ULONG CALLBACK CMouse::MouseThreadStub(PVOID context) { CMouse * pMouse = (CMouse *)context; (pMouse->MouseThread); } // USB鼠标线程 DWORD CMouse::MouseThread { DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: Worker thread started\r\n"))); SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_HIGHEST); (SubmitInterrupt) { while (!m_fClosing) { WaitForSingleObject(m_hEvent, INFINITE); (m_fClosing) ; ((*m_lpUsbFuncs->lpIsTransferComplete)(m_hInterruptTransfer)) { (!HandleInterrupt) ; } { RETAILMSG(1,(TEXT("!USBMouse: Event signalled, but transfer not complete\r\n"))); // The only time this should happen is we get an error on the transfer ASSERT(m_fClosing || (m_hInterruptTransfer NULL)); ; } } } RETAILMSG(1,(TEXT("USBMouse: Worker thread exiting\r\n"))); (0); } 看到了没有其实USB驱动编写就这么简单类似其他设备例如打印机设备就有Bulk OUT PIPE需要Bulk传输那就需要了解下IssueBulkTransfer()应用当然如果是开发USB Mass Storage Disk驱动那就需要了解更多协议例如Bulk-Only Transport协议等 微软Windows CE.NETPlatform Build中已经带有USB Prer和USB Mass Storage Disk驱动源代码了好好研究下你定回受益非浅 参考资料: 1. 微软出版社 <<Windows Ce Device Driver Kit>> 2. <<Universal Serial Bus Specication 1.1>> 来自http:://www.usb.org 0
相关文章
读者评论发表评论 |