📄 hidmdd.cpp
字号:
// Set idle rate
DEBUGCHK(pHidContext->hidpDeviceDesc.ReportIDs != NULL);
for (dwIdx = 0; dwIdx < pHidContext->hidpDeviceDesc.ReportIDsLength; ++dwIdx) {
PHIDP_REPORT_IDS phidpReport = &pHidContext->hidpDeviceDesc.ReportIDs[dwIdx];
if (phidpReport->CollectionNumber == dwCollection) {
// This report falls under this collection.
DEBUGMSG(ZONE_COMMENT, (_T("%s: Setting report %u to idle rate of %u\r\n"),
pszFname, phidpReport->ReportID, dwDuration));
dwErr = HidPdd_SetIdle(pHidContext->hPddDevice,
dwDuration, phidpReport->ReportID);
if (dwErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARNING,
(_T("%s: Unable to set idle rate for device\r\n"),
pszFname));
}
}
}
}
}
// Load a HID client for each top level collection, if possible.
// Returns FALSE if there was a major error. Returns TRUE even
// if certain TLC's do not have clients. This is not an error
// because internal processing will still be performed on unhandled
// reports (like power events).
static
BOOL
LoadHidClients(
PHID_CONTEXT pHidContext,
DWORD dwVendorId,
DWORD dwProductId,
DWORD dwReleaseNumber,
DWORD dwInterface
)
{
SETFNAME(_T("LoadHidClients"));
BOOL fRet = FALSE;
DWORD cCollections;
DWORD dwIdx;
DWORD dwType;
LONG iErr;
HID_DRIVER_SETTINGS driverSettings;
PREFAST_DEBUGCHK(pHidContext != NULL);
ValidateHidContext(pHidContext);
// Initially set all reports on the interface to infinite idle
DEBUGMSG(ZONE_COMMENT, (_T("%s: Setting all reports to infinite idle\r\n"),
pszFname));
HidPdd_SetIdle(pHidContext->hPddDevice, 0, 0);
cCollections = pHidContext->hidpDeviceDesc.CollectionDescLength;
driverSettings.dwVendorId = dwVendorId;
driverSettings.dwProductId = dwProductId;
driverSettings.dwReleaseNumber = dwReleaseNumber;
driverSettings.dwInterfaceNumber = dwInterface;
for (dwIdx = 0; dwIdx < cCollections; ++dwIdx)
{
PHIDP_COLLECTION_DESC pCollection = &pHidContext->hidpDeviceDesc.CollectionDesc[dwIdx];
PHID_CLIENT_HANDLE pClientHandle = &pHidContext->pClientHandles[dwIdx];
TCHAR szBuf[MAX_PATH];
DWORD cchBuf = dim(szBuf);
HKEY hKey;
HKEY hSubKey = NULL;
HINSTANCE hInst = NULL;
LPHID_CLIENT_ATTACH pfnAttach;
BOOL fSuccess = FALSE;
DEBUGCHK(pClientHandle->hInst == NULL);
DEBUGCHK(pClientHandle->pQueue != NULL);
driverSettings.dwCollection = pCollection->CollectionNumber;
driverSettings.dwUsagePage = pCollection->UsagePage;
driverSettings.dwUsage = pCollection->Usage;
hKey = FindClientRegKey(&driverSettings, &pClientHandle->driverSettings);
if (hKey == NULL) {
// No match for top level collection. Just continue.
goto CONTINUE;
}
iErr = RegEnumKeyEx(hKey, 0, szBuf, &cchBuf, NULL, NULL, NULL, NULL);
if (iErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Could not enumerate subkey of LoadClient key. Error %i\r\n"),
pszFname, iErr));
goto CONTINUE;
}
iErr = RegOpenKey(hKey, szBuf, &hSubKey);
if (iErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Could not open subkey \"%s\"of LoadClient key. Error %i\r\n"),
pszFname, szBuf, iErr));
goto CONTINUE;
}
// ** At this point we have our client key **
// Set various device features.
SetRemoteWakeup(pHidContext, hSubKey);
SetIdleRate(pHidContext, hSubKey, pCollection->CollectionNumber);
cchBuf = dim(szBuf);
iErr = RegQueryValueEx(hSubKey, DLL_VALUE_SZ, NULL, &dwType,
(PBYTE) szBuf, &cchBuf);
if (iErr != ERROR_SUCCESS || dwType != REG_SZ) {
DEBUGMSG(ZONE_ERROR, (_T("s: Could not get %s value in LoadClient key.\r\n"),
pszFname, DLL_VALUE_SZ));
goto CONTINUE;
}
szBuf[dim(szBuf) - 1] = 0; // Force NULL-termination.
hInst = LoadDriver(szBuf);
if (hInst == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Could not load client DLL %s\r\n"),
pszFname, szBuf));
goto CONTINUE;
}
pfnAttach = (LPHID_CLIENT_ATTACH) GetProcAddress(hInst, SZ_HID_CLIENT_ATTACH);
if (pfnAttach == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Could not get the address of %s from %s\r\n"),
pszFname, SZ_HID_CLIENT_ATTACH, szBuf));
goto CONTINUE;
}
__try {
fSuccess = (*pfnAttach)(
(HID_HANDLE) pClientHandle,
&g_HidFuncs,
&pClientHandle->driverSettings,
pCollection->PreparsedData,
&pClientHandle->lpvNotifyParameter,
0);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Exception in attach procedure %s in %s\r\n"),
pszFname, SZ_HID_CLIENT_ATTACH, szBuf));
}
if (fSuccess != TRUE) {
DEBUGMSG(ZONE_INIT, (_T("%s: Failure in attach procedure %s in %s\r\n"),
pszFname, SZ_HID_CLIENT_ATTACH, szBuf));
goto CONTINUE;
}
// Turn on this client's queue.
pClientHandle->pQueue->AcceptNewReports(TRUE);
// Finally this client has been initialized. Save our hInst.
pClientHandle->hInst = hInst;
CONTINUE:
if (hKey != NULL) RegCloseKey(hKey);
if (hSubKey != NULL) RegCloseKey(hSubKey);
if (pClientHandle->hInst == NULL) {
// We did not successfully initialize the client.
if (hInst != NULL) FreeLibrary(hInst);
DEBUGMSG(ZONE_COMMENT, (_T("%s: No client found for HID top level collection 0x%X-0x%X on interface 0x%X\r\n"),
pszFname, pCollection->UsagePage, pCollection->Usage,
dwInterface));
}
}
fRet = TRUE;
return fRet;
}
// We have data structures for each top level collection. This initializes them.
static
BOOL
InitializeTLCStructures(
PHID_CONTEXT pHidContext
)
{
SETFNAME(_T("InitializeTLCStructures"));
BOOL fRet = FALSE;
DWORD cCollections;
DWORD dwIdx;
PREFAST_DEBUGCHK(pHidContext != NULL);
// Allocate our HID queues. One for each top level collection.
cCollections = pHidContext->hidpDeviceDesc.CollectionDescLength;
pHidContext->pQueues = new HidTLCQueue[cCollections];
if (pHidContext->pQueues == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Memory allocation error\r\n"), pszFname));
goto EXIT;
}
// Allocate our HID client handles. One for each TLC.
pHidContext->pClientHandles = (PHID_CLIENT_HANDLE)
HidAlloc(sizeof(HID_CLIENT_HANDLE) * cCollections);
if (pHidContext->pClientHandles == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: LocalAlloc error:%d\r\n"), pszFname, GetLastError()));
goto EXIT;
}
// Initialize our HID queues and client handles.
for (dwIdx = 0; dwIdx < cCollections; ++dwIdx)
{
BOOL fSucceeded;
PHIDP_COLLECTION_DESC phidpCollection =
&pHidContext->hidpDeviceDesc.CollectionDesc[dwIdx];
PHID_CLIENT_HANDLE pClientHandle = &pHidContext->pClientHandles[dwIdx];
fSucceeded = pHidContext->pQueues[dwIdx].Initialize(
HID_TLC_QUEUE_DEFAULT_CAPACITY,
phidpCollection->InputLength);
if (fSucceeded == FALSE) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Failed initializing queue\r\n"), pszFname));
goto EXIT;
}
pClientHandle->Sig = HID_CLIENT_SIG;
pClientHandle->hInst = NULL;
pClientHandle->lpvNotifyParameter = NULL;
pClientHandle->pHidContext = pHidContext;
pClientHandle->pQueue = &pHidContext->pQueues[dwIdx];
pClientHandle->phidpPreparsedData = phidpCollection->PreparsedData;
}
fRet = TRUE;
EXIT:
return fRet;
}
// Frees the Hid context for a specific PDD-defined device. Calls any
// client's notification routine and releases the library.
//
// Note that synchronization is unnecessary because the only threads
// that will call into the MDD at this point are the client's. We do
// not free the data structures until the client is completely closed.
// If HID_IOControl ever does anything specific to a Hid context, then
// synchronization will need to be added.
static
void
FreeHidContext(
PHID_CONTEXT pHidContext
)
{
SETFNAME(_T("FreeHidContext"));
DWORD cCollections = 0;
DWORD dwIdx;
DEBUGCHK(pHidContext != NULL);
if (VALID_HID_CONTEXT(pHidContext)) {
cCollections = pHidContext->hidpDeviceDesc.CollectionDescLength;
if (pHidContext->pQueues != NULL)
{
// Tell each queue that it is closing.
for (dwIdx = 0; dwIdx < cCollections; ++dwIdx)
{
HidTLCQueue *pQueue = &pHidContext->pQueues[dwIdx];
if (pQueue->IsInitialized() == TRUE) {
pQueue->Close();
}
}
}
if (pHidContext->pClientHandles != NULL) {
// Notify each client that its device has been removed.
for (dwIdx = 0; dwIdx < cCollections; ++dwIdx) {
PHID_CLIENT_HANDLE pHidClient = &pHidContext->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,(_T("%s: Exception in notification proc\r\n"),
pszFname));
}
}
FreeLibrary(pHidClient->hInst);
}
}
HidFree(pHidContext->pClientHandles);
}
if (pHidContext->pQueues != NULL) delete [] pHidContext->pQueues;
HidP_FreeCollectionDescription(&pHidContext->hidpDeviceDesc);
HidFree(pHidContext);
}
else {
DEBUGMSG(ZONE_ERROR, (_T("%s: Invalid Parameter\r\n"), pszFname));
DEBUGCHK(FALSE);
}
}
// Determine the length of the longest input report.
static
BOOL
DetermineMaxInputReportLength(
PHIDP_DEVICE_DESC phidpDeviceDesc,
PDWORD pcbMaxReport
)
{
PREFAST_DEBUGCHK(phidpDeviceDesc);
PREFAST_DEBUGCHK(pcbMaxReport);
*pcbMaxReport = 0;
for (DWORD dwReport = 0; dwReport < phidpDeviceDesc->ReportIDsLength; ++dwReport) {
PHIDP_REPORT_IDS phidpReportIds = &phidpDeviceDesc->ReportIDs[dwReport];
*pcbMaxReport = max(*pcbMaxReport, phidpReportIds->InputLength);
}
return TRUE;
}
// Called with that report descriptor and ID structure of a newly-connected
// device.
BOOL
WINAPI
HidMdd_Attach(
HID_PDD_HANDLE hPddDevice,
PHIDP_REPORT_DESCRIPTOR pbReportDescriptor,
DWORD cbReportDescriptor,
DWORD dwVendorId,
DWORD dwProductId,
DWORD dwReleaseNumber,
DWORD dwInterface,
PVOID *ppvNotifyParameter,
PDWORD pcbMaxInputReport
)
{
SETFNAME(_T("HidMdd_Attach"));
BOOL fRet = FALSE;
PHID_CONTEXT pHidContext = NULL;
NTSTATUS status;
DEBUGMSG(ZONE_INIT, (_T("+%s"), pszFname));
DEBUGCHK(pbReportDescriptor != NULL);
PREFAST_DEBUGCHK(ppvNotifyParameter != NULL);
PREFAST_DEBUGCHK(pcbMaxInputReport);
DumpHIDReportDescriptor(pbReportDescriptor, cbReportDescriptor);
pHidContext = (PHID_CONTEXT) HidAlloc(sizeof(HID_CONTEXT));
if (pHidContext == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: LocalAlloc error:%d\r\n"), pszFname,
GetLastError()));
goto EXIT;
}
ZeroMemory(pHidContext, sizeof(HID_CONTEXT));
pHidContext->Sig = HID_SIG;
pHidContext->hPddDevice = hPddDevice;
// Now that we've allocated space for it, let's parse the report descriptor.
status = HidP_GetCollectionDescription(
pbReportDescriptor,
cbReportDescriptor,
0,
&pHidContext->hidpDeviceDesc
);
if (NT_SUCCESS(status) == FALSE) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Problem parsing report descriptor Error: 0x%x\r\n"),
pszFname, status));
goto EXIT;
}
DumpHIDDeviceDescription(&pHidContext->hidpDeviceDesc);
// Set up our data structures for each top level collection.
if (InitializeTLCStructures(pHidContext) == FALSE) {
goto EXIT;
}
// Determine how long the longest input report may be.
if ( DetermineMaxInputReportLength(&pHidContext->hidpDeviceDesc,
pcbMaxInputReport) == FALSE ) {
goto EXIT;
}
if (LoadHidClients(pHidContext, dwVendorId, dwProductId,
dwReleaseNumber, dwInterface) == FALSE) {
goto EXIT;
}
*ppvNotifyParameter = (PVOID) pHidContext;
DumpDeviceStrings(pHidContext);
fRet = TRUE;
EXIT:
if (fRet == FALSE) {
if (pHidContext != NULL) {
FreeHidContext(pHidContext);
}
*ppvNotifyParameter = NULL;
}
DEBUGMSG(ZONE_INIT, (_T("-%s"), pszFname));
return fRet;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -