📄 hidmdd.cpp
字号:
}
// Notifies the MDD of device changes.
BOOL
WINAPI
HidMdd_Notifications(
DWORD dwMsg,
WPARAM wParam,
PVOID pvNotifyParameter
)
{
SETFNAME(_T("HidMdd_Notifications"));
BOOL fRet = FALSE;
PHID_CONTEXT pHidContext = (PHID_CONTEXT) pvNotifyParameter;
UNREFERENCED_PARAMETER(wParam);
ValidateHidContext(pHidContext);
switch(dwMsg) {
case HID_MDD_CLOSE_DEVICE:
FreeHidContext(pHidContext);
fRet = TRUE;
break;
default:
DEBUGMSG(ZONE_ERROR, (_T("%s: Unhandled message %u\r\n"), pszFname));
break;
};
return fRet;
}
// Return a report descriptor given the ID.
static
PHIDP_REPORT_IDS
GetReportDesc(
PHIDP_DEVICE_DESC phidpDeviceDesc,
DWORD dwReportID
)
{
PHIDP_REPORT_IDS pReport = NULL;
DWORD dwIdx;
PREFAST_DEBUGCHK(phidpDeviceDesc != NULL);
DEBUGCHK(phidpDeviceDesc->ReportIDs != NULL);
for (dwIdx = 0; dwIdx < phidpDeviceDesc->ReportIDsLength; ++dwIdx)
{
PHIDP_REPORT_IDS pCurrReport = &phidpDeviceDesc->ReportIDs[dwIdx];
PREFAST_DEBUGCHK(pCurrReport != NULL);
if (pCurrReport->ReportID == dwReportID) {
pReport = pCurrReport;
break;
}
}
DEBUGCHK(pReport != NULL);
return pReport;
}
// Return a collection decriptor given the collection number. Also returns the
// index of the collection in the device context's array.
static
PHIDP_COLLECTION_DESC
GetCollectionDesc(
PHIDP_DEVICE_DESC phidpDeviceDesc,
DWORD dwCollectionNumber,
PDWORD pdwCollectionIndex
)
{
PHIDP_COLLECTION_DESC pColl = NULL;
DWORD dwIdx;
PREFAST_DEBUGCHK(phidpDeviceDesc != NULL);
DEBUGCHK(phidpDeviceDesc->CollectionDesc != NULL);
for (dwIdx = 0; dwIdx < phidpDeviceDesc->CollectionDescLength; ++dwIdx)
{
PHIDP_COLLECTION_DESC pCurrColl = &phidpDeviceDesc->CollectionDesc[dwIdx];
PREFAST_DEBUGCHK(pCurrColl != NULL);
if (pCurrColl->CollectionNumber == dwCollectionNumber) {
pColl = pCurrColl;
break;
}
}
DEBUGCHK(pColl != NULL);
if (pdwCollectionIndex != NULL) {
*pdwCollectionIndex = dwIdx;
}
return pColl;
}
// If this report includes power events, perform them.
static
void
PerformPowerEvents(
PHIDP_COLLECTION_DESC phidpCollection,
BYTE *pbHidPacket,
DWORD cbHidPacket
)
{
SETFNAME(_T("PerformPowerEvents"));
NTSTATUS status;
ULONG uPowerEvents = 0;
PREFAST_DEBUGCHK(phidpCollection != NULL);
DEBUGCHK(pbHidPacket != NULL);
status = HidP_SysPowerEvent((PCHAR) pbHidPacket, (USHORT) cbHidPacket,
phidpCollection->PreparsedData, &uPowerEvents);
if (NT_SUCCESS(status))
{
DEBUGMSG(ZONE_HID_DATA, (_T("%s: Received power event 0x%08x\r\n"),
pszFname, uPowerEvents));
if ((uPowerEvents & (SYS_BUTTON_SLEEP | SYS_BUTTON_POWER)) != 0) {
SetSystemPowerState(NULL, POWER_STATE_SUSPEND, FALSE);
}
}
}
// Called by the PDD when a new report arrives. The report is supplied
// in its raw format (ie. the report ID of 0 is not prepended).
DWORD
WINAPI
HidMdd_ProcessInterruptReport(
PBYTE pData,
DWORD cbData,
PVOID pvNotifyParameter
)
{
SETFNAME(_T("HidMdd_ProcessInterruptReport"));
PHID_CONTEXT pHidContext = (PHID_CONTEXT) pvNotifyParameter;
PHIDP_REPORT_IDS phidpReport;
PHIDP_COLLECTION_DESC phidpCollection;
DWORD dwReportID;
DWORD dwCollectionIndex;
PHID_CLIENT_HANDLE pClientHandle;
HidTLCQueue *pQueue;
DWORD dwRet = ERROR_INVALID_PARAMETER;
PREFAST_DEBUGCHK(pData != NULL);
ValidateHidContext(pHidContext);
if (pHidContext->hidpDeviceDesc.ReportIDs[0].ReportID == 0) {
// The report ID is not returned in this report
dwReportID = 0;
}
else {
// We got a report ID.
dwReportID = *pData;
}
// Get the report and collection data structures
phidpReport = GetReportDesc(&pHidContext->hidpDeviceDesc, dwReportID);
if (phidpReport != NULL) {
phidpCollection = GetCollectionDesc(&pHidContext->hidpDeviceDesc,
phidpReport->CollectionNumber, &dwCollectionIndex);
if (phidpCollection != NULL) {
DEBUGCHK(dwCollectionIndex < pHidContext->hidpDeviceDesc.CollectionDescLength);
OutputReport(pData, cbData, dwReportID, phidpCollection->UsagePage,
phidpCollection->Usage);
// Perform any power events listed in this report
PerformPowerEvents(phidpCollection, pData, cbData);
// Send this HID packet to the proper client
pClientHandle = &pHidContext->pClientHandles[dwCollectionIndex];
// Only queue this report if we have a client that will receive it.
if (pClientHandle->hInst != NULL)
{
pQueue = pClientHandle->pQueue;
pQueue->Lock();
if (pQueue->IsAccepting() == TRUE) {
if (pQueue->IsFull() == FALSE) {
BOOL fRet;
fRet = pQueue->Enqueue((PCHAR) pData, cbData, dwReportID);
DEBUGCHK(fRet);
}
else {
DEBUGMSG(ZONE_ERROR,
(_T("%s: Error: Queue is full. Dropping packet.\r\n"), pszFname));
}
}
else {
DEBUGMSG(ZONE_HID_DATA,
(_T("%s: Queue not accepting input. Dropping packet.\r\n"), pszFname));
}
pQueue->Unlock();
}
dwRet = ERROR_SUCCESS;
}
}
DEBUGMSG(ZONE_ERROR && dwRet != ERROR_SUCCESS,
(_T("%s: Error: Received an invalid report.\r\n"), pszFname));
return dwRet;
}
#define HID_DEVICE_CONTEXT_HANDLE 0xCAFE
#ifdef DEBUG
static DWORD g_dwInitCount = 0;
#endif
// Called by the PDD during XXX_Init. The PDD is responsible for
// making sure the return value is stored and passed into
// HidMdd_Deinit.
DWORD
WINAPI
HidMdd_Init (
LPCWSTR lpszDevKey
)
{
DEBUGCHK(lpszDevKey);
#ifdef DEBUG
// Be sure that only one instance of this DLL is initialized.
DEBUGCHK(g_dwInitCount == 0);
++g_dwInitCount;
#endif
return HID_DEVICE_CONTEXT_HANDLE;
}
// Called by the PDD during XXX_Deinit. The PDD is responsible for
// making sure dwContext is the same value returned from
// HidMdd_Init.
BOOL
WINAPI
HidMdd_Deinit(
DWORD dwContext
)
{
#ifdef DEBUG
// Be sure that only one instance of this DLL is initialized.
DEBUGCHK(g_dwInitCount == 1);
--g_dwInitCount;
#endif
DEBUGCHK(dwContext == HID_DEVICE_CONTEXT_HANDLE);
return TRUE;
}
// Called by the PDD during XXX_Open. The PDD is responsible for
// making sure the return value is stored and passed into
// HidMdd_Close.
DWORD
WINAPI
HidMdd_Open(
DWORD dwContext,
DWORD dwAccMode,
DWORD dwShrMode
)
{
DEBUGCHK(dwContext == HID_DEVICE_CONTEXT_HANDLE);
return HID_DEVICE_CONTEXT_HANDLE;
}
// Called by the PDD during XXX_Close. The PDD is responsible for
// making sure dwContext is the same value returned from
// HidMdd_Open.
BOOL
WINAPI
HidMdd_Close(
DWORD dwContext
)
{
DEBUGCHK(dwContext == HID_DEVICE_CONTEXT_HANDLE);
return TRUE;
}
// Called by the PDD during XXX_IOControl. The PDD is responsible for
// making sure dwContext is the same value returned from
// HidMdd_Open.
//
// IOCTLs with a Function value between 0x300 and 0x3FF are reserved
// for the MDD.
BOOL
WINAPI
HidMdd_IOControl(
DWORD dwContext,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned
)
{
return ERROR_NOT_SUPPORTED;
}
// Called by the PDD from its DLL entry function. This allows the MDD
// to initialize any MDD global variables.
BOOL
WINAPI
HidMdd_DllEntry(
DWORD dwReason
)
{
switch (dwReason) {
case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&g_csHidRefCount);
break;
case DLL_PROCESS_DETACH:
DeleteCriticalSection(&g_csHidRefCount);
break;
}
return TRUE;
}
// The Init entry point for the public interface to the driver.
// Its only purpose is to keep a reference count so that the underlying
// named stream interface is only activated one time.
// dwClientInfo should be the registry path to the stream driver to load.
extern "C"
DWORD Init(
LPCWSTR lpszDevKey,
DWORD dwClientInfo
)
{
TCHAR szHidDriverKey[DEVKEY_LEN];
DWORD dwRet = 0;
DWORD dwErr = ERROR_SUCCESS;
EnterCriticalSection(&g_csHidRefCount);
LPCTSTR pszHidDriverKey = (LPCTSTR) dwClientInfo;
if (pszHidDriverKey == NULL) {
dwErr = ERROR_INVALID_PARAMETER;
goto EXIT;
}
BOOL fException = FALSE;
__try {
_tcsncpy(szHidDriverKey, pszHidDriverKey, dim(szHidDriverKey) - 1);
szHidDriverKey[dim(szHidDriverKey) - 1] = 0; // Force null-termination
}
__except(EXCEPTION_EXECUTE_HANDLER) {
fException = TRUE;
}
if (fException) {
dwErr = ERROR_INVALID_PARAMETER;
goto EXIT;
}
if (g_dwHidRefCount == 0) {
DEBUGCHK(g_hMainHidDriver == NULL);
g_hMainHidDriver = ActivateDeviceEx(szHidDriverKey, NULL, 0, NULL);
if (g_hMainHidDriver == NULL) {
dwErr = ERROR_DEVICE_NOT_AVAILABLE;
}
}
dwRet = (DWORD) g_hMainHidDriver;
EXIT:
if (dwErr != ERROR_SUCCESS) {
SetLastError(dwErr);
DEBUGCHK(dwRet == 0);
}
else {
DEBUGCHK(dwRet != 0);
++g_dwHidRefCount;
}
LeaveCriticalSection(&g_csHidRefCount);
return dwRet;
}
// The Init entry point for the public interface to the driver.
// Its only purpose is to keep a reference count so that the underlying
// named stream interface is only deactivated one time.
extern "C"
BOOL Deinit(DWORD hDeviceContext)
{
EnterCriticalSection(&g_csHidRefCount);
DEBUGCHK(g_dwHidRefCount > 0);
DEBUGCHK(hDeviceContext == (DWORD) g_hMainHidDriver);
--g_dwHidRefCount;
if (g_dwHidRefCount == 0) {
DEBUGCHK(g_hMainHidDriver);
DeactivateDevice(g_hMainHidDriver);
g_hMainHidDriver = NULL;
}
LeaveCriticalSection(&g_csHidRefCount);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -