📄 hid.cpp
字号:
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
hid.cpp
Abstract:
USB Client Driver for Human Interface Device (HID) Class.
Functions:
Notes:
--*/
#include "usbhid.h"
#include "Oemioctl.h"
#pragma warning( disable : 4100 )
#undef DEBUGMSG
#define DEBUGMSG(x,y) NKDbgPrintfW y
#undef SETFNAME
#define SETFNAME(name) LPCTSTR pszFname = (name)
#define GET_HID_DESCRIPTOR_TIMEOUT 2000
// This is only used at initialization so the perf hit
// from a small initial size is negligible.
#define INITIAL_HID_CONTEXT_SIZE 1
// Global HID class data
CRITICAL_SECTION g_csHidLock; // Protects accesses to the following variables
BOOL g_fInitialized; // Has this global data been initialized?
PUSBHID_CONTEXT *g_rgpUsbHid; // Holds information for each HID interface
DWORD g_cpUsbHid; // Count of entries in g_rgpUsbHid
HANDLE g_hOSDevice; // The HID class device (HID0:)
#ifdef DEBUG
INT g_cInHidCS; // The current depth of g_csHidLock
#endif
// List of HID functions. Passed to HID clients.
static const HID_FUNCS g_HidFuncs =
{
sizeof(HID_FUNCS), // DWORD dwCount;
&GetReport,
&SetReport,
&GetInterruptReport,
};
// Helper function to close a pipe structure
static
void
ClosePipe(
LPCUSB_FUNCS pUsbFuncs,
PPIPE pPipe
)
{
DEBUGCHK(pUsbFuncs != NULL);
DEBUGCHK(pPipe != NULL);
if (pPipe->hPipe) {
pUsbFuncs->lpClosePipe(pPipe->hPipe);
}
if (pPipe->hEvent) {
CloseHandle(pPipe->hEvent);
}
}
// Returns the index of the device in the global list. If not found,
// returns g_cpUsbHid.
static
DWORD
FindDeviceInList(
PUSBHID_CONTEXT pUsbHid
)
{
DWORD dwSize, dwIdx;
DEBUGCHK(pUsbHid != NULL);
LockHidData();
dwSize = g_cpUsbHid;
for (dwIdx = 0; dwIdx < dwSize; ++dwIdx) {
if (g_rgpUsbHid[dwIdx] == pUsbHid) {
break;
}
}
ReleaseHidData();
return dwIdx;
}
// Is the device in the global list?
static
BOOL
IsDeviceInList(
PUSBHID_CONTEXT pUsbHid
)
{
DWORD dwIdx, dwSize;
DEBUGCHK(pUsbHid != NULL);
LockHidData();
dwSize = g_cpUsbHid;
dwIdx = FindDeviceInList(pUsbHid);
ReleaseHidData();
NKDbgPrintfW(TEXT("Hid IsDeviceInList:%d\r\n"),dwIdx);
return dwIdx != dwSize;
}
// Removes a device from the global list.
static
void
RemoveDeviceFromList(
PUSBHID_CONTEXT pUsbHid
)
{
SETFNAME(_T("RemoveDeviceFromList"));
DWORD dwIdx;
DEBUGCHK(pUsbHid != NULL);
LockHidData();
DEBUGCHK(g_fInitialized == TRUE);
ValidateHidGlobals();
DEBUGCHK(IsDeviceInList(pUsbHid) == TRUE);
dwIdx = FindDeviceInList(pUsbHid);
DEBUGCHK(dwIdx != g_cpUsbHid);
g_rgpUsbHid[dwIdx] = NULL;
ValidateHidGlobals();
ReleaseHidData();
}
// Frees all device handles and removes it from the global list.
void
RemoveDeviceContext(
PUSBHID_CONTEXT pUsbHid
)
{
SETFNAME(_T("RemoveDeviceContext"));
DWORD cCollections = 0;
DWORD dwIdx;
DEBUGCHK(pUsbHid != NULL);
if (VALID_CONTEXT(pUsbHid)) {
// Remove the device from the list if it is there.
if (IsDeviceInList(pUsbHid) == TRUE) {
RemoveDeviceFromList(pUsbHid);
}
// If nothing else, at least the CS was initialized.
LockHidContext(pUsbHid);
pUsbHid->Flags.UnloadPending = TRUE;
ReleaseHidContext(pUsbHid);
if (pUsbHid->InterruptIn.hPipe != NULL) {
pUsbHid->pUsbFuncs->lpAbortPipeTransfers(pUsbHid->InterruptIn.hPipe, 0);
}
ClosePipe(pUsbHid->pUsbFuncs, &pUsbHid->InterruptIn);
if (pUsbHid->hThread != NULL) {
WaitForSingleObject(pUsbHid->hThread, INFINITE);
CloseHandle(pUsbHid->hThread);
}
if (pUsbHid->phidpDeviceDesc != NULL) {
cCollections = pUsbHid->phidpDeviceDesc->CollectionDescLength;
}
if (pUsbHid->pQueues != NULL)
{
// Tell each queue that it is closing.
for (dwIdx = 0; dwIdx < cCollections; ++dwIdx)
{
HidTLCQueue *pQueue = &pUsbHid->pQueues[dwIdx];
if (pQueue->IsInitialized() == TRUE) {
pQueue->Close();
}
}
}
if (pUsbHid->pClientHandles != NULL) {
// Notify each client that its device has been removed.
for (dwIdx = 0; dwIdx < cCollections; ++dwIdx) {
PHID_CLIENT_HANDLE pHidClient = &pUsbHid->pClientHandles[dwIdx];
if (pHidClient->hInst != NULL) {
LPHID_CLIENT_NOTIFICATIONS lpNotifications;
lpNotifications = (LPHID_CLIENT_NOTIFICATIONS)
GetProcAddress(pHidClient->hInst, SZ_HID_CLIENT_NOTIFICATIONS);
if (lpNotifications == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Could not get client address of %s\r\n"),
pszFname, SZ_HID_CLIENT_NOTIFICATIONS));
}
else
{
__try {
(*lpNotifications)(HID_CLOSE_DEVICE, 0,
pHidClient->lpvNotifyParameter);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_ERROR,(TEXT("%s: Exception in notification proc\r\n"),pszFname));
}
}
FreeLibrary(pHidClient->hInst);
}
}
HidFree(pUsbHid->pClientHandles);
}
if (pUsbHid->pQueues != NULL) delete [] pUsbHid->pQueues;
if (pUsbHid->hEP0Event != NULL) CloseHandle(pUsbHid->hEP0Event);
if (pUsbHid->phidpDeviceDesc != NULL) {
HidP_FreeCollectionDescription(pUsbHid->phidpDeviceDesc);
HidFree(pUsbHid->phidpDeviceDesc);
}
DeleteCriticalSection(&pUsbHid->csLock);
HidFree(pUsbHid);
}
else {
DEBUGMSG(ZONE_ERROR, (TEXT("%s: Invalid Parameter\r\n"), pszFname));
DEBUGCHK(FALSE);
}
}
// Initialize the global data if not already initialized.
BOOL
InitializeGlobalHidData(
)
{
SETFNAME(_T("InitializeGlobalHidData"));
const DWORD cpUsbHid = INITIAL_HID_CONTEXT_SIZE;
const TCHAR * const pszClientKey = CLIENT_REGKEY_SZ;
BOOL fRet = FALSE;
LockHidData();
// Only initialize if we have not done so already.
if (g_fInitialized == FALSE)
{
ValidateHidGlobals();
g_rgpUsbHid = (PUSBHID_CONTEXT*) HidAlloc(HID_ARRAY_BYTE_SIZE(cpUsbHid));
if (g_rgpUsbHid == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: LocalAlloc error:%d\r\n"), pszFname, GetLastError()));
goto EXIT;
}
ZeroMemory(g_rgpUsbHid, HID_ARRAY_BYTE_SIZE(cpUsbHid));
g_cpUsbHid = cpUsbHid;
g_hOSDevice = ActivateDevice(pszClientKey, 0);
if (g_hOSDevice == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Error on ActivateDevice(%s)\r\n"), pszFname, pszClientKey));
goto EXIT;
}
// Finally we are totally initialized
g_fInitialized = TRUE;
}
fRet = TRUE;
EXIT:
if (fRet == FALSE)
{
// Clean up allocated memory.
DEBUGCHK(g_fInitialized == FALSE);
DEBUGCHK(g_hOSDevice == NULL);
if (g_rgpUsbHid != NULL) HidFree(g_rgpUsbHid);
g_rgpUsbHid = NULL;
g_cpUsbHid = 0;
}
NKDbgPrintfW(TEXT("Hid InitializeGlobalHidData Fail\r\n"));
ReleaseHidData();
ValidateHidGlobals();
return fRet;
}
// Frees the global HID data if there are no remaining devices.
void
FreeGlobalHidData(
)
{
DWORD dwSize, dwIdx;
LockHidData();
ValidateHidGlobals();
if (g_fInitialized == TRUE)
{
// Are there any remaining HID devices?
dwSize = g_cpUsbHid;
for (dwIdx = 0; dwIdx < dwSize; ++dwIdx) {
if (g_rgpUsbHid[dwIdx] != NULL) {
break;
}
}
if (dwIdx == dwSize)
{
// No, free all global data.
DeactivateDevice(g_hOSDevice);
g_hOSDevice = NULL;
HidFree(g_rgpUsbHid);
g_rgpUsbHid = NULL;
g_cpUsbHid = 0;
g_fInitialized = FALSE;
}
}
ValidateHidGlobals();
ReleaseHidData();
}
// Returns the interface to use.
LPCUSB_INTERFACE
ParseUsbDescriptors(
USB_HANDLE hUsbDevice,
LPCUSB_FUNCS pUsbFuncs,
LPCUSB_INTERFACE pCurrInterface
)
{
SETFNAME(_T("ParseUsbDescriptors"));
LPCUSB_INTERFACE pHidInterface = NULL;
DEBUGMSG(ZONE_INIT, (_T("+%s"), pszFname));
DEBUGCHK(pUsbFuncs != NULL);
DEBUGCHK(pCurrInterface != NULL);
if (pCurrInterface != NULL)
{
// If loaded as an interface driver, ignore non HID interfaces
if (pCurrInterface->Descriptor.bInterfaceClass != USB_DEVICE_CLASS_HUMAN_INTERFACE) {
DEBUGMSG(ZONE_INIT, (TEXT("%s: DeviceAttach, ignoring non HID interface class %u\r\n"),
pszFname, pCurrInterface->Descriptor.bInterfaceClass));
}
else {
pHidInterface = pCurrInterface;
}
}
DEBUGMSG(ZONE_INIT, (_T("-%s"), pszFname));
return pHidInterface;
}
// Get the report descriptor from the device.
static
BOOL
GetReportDescriptor(
PUSBHID_CONTEXT pUsbHid,
USHORT uReportDescriptorLength
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -