专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »嵌入式开发 » windowsce.net:如何编写Windows CE.net的usb驱动程序(2) »正文

windowsce.net:如何编写Windows CE.net的usb驱动程序(2)

来源: 发布时间:星期五, 2008年12月12日 浏览:48次 评论:0

=tf width="98%" align=center border=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

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: