📄 hidparser.cxx
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#include <windows.h>
#include <pkfuncs.h>
#include <hidpddi.h>
#include "../base/bthidpar.h"
#include "usbhid.h"
#ifdef DEBUG
DBGPARAM dpCurSettings = {
TEXT("BTHHID"), {
TEXT("Errors"), TEXT("Warnings"), TEXT("Init"), TEXT("Function"),
TEXT("HID Data"), TEXT(""), TEXT(""), TEXT(""),
TEXT("USB Parse"), TEXT(""), TEXT(""), TEXT(""),
TEXT(""), TEXT(""), TEXT(""), TEXT("USB Client") },
ZONE_ERROR | ZONE_WARNING };
#endif // DEBUG
// {E5504F26-FEFA-4019-9730-79C6431B5500}
const IID IID_IBTHHIDParser = {0xe5504f26,0xfefa,0x4019,{0x97,0x30,0x79,0xc6,0x43,0x1b,0x55,0x0}};
class IBTHHIDReportHandler;
class BTHHIDPacket;
class BTHHIDParser : public IBTHHIDParser
{
public:
BTHHIDParser(IBTHHIDReportHandler* pReportHandler);
~BTHHIDParser();
// IUnknown overrides
STDMETHOD_(ULONG, AddRef());
STDMETHOD_(ULONG, Release());
STDMETHOD(QueryInterface(REFIID riid, void** ppvObject));
// IBTHHIDParser overrides
BOOL IsInitialized();
int SetReportDescriptor(unsigned char* pReportDescriptor, int cDescriptor);
int ProcessInterruptReport(BYTE* pReport, int cReport);
IBTHHIDReportHandler* GetHandler();
// Debug functions
void ValidateHidContextEx();
static void ValidateClientHandleEx(PHID_CLIENT_HANDLE pHidClient);
private:
int ForceReportProtocol();
int SetIdle();
// Internal initialisation functions
int Initialize(unsigned char* pReportDescriptor, int cDescriptor);
void Deinitialize();
BOOL InitializeTLCStructures();
BOOL LoadHidClients();
// Synchronisation helpers
void LockHidContextEx();
void ReleaseHidContextEx();
// Various helpers
static PHIDP_REPORT_IDS GetReportDesc(PHIDP_DEVICE_DESC phidpDeviceDesc,DWORD dwReportID);
static PHIDP_COLLECTION_DESC GetCollectionDesc(PHIDP_DEVICE_DESC phidpDeviceDesc,DWORD dwCollectionNumber,PDWORD pdwCollectionIndex);
static void PerformPowerEvents(PHIDP_COLLECTION_DESC phidpCollection, BYTE *pbHidPacket, DWORD cbHidPacket);
// Registry utils
static HKEY OpenSpecificClientRegKey(HKEY hKeyRoot, const DWORD *pdwVals, DWORD cdwVals);
static HKEY OpenClientRegKey(
HKEY hKeyRoot,
const DWORD *pdwVendorVals,
DWORD cdwVendorVals,
const DWORD *pdwInterfaceVals,
DWORD cdwInterfaceVals,
const DWORD *pdwTLCVals,
DWORD cdwTLCVals,
PHID_DRIVER_SETTINGS pDriverSettingsUsed);
static HKEY FindClientRegKey(const HID_DRIVER_SETTINGS *pDriverSettings, PHID_DRIVER_SETTINGS pDriverSettingsUsed);
// Private data
BOOL m_fIsInitialized;
IBTHHIDReportHandler* m_pReportHandler;
USBHID_CONTEXT m_UsbHid; // Holds information for one HID interface
int m_cRef; // Uses refcounting to for IUnknown (per instance)
static int m_scRef; // Uses refcounting to activate/deactivate m_hOSDevice (global)
static HANDLE m_hOSDevice; // The HID class device (HID0:)
};
// Public HID functions for clients
DWORD GetReport(HID_HANDLE hDevice, HIDP_REPORT_TYPE type, PCHAR pBuffer, DWORD cbBuffer, PDWORD pcbTransferred, DWORD dwTimeout);
DWORD SetReport(HID_HANDLE hDevice, HIDP_REPORT_TYPE type, PCHAR pBuffer, DWORD cbBuffer, DWORD dwTimeout);
DWORD GetInterruptReport(HID_HANDLE hDevice, PCHAR pbBuffer, DWORD cbBuffer, PDWORD pcbTransferred, HANDLE hCancel, DWORD dwTimeout);
#define HID_CLOSE_DEVICE 1
int BTHHIDParser::m_scRef = 0;
HANDLE BTHHIDParser::m_hOSDevice = NULL; // The HID class device (HID0:)
// List of HID functions. Passed to HID clients.
static const HID_FUNCS g_HidFuncs =
{
sizeof(HID_FUNCS), // DWORD dwCount;
&GetReport,
&SetReport,
&GetInterruptReport,
};
BTHHIDParser::BTHHIDParser(IBTHHIDReportHandler* pReportHandler) :
m_pReportHandler(pReportHandler),
m_fIsInitialized(FALSE),
m_cRef(1)
{
ZeroMemory((void*) &m_UsbHid, sizeof(m_UsbHid));
ULONG cRef = InterlockedIncrement((LPLONG)&m_scRef);
// if (cRef == 1)
// {
// m_hOSDevice = ActivateDevice(CLIENT_REGKEY_SZ, 0);
// if (m_hOSDevice == NULL)
// DEBUGMSG(ZONE_ERROR, (_T("Error on ActivateDevice(%s)\r\n"), CLIENT_REGKEY_SZ));
// }
}
BTHHIDParser::~BTHHIDParser()
{
if (m_fIsInitialized)
Deinitialize();
ULONG cRef = InterlockedDecrement((LPLONG)&m_scRef);
// if (cRef == 0)
// {
// BOOL fSucceeded = DeactivateDevice(m_hOSDevice);
// if (!fSucceeded)
// DEBUGMSG(ZONE_ERROR, (_T("Error on DeactivateDevice\r\n")));
// }
}
ULONG BTHHIDParser::AddRef()
{
return InterlockedIncrement((LPLONG)&m_cRef);
}
ULONG BTHHIDParser::Release()
{
ULONG cRef = InterlockedDecrement((LPLONG)&m_cRef);
if(cRef == 0)
delete this;
return cRef;
}
HRESULT BTHHIDParser::QueryInterface(REFIID riid, void** ppvObject)
{
HRESULT hr = E_NOINTERFACE;
if (!ppvObject)
return E_INVALIDARG;
*ppvObject = NULL;
if ((riid == IID_IUnknown) || (riid == IID_IBTHHIDParser))
{
*ppvObject = this;
ASSERT(*ppvObject);
AddRef();
hr = S_OK;
}
return hr;
}
int BTHHIDParser::SetReportDescriptor(unsigned char* pReportDescriptor, int cDescriptor)
{
int iErr = ERROR_INVALID_PARAMETER;
DEBUGCHK(!IsBadReadPtr(pReportDescriptor, cDescriptor));
if (m_fIsInitialized)
Deinitialize();
iErr = Initialize(pReportDescriptor, cDescriptor);
return iErr;
}
int BTHHIDParser::ProcessInterruptReport(BYTE* pReport, int cReport)
{
PHIDP_REPORT_IDS phidpReport;
PHIDP_COLLECTION_DESC phidpCollection;
PHID_CLIENT_HANDLE pClientHandle;
DWORD dwReportID;
DWORD dwCollectionIndex;
HidTLCQueue* pQueue;
// Must be initialized.
DEBUGCHK(m_fIsInitialized);
// We always get a report ID.
dwReportID = *pReport;
// $TODO Those reportID are causing the parser problems. Discard for now. This should be fixed SOON by the new parser
if (dwReportID < 0 || dwReportID > 3)
return ERROR_INVALID_PARAMETER;
// Get the report and collection data structures
phidpReport = GetReportDesc(m_UsbHid.phidpDeviceDesc, dwReportID);
DEBUGCHK(phidpReport != NULL);
phidpCollection = GetCollectionDesc(m_UsbHid.phidpDeviceDesc,
phidpReport->CollectionNumber, &dwCollectionIndex);
DEBUGCHK(phidpCollection != NULL);
DEBUGCHK(dwCollectionIndex < m_UsbHid.phidpDeviceDesc->CollectionDescLength);
// Perform any power events listed in this report
PerformPowerEvents(phidpCollection, pReport, cReport);
// Send this HID packet to the proper client
pClientHandle = &m_UsbHid.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) pReport, cReport);
DEBUGCHK(fRet);
}
else
DEBUGMSG(ZONE_ERROR, (_T("Error: Queue is full. Dropping packet.\r\n")));
}
else
DEBUGMSG(ZONE_HID_DATA, (_T("Queue not accepting input. Dropping packet.\r\n")));
pQueue->Unlock();
}
return 0;
}
BOOL BTHHIDParser::IsInitialized()
{
return m_fIsInitialized;
}
void BTHHIDParser::ValidateHidContextEx()
{
LockHidContextEx();
DEBUGCHK(m_UsbHid.Sig == USB_HID_SIG);
DEBUGCHK(m_UsbHid.hEP0Event != NULL);
DEBUGCHK(m_UsbHid.phidpDeviceDesc != NULL);
// DEBUGCHK(LocalSize(m_UsbHid.phidpDeviceDesc) == sizeof(HIDP_DEVICE_DESC));
DEBUGCHK(m_UsbHid.pQueues != NULL);
DEBUGCHK(m_UsbHid.pClientHandles != NULL);
ReleaseHidContextEx();
}
void BTHHIDParser::ValidateClientHandleEx(PHID_CLIENT_HANDLE pHidClient)
{
DEBUGCHK(pHidClient != NULL);
DEBUGCHK(IsBadReadPtr(pHidClient, sizeof(*pHidClient)) == FALSE);
DEBUGCHK(pHidClient->Sig == USB_HID_CLIENT_SIG);
DEBUGCHK(pHidClient->pQueue != NULL);
pHidClient->pQueue->Validate();
DEBUGCHK(pHidClient->phidpPreparsedData != NULL);
DEBUGCHK(pHidClient->pUsbHid != NULL);
BTHHIDParser* pParser = (BTHHIDParser*) pHidClient->lpvContext;
DEBUGCHK(pParser != NULL);
pParser->ValidateHidContextEx();
}
int BTHHIDParser::ForceReportProtocol()
{
return m_pReportHandler->SetProtocol(BTHID_REPORT_PROTOCOL);
}
int BTHHIDParser::SetIdle()
{
return m_pReportHandler->SetIdle(0);
}
int BTHHIDParser::Initialize(unsigned char* pReportDescriptor, int cDescriptor)
{
if (m_fIsInitialized)
return ERROR_ALREADY_INITIALIZED;
int iErr = -1;
NTSTATUS status = 0;
ZeroMemory((void*) &m_UsbHid, sizeof(m_UsbHid));
InitializeCriticalSection(&m_UsbHid.csLock);
m_UsbHid.Sig = USB_HID_SIG; // mimic a USB driver from the clients.
m_UsbHid.Flags.Open = FALSE;
m_UsbHid.Flags.UnloadPending = FALSE;
// create endpoint 0 event
m_UsbHid.hEP0Event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_UsbHid.hEP0Event == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("CreateEvent error:%d\r\n"), GetLastError()));
goto EXIT;
}
// Get the report descriptor for our interface.
m_UsbHid.phidpDeviceDesc = (PHIDP_DEVICE_DESC) LocalAlloc(LMEM_FIXED, sizeof(HIDP_DEVICE_DESC));
if (m_UsbHid.phidpDeviceDesc == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("LocalAlloc error:%d\r\n"), GetLastError()));
goto EXIT;
}
ZeroMemory(m_UsbHid.phidpDeviceDesc, sizeof(*m_UsbHid.phidpDeviceDesc));
status = HidP_GetCollectionDescription(
pReportDescriptor,
cDescriptor,
0,
m_UsbHid.phidpDeviceDesc
);
if (NT_SUCCESS(status) == FALSE) {
DEBUGMSG(ZONE_ERROR, (_T("Problem parsing report descriptor Error: 0x%x\r\n"),status));
goto EXIT;
}
// Set up our data structres for each top level collection.
if (InitializeTLCStructures() == FALSE)
goto EXIT;
// Load client drivers for our top level collections
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -