作者:bjtuzdq
转自:http://blog.csdn.net/bjtuzdq/article/details/3856890
USB鼠标的类的定义如下:
class CMouse
{
public:
CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,
LPCUSB_INTERFACE lpInterface);
~CMouse();
BOOL Initialize();
private:
// 传输完毕调用的回调函数
static DWORD CALLBACK MouseTransferCompleteStub(LPVOID lpvNotifyParameter);
// 中断处理函数
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;
// 数据接受缓冲区。
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;
memset(m_pbDataBuffer, 0, sizeof(m_pbDataBuffer));
}
// 析构函数,用于清除申请的资源。
CMouse::~CMouse()
{
// 通知系统去关闭相关的函数接口。
m_fClosing = TRUE;
// Wake up the connection thread again and give it time to die.
if (m_hEvent != NULL)
{
// 通知关闭数据接受线程。
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鼠标驱动程序
BOOL CMouse::Initialize()
{
LPCUSB_DEVICE lpDeviceInfo = (*m_lpUsbFuncs->lpGetDeviceInfo)(m_hDevice);
// 检测配置:USB鼠标应该只有一个中断管道
if ((m_pInterface->lpEndpoints[0].Descriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_INTERRUPT)
{
RETAILMSG(1,(TEXT("!USBMouse: EP 0 wrong type (%u)!/r/n"),
m_pInterface->lpEndpoints[0].Descriptor.bmAttributes));
return FALSE;
}
DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: EP 0:MaxPacket: %u, Interval: %u/r/n"),
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 pipe/r/n")));
return (FALSE);
}
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hEvent == NULL)
{
RETAILMSG(1,(TEXT("USBMouse: Error on CreateEvent for connect event/r/n")));
return(FALSE);
}
// 创建数据接受线程
m_hThread = CreateThread(0, 0, MouseThreadStub, this, 0, NULL);
if (m_hThread == NULL)
{
RETAILMSG(1,(TEXT("USBMouse: Error on CreateThread/r/n")));
return(FALSE);
}
return(TRUE);
}
// 从USB鼠标设备中读出数据,产生相应的鼠标事件。
BOOL CMouse::SubmitInterrupt()
{
if(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->lpEndpoints[0].Descriptor.wMaxPacketSize,
sizeof(m_pbDataBuffer)),
m_pbDataBuffer,
NULL);
if (m_hInterruptTransfer == NULL)
{
DEBUGMSG(ZONE_ERROR,(L "!USBMouse: Error in IssueInterruptTransfer/r/n"));
return FALSE;
}
else
{
DEBUGMSG(ZONE_TRANSFER,(L"USBMouse::SubmitInterrupt,Transfer:0x%X/r/n",
m_hInterruptTransfer));
}
return 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;
if (!(*m_lpUsbFuncs->lpGetTransferStatus)(m_hInterruptTransfer, &dwBytes,&dwError))
{
DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error in GetTransferStatus(0x%X)/r/n"),
m_hInterruptTransfer));
return FALSE;
}
else
{
DEBUGMSG(ZONE_TRANSFER,(TEXT("USBMouse::HandleInterrupt, hTransfer 0x%X complete (%u bytes, Error:%X)/r/n"),
m_hInterruptTransfer,dwBytes,dwError));
}
if (!SubmitInterrupt())
return FALSE;
if(dwError != USB_NO_ERROR)
{
DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error 0x%X in interrupt transfer/r/n"),dwError));
return TRUE;
}
if(dwBytes < 3)
{
DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Invalid byte cnt %u from interrupt transfer/r/n"),dwBytes));
return TRUE;
}
if(dx || dy)
dwFlags |= MOUSEEVENTF_MOVE;
if(fButton1 != m_fPrevButton1)
{
if(fButton1)
dwFlags |= MOUSEEVENTF_LEFTDOWN;
else
dwFlags |= MOUSEEVENTF_LEFTUP;
}
if(fButton2 != m_fPrevButton2)
{
if(fButton2)
dwFlags |= MOUSEEVENTF_RIGHTDOWN;
else
dwFlags |= MOUSEEVENTF_RIGHTUP;
}
if(fButton3 != m_fPrevButton3)
{
if(fButton3)
dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
else
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));
// 通知系统产生鼠标事件
if (m_fReadyForMouseEvents)
mouse_event(dwFlags, dx, dy, 0, 0);
else
m_fReadyForMouseEvents = IsAPIReady(SH_WMGR);
return TRUE;
}
DWORD CALLBACK CMouse::MouseTransferCompleteStub(LPVOID lpvNotifyParameter)
{
CMouse * pMouse = (CMouse *)lpvNotifyParameter;
return(pMouse->MouseTransferComplete());
}
// 数据传输完毕回调函数
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鼠标线程
DWORD CMouse::MouseThread()
{
DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: Worker thread started/r/n")));
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 complete/r/n")));
// The only time this should happen is if we get an error on the transfer
ASSERT(m_fClosing || (m_hInterruptTransfer == NULL));
break;
}
}
}
RETAILMSG(1,(TEXT("USBMouse: Worker thread exiting/r/n")));
return(0);
}
看到了没有,其实USB的驱动程序编写就这么简单,类似的其他设备,例如打印机设备,就有Bulk OUT PIPE,需要Bulk传输,那就需要了解一下IssueBulkTransfer()的应用。当然如果是开发USB Mass Storage Disk的驱动,那就需要了解更多的协议,例如Bulk-Only Transport协议等。
微软的Windows CE的Platform Build中已经带有USB Printer和USB Mass Storage Disk的驱动的源代码了,好好研究一下,你一定回受益非浅的。