Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3541 lines
117 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: hidevice.c
  3. *
  4. * Copyright (c) 1985 - 2000, Microsoft Corporation
  5. *
  6. * This module handles HID inputs
  7. *
  8. * History:
  9. * 2000-02-16 HiroYama
  10. \***************************************************************************/
  11. /*
  12. * HidDeviceStartStop() needs to be called after both the process devlice request list
  13. * and the global TLC list are fully updated.
  14. * Each deletion of addition should only recalc the reference count of each devicetype info
  15. * and UsagePage-only req-list, but does not actively changes the actual read state of
  16. * each device.
  17. *
  18. * The device should start if:
  19. * - cDirectRequest > 0.
  20. * This device type is in the inclusion list, so no matter the other ref counts are,
  21. * the device needs to be read.
  22. * - or, cUsagePageRequest > cExcludeRequest
  23. * if UsagePage inclusion exceeds the exclude request count, this device needs to be read.
  24. *
  25. * The device should stop if:
  26. * - uDrecoutRequest == 0 && cUsagePageRequest <= cExcludeRequest
  27. * No process specifies this device in the inclusion list.
  28. * Exclude count exceeds the UP only request.
  29. *
  30. * The above consideration assumes, in a single process, specific UsagePage/Usage only appears
  31. * either in inclusion list or exclusion list, but not both.
  32. *
  33. * N.b. No need to maintain the global *exclusion* list.
  34. * Each DeviceTLCInfo has three ref counter:
  35. * - cDirectRequest
  36. * - cUsagePageRequest
  37. * - cExcludeRequest
  38. * plus, cDevices.
  39. *
  40. * N.b. Legit number of exclusive requests in TLCInfo is,
  41. * cExclusive - cExclusiveOrphaned.
  42. *
  43. */
  44. #include "precomp.h"
  45. #pragma hdrstop
  46. #ifdef GENERIC_INPUT
  47. #define API_PROLOGUE(type, err) \
  48. type retval; \
  49. type errval = err
  50. #define API_ERROR(lasterr) \
  51. retval = errval; \
  52. if (lasterr) { \
  53. UserSetLastError(lasterr); \
  54. } \
  55. goto error_exit
  56. #define API_CLEANUP() \
  57. goto error_exit; \
  58. error_exit: \
  59. #define API_EPILOGUE() \
  60. return retval
  61. #define StubExceptionHandler(fSetLastError) W32ExceptionHandler((fSetLastError), RIP_WARNING)
  62. #ifdef GI_SINK
  63. HID_COUNTERS gHidCounters;
  64. #endif
  65. #if DBG
  66. /*
  67. * Quick sneaky way for the memory leak check.
  68. */
  69. struct HidAllocateCounter {
  70. int cHidData;
  71. int cHidDesc;
  72. int cTLCInfo;
  73. int cPageOnlyRequest;
  74. int cProcessDeviceRequest;
  75. int cProcessRequestTable;
  76. int cHidSinks;
  77. int cKbdSinks;
  78. int cMouseSinks;
  79. } gHidAllocCounters;
  80. int gcAllocHidTotal;
  81. #define DbgInc(a) do { UserAssert(gHidAllocCounters.a >= 0 && gcAllocHidTotal >= 0); ++gHidAllocCounters.a; ++gcAllocHidTotal; } while (FALSE)
  82. #define DbgDec(a) do { --gHidAllocCounters.a; --gcAllocHidTotal; UserAssert(gHidAllocCounters.a >= 0 && gcAllocHidTotal >= 0); } while (FALSE)
  83. #define DbgFreInc(a) do { DbgInc(a); ++gHidCounters.a; } while (FALSE)
  84. #define DbgFreDec(a) do { DbgDec(a); --gHidCounters.a; } while (FALSE)
  85. #else
  86. #define DbgInc(a)
  87. #define DbgDec(a)
  88. #define DbgFreInc(a) do { ++gHidCounters.a; } while (FALSE)
  89. #define DbgFreDec(a) do { --gHidCounters.a; } while (FALSE)
  90. #endif
  91. /*
  92. * Short helpers
  93. */
  94. __inline BOOL IsKeyboardDevice(USAGE usagePage, USAGE usage)
  95. {
  96. return usagePage == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_KEYBOARD;
  97. }
  98. __inline BOOL IsMouseDevice(USAGE usagePage, USAGE usage)
  99. {
  100. return usagePage == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_MOUSE;
  101. }
  102. __inline BOOL IsLegacyDevice(USAGE usagePage, USAGE usage)
  103. {
  104. BOOL fRet = FALSE;
  105. switch (usagePage) {
  106. case HID_USAGE_PAGE_GENERIC:
  107. switch (usage) {
  108. case HID_USAGE_GENERIC_KEYBOARD:
  109. case HID_USAGE_GENERIC_MOUSE:
  110. fRet = TRUE;
  111. }
  112. }
  113. UserAssert(fRet == (IsKeyboardDevice(usagePage, usage) || IsMouseDevice(usagePage, usage)));
  114. return fRet;
  115. }
  116. /*
  117. * Debug helpers
  118. */
  119. #if DBG
  120. /***************************************************************************\
  121. * CheckupHidLeak
  122. *
  123. * Check if there is any leaked memory.
  124. * This one should be called after the pDeviceInfo and all process cleanup.
  125. \***************************************************************************/
  126. void CheckupHidLeak(void)
  127. {
  128. UserAssert(gHidAllocCounters.cHidData == 0);
  129. UserAssert(gHidAllocCounters.cHidDesc == 0);
  130. UserAssert(gHidAllocCounters.cTLCInfo == 0);
  131. UserAssert(gHidAllocCounters.cPageOnlyRequest == 0);
  132. UserAssert(gHidAllocCounters.cProcessDeviceRequest == 0);
  133. UserAssert(gHidAllocCounters.cProcessRequestTable == 0);
  134. #ifdef GI_SINK
  135. UserAssert(gHidCounters.cKbdSinks == (DWORD)gHidAllocCounters.cKbdSinks);
  136. UserAssert(gHidCounters.cMouseSinks == (DWORD)gHidAllocCounters.cMouseSinks);
  137. UserAssert(gHidCounters.cHidSinks == (DWORD)gHidAllocCounters.cHidSinks);
  138. UserAssert(gHidAllocCounters.cKbdSinks == 0);
  139. UserAssert(gHidAllocCounters.cMouseSinks == 0);
  140. UserAssert(gHidAllocCounters.cHidData == 0);
  141. UserAssert(gHidCounters.cKbdSinks == 0);
  142. UserAssert(gHidCounters.cMouseSinks == 0);
  143. UserAssert(gHidCounters.cHidSinks == 0);
  144. #endif
  145. }
  146. void CheckupHidCounter(void)
  147. {
  148. PLIST_ENTRY pList;
  149. UserAssert(gHidAllocCounters.cHidData >= 0);
  150. UserAssert(gHidAllocCounters.cHidDesc >= 0);
  151. UserAssert(gHidAllocCounters.cTLCInfo >= 0);
  152. UserAssert(gHidAllocCounters.cPageOnlyRequest >= 0);
  153. UserAssert(gHidAllocCounters.cProcessDeviceRequest >= 0);
  154. UserAssert(gHidAllocCounters.cProcessRequestTable >= 0);
  155. #ifdef GI_SINK
  156. UserAssert(gHidCounters.cKbdSinks == (DWORD)gHidAllocCounters.cKbdSinks);
  157. UserAssert(gHidCounters.cMouseSinks == (DWORD)gHidAllocCounters.cMouseSinks);
  158. UserAssert(gHidCounters.cHidSinks == (DWORD)gHidAllocCounters.cHidSinks);
  159. UserAssert((int)gHidAllocCounters.cKbdSinks >= 0);
  160. UserAssert((int)gHidAllocCounters.cMouseSinks >= 0);
  161. UserAssert((int)gHidAllocCounters.cHidData >= 0);
  162. UserAssert((int)gHidCounters.cKbdSinks >= 0);
  163. UserAssert((int)gHidCounters.cMouseSinks >= 0);
  164. UserAssert((int)gHidCounters.cHidSinks >= 0);
  165. #endif
  166. /*
  167. * Checkup TLC Info
  168. */
  169. for (pList = gHidRequestTable.TLCInfoList.Flink; pList != &gHidRequestTable.TLCInfoList; pList = pList->Flink) {
  170. PHID_TLC_INFO pTLCInfo = CONTAINING_RECORD(pList, HID_TLC_INFO, link);
  171. UserAssert((int)pTLCInfo->cDevices >= 0);
  172. UserAssert((int)pTLCInfo->cDirectRequest >= 0);
  173. UserAssert((int)pTLCInfo->cUsagePageRequest >= 0);
  174. UserAssert((int)pTLCInfo->cExcludeRequest >= 0);
  175. UserAssert((int)pTLCInfo->cExcludeOrphaned >= 0);
  176. }
  177. #ifdef GI_SINK
  178. /*
  179. * Checkup process request tables.
  180. */
  181. for (pList = gHidRequestTable.ProcessRequestList.Flink; pList != &gHidRequestTable.ProcessRequestList; pList = pList->Flink) {
  182. PPROCESS_HID_TABLE pHidTable = CONTAINING_RECORD(pList, PROCESS_HID_TABLE, link);
  183. UserAssert((int)pHidTable->nSinks >= 0);
  184. }
  185. #endif
  186. }
  187. /***************************************************************************\
  188. * DBGValidateHidRequestIsNew
  189. *
  190. * Make sure there's no deviceinfo that has this UsagePage/Usage.
  191. \***************************************************************************/
  192. void DBGValidateHidRequestIsNew(
  193. USAGE UsagePage,
  194. USAGE Usage)
  195. {
  196. PDEVICEINFO pDeviceInfo;
  197. CheckDeviceInfoListCritIn();
  198. if (IsLegacyDevice(UsagePage, Usage)) {
  199. return;
  200. }
  201. for (pDeviceInfo = gpDeviceInfoList; pDeviceInfo; pDeviceInfo = pDeviceInfo->pNext) {
  202. if (pDeviceInfo->type == DEVICE_TYPE_HID) {
  203. UserAssert(pDeviceInfo->hid.pHidDesc->hidpCaps.UsagePage != UsagePage ||
  204. pDeviceInfo->hid.pHidDesc->hidpCaps.Usage != Usage);
  205. }
  206. }
  207. }
  208. /***************************************************************************\
  209. * DBGValidateHidReqNotInList
  210. *
  211. * Make sure this request is not in ppi->pHidTable
  212. \***************************************************************************/
  213. void DBGValidateHidReqNotInList(
  214. PPROCESSINFO ppi,
  215. PPROCESS_HID_REQUEST pHid)
  216. {
  217. PLIST_ENTRY pList;
  218. for (pList = ppi->pHidTable->InclusionList.Flink; pList != &ppi->pHidTable->InclusionList; pList = pList->Flink) {
  219. const PPROCESS_HID_REQUEST pHidTmp = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  220. UserAssert(pHid != pHidTmp);
  221. }
  222. for (pList = ppi->pHidTable->UsagePageList.Flink; pList != &ppi->pHidTable->UsagePageList; pList = pList->Flink) {
  223. const PPROCESS_HID_REQUEST pHidTmp = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  224. UserAssert(pHid != pHidTmp);
  225. }
  226. for (pList = ppi->pHidTable->ExclusionList.Flink; pList != &ppi->pHidTable->ExclusionList; pList = pList->Flink) {
  227. const PPROCESS_HID_REQUEST pHidTmp = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  228. UserAssert(pHid != pHidTmp);
  229. }
  230. }
  231. #else
  232. /*
  233. * NOT DBG
  234. */
  235. #define CheckupHidCounter()
  236. #define DBGValidateHidReqNotInList(ppi, pHid)
  237. #endif // DBG
  238. /*
  239. * Function prototypes
  240. */
  241. PHID_PAGEONLY_REQUEST SearchHidPageOnlyRequest(
  242. USHORT usUsagePage);
  243. PHID_TLC_INFO SearchHidTLCInfo(
  244. USHORT usUsagePage,
  245. USHORT usUsage);
  246. void FreeHidPageOnlyRequest(
  247. PHID_PAGEONLY_REQUEST pPOReq);
  248. void ClearProcessTableCache(
  249. PPROCESS_HID_TABLE pHidTable);
  250. /***************************************************************************\
  251. * HidDeviceTypeNoReference
  252. \***************************************************************************/
  253. __inline BOOL HidTLCInfoNoReference(PHID_TLC_INFO pTLCInfo)
  254. {
  255. /*
  256. * Orphaned Exclusive requests are always less then cExclusive.
  257. */
  258. UserAssert(pTLCInfo->cExcludeRequest >= pTLCInfo->cExcludeOrphaned);
  259. /*
  260. * Hacky, but a bit faster than comparing 0 with each counter.
  261. */
  262. return (pTLCInfo->cDevices | pTLCInfo->cDirectRequest | pTLCInfo->cExcludeRequest | pTLCInfo->cUsagePageRequest) == 0;
  263. }
  264. /***************************************************************************\
  265. * HidDeviceStartStop:
  266. *
  267. * This routine has to be called after the global request list is fully updated.
  268. \***************************************************************************/
  269. VOID HidDeviceStartStop()
  270. {
  271. PDEVICEINFO pDeviceInfo;
  272. /*
  273. * The caller has to ensure being in the device list critical section.
  274. */
  275. CheckDeviceInfoListCritIn();
  276. /*
  277. * Walk through the list, and start or stop the HID device accordingly.
  278. */
  279. for (pDeviceInfo = gpDeviceInfoList; pDeviceInfo; pDeviceInfo = pDeviceInfo->pNext) {
  280. if (pDeviceInfo->type == DEVICE_TYPE_HID) {
  281. PHID_TLC_INFO pTLCInfo = pDeviceInfo->hid.pTLCInfo;
  282. UserAssert(pTLCInfo);
  283. if (HidTLCActive(pTLCInfo)) {
  284. if (pDeviceInfo->handle == 0) {
  285. TAGMSG3(DBGTAG_PNP, "HidTLCActive: starting pDevInfo=%p (%x, %x)", pDeviceInfo,
  286. pDeviceInfo->hid.pHidDesc->hidpCaps.UsagePage, pDeviceInfo->hid.pHidDesc->hidpCaps.Usage);
  287. RequestDeviceChange(pDeviceInfo, GDIAF_STARTREAD, TRUE);
  288. }
  289. } else {
  290. UserAssert(pTLCInfo->cDirectRequest == 0 && pTLCInfo->cUsagePageRequest <= HidValidExclusive(pTLCInfo));
  291. if (pDeviceInfo->handle) {
  292. TAGMSG3(DBGTAG_PNP, "HidTLCActive: stopping pDevInfo=%p (%x, %x)", pDeviceInfo,
  293. pDeviceInfo->hid.pHidDesc->hidpCaps.UsagePage, pDeviceInfo->hid.pHidDesc->hidpCaps.Usage);
  294. RequestDeviceChange(pDeviceInfo, GDIAF_STOPREAD, TRUE);
  295. }
  296. }
  297. }
  298. }
  299. }
  300. /***************************************************************************\
  301. * AllocateAndLinkHidTLCInfo
  302. *
  303. * Allocates DeviceTypeRequest and link it to the global device type request list.
  304. *
  305. * N.b. the caller has the responsibility to manage the appropriate link count.
  306. \***************************************************************************/
  307. PHID_TLC_INFO AllocateAndLinkHidTLCInfo(USHORT usUsagePage, USHORT usUsage)
  308. {
  309. PHID_TLC_INFO pTLCInfo;
  310. PLIST_ENTRY pList;
  311. CheckDeviceInfoListCritIn();
  312. UserAssert(!IsLegacyDevice(usUsagePage, usUsage));
  313. /*
  314. * Make sure this device type is not in the global device request list.
  315. */
  316. UserAssert(SearchHidTLCInfo(usUsagePage, usUsage) == NULL);
  317. pTLCInfo = UserAllocPoolZInit(sizeof *pTLCInfo, TAG_PNP);
  318. if (pTLCInfo == NULL) {
  319. RIPMSG0(RIP_WARNING, "AllocateAndLinkHidTLCInfoList: failed to allocate.");
  320. return NULL;
  321. }
  322. DbgInc(cTLCInfo);
  323. pTLCInfo->usUsagePage = usUsagePage;
  324. pTLCInfo->usUsage = usUsage;
  325. /*
  326. * Link it in.
  327. */
  328. InsertHeadList(&gHidRequestTable.TLCInfoList, &pTLCInfo->link);
  329. /*
  330. * Set the correct counter of UsagePage-only request.
  331. */
  332. for (pList = gHidRequestTable.UsagePageList.Flink; pList != &gHidRequestTable.UsagePageList; pList = pList->Flink) {
  333. PHID_PAGEONLY_REQUEST pPoReq = CONTAINING_RECORD(pList, HID_PAGEONLY_REQUEST, link);
  334. if (pPoReq->usUsagePage == usUsagePage) {
  335. pTLCInfo->cUsagePageRequest = pPoReq->cRefCount;
  336. break;
  337. }
  338. }
  339. /*
  340. * The caller is responsible for the further actions, including:
  341. * 1) increments appropriate refcount in this strucutre, or
  342. * 2) check & start read if this is allocated though the SetRawInputDevice API.
  343. * etc.
  344. */
  345. return pTLCInfo;
  346. }
  347. /***************************************************************************\
  348. * FreeHidTLCInfo.
  349. *
  350. * Make sure that no one is interested in this device type before
  351. * calling this function.
  352. \***************************************************************************/
  353. VOID FreeHidTLCInfo(PHID_TLC_INFO pTLCInfo)
  354. {
  355. CheckDeviceInfoListCritIn();
  356. DbgDec(cTLCInfo);
  357. UserAssert(pTLCInfo->cDevices == 0);
  358. UserAssert(pTLCInfo->cDirectRequest == 0);
  359. UserAssert(pTLCInfo->cUsagePageRequest == 0);
  360. UserAssert(pTLCInfo->cExcludeRequest == 0);
  361. UserAssert(pTLCInfo->cExcludeOrphaned == 0);
  362. RemoveEntryList(&pTLCInfo->link);
  363. UserFreePool(pTLCInfo);
  364. }
  365. /***************************************************************************\
  366. * SearchHidTLCInfo
  367. *
  368. * Simply searches the UsagePage/Usage in the global device type request list.
  369. \***************************************************************************/
  370. PHID_TLC_INFO SearchHidTLCInfo(USHORT usUsagePage, USHORT usUsage)
  371. {
  372. PLIST_ENTRY pList;
  373. CheckDeviceInfoListCritIn();
  374. for (pList = gHidRequestTable.TLCInfoList.Flink; pList != &gHidRequestTable.TLCInfoList; pList = pList->Flink) {
  375. PHID_TLC_INFO pTLCInfo = CONTAINING_RECORD(pList, HID_TLC_INFO, link);
  376. UserAssert(!IsLegacyDevice(pTLCInfo->usUsagePage, pTLCInfo->usUsage));
  377. if (pTLCInfo->usUsagePage == usUsagePage && pTLCInfo->usUsage == usUsage) {
  378. return pTLCInfo;
  379. }
  380. }
  381. return NULL;
  382. }
  383. /***************************************************************************\
  384. * FixupHidPageOnlyRequest
  385. *
  386. * After the page-only request is freed, fix up the reference counter in
  387. * DeviceTypeRequest. If there's no reference, this function also frees
  388. * the DeviceTypeRequest.
  389. \***************************************************************************/
  390. void SetHidPOCountToTLCInfo(USHORT usUsagePage, DWORD cRefCount, BOOL fFree)
  391. {
  392. PLIST_ENTRY pList;
  393. CheckDeviceInfoListCritIn();
  394. fFree = (fFree && cRefCount == 0);
  395. for (pList = gHidRequestTable.TLCInfoList.Flink; pList != &gHidRequestTable.TLCInfoList;) {
  396. PHID_TLC_INFO pTLCInfo = CONTAINING_RECORD(pList, HID_TLC_INFO, link);
  397. pList = pList->Flink;
  398. if (pTLCInfo->usUsagePage == usUsagePage) {
  399. pTLCInfo->cUsagePageRequest = cRefCount;
  400. if (fFree && HidTLCInfoNoReference(pTLCInfo)) {
  401. /*
  402. * Currently there's no devices of this type attached to the system,
  403. * and nobody is interested in this type of device any more.
  404. * We can free it now.
  405. */
  406. FreeHidTLCInfo(pTLCInfo);
  407. }
  408. }
  409. }
  410. }
  411. /***************************************************************************\
  412. * AllocateAndLinkHidPageOnlyRequest
  413. *
  414. * Allocates the page-only request and link it in the global request list.
  415. * The caller is responsible for setting the proper link count.
  416. \***************************************************************************/
  417. PHID_PAGEONLY_REQUEST AllocateAndLinkHidPageOnlyRequest(USHORT usUsagePage)
  418. {
  419. PHID_PAGEONLY_REQUEST pPOReq;
  420. CheckDeviceInfoListCritIn();
  421. /*
  422. * Make sure this PageOnly request is not in the global PageOnly request list.
  423. */
  424. UserAssert((pPOReq = SearchHidPageOnlyRequest(usUsagePage)) == NULL);
  425. pPOReq = UserAllocPoolZInit(sizeof(*pPOReq), TAG_PNP);
  426. if (pPOReq == NULL) {
  427. RIPMSG0(RIP_WARNING, "AllocateAndLinkHidPageOnlyRequest: failed to allocate.");
  428. return NULL;
  429. }
  430. DbgInc(cPageOnlyRequest);
  431. pPOReq->usUsagePage = usUsagePage;
  432. /*
  433. * Link it in
  434. */
  435. InsertHeadList(&gHidRequestTable.UsagePageList, &pPOReq->link);
  436. return pPOReq;
  437. }
  438. /***************************************************************************\
  439. * FreeHidPageOnlyRequest
  440. *
  441. * Frees the page-only request in the global request list.
  442. * The caller is responsible for setting the proper link count.
  443. \***************************************************************************/
  444. void FreeHidPageOnlyRequest(PHID_PAGEONLY_REQUEST pPOReq)
  445. {
  446. CheckDeviceInfoListCritIn();
  447. UserAssert(pPOReq->cRefCount == 0);
  448. RemoveEntryList(&pPOReq->link);
  449. UserFreePool(pPOReq);
  450. DbgDec(cPageOnlyRequest);
  451. }
  452. /***************************************************************************\
  453. * SearchHidPageOnlyRequest
  454. *
  455. * Searches the page-only request in the global request list.
  456. * The caller is responsible for setting the proper link count.
  457. \***************************************************************************/
  458. PHID_PAGEONLY_REQUEST SearchHidPageOnlyRequest(USHORT usUsagePage)
  459. {
  460. PLIST_ENTRY pList;
  461. for (pList = gHidRequestTable.UsagePageList.Flink; pList != &gHidRequestTable.UsagePageList; pList = pList->Flink) {
  462. PHID_PAGEONLY_REQUEST pPOReq = CONTAINING_RECORD(pList, HID_PAGEONLY_REQUEST, link);
  463. if (pPOReq->usUsagePage == usUsagePage) {
  464. return pPOReq;
  465. }
  466. }
  467. return NULL;
  468. }
  469. /***************************************************************************\
  470. * SearchProcessHidRequestInclusion
  471. *
  472. * Searches specific TLC in the per-process inclusion request.
  473. \***************************************************************************/
  474. __inline PPROCESS_HID_REQUEST SearchProcessHidRequestInclusion(
  475. PPROCESS_HID_TABLE pHidTable,
  476. USHORT usUsagePage,
  477. USHORT usUsage)
  478. {
  479. PLIST_ENTRY pList;
  480. UserAssert(pHidTable); // the caller has to validate this
  481. for (pList = pHidTable->InclusionList.Flink; pList != &pHidTable->InclusionList; pList = pList->Flink) {
  482. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  483. if (pHid->usUsagePage == usUsagePage && pHid->usUsage == usUsage) {
  484. return pHid;
  485. }
  486. }
  487. return NULL;
  488. }
  489. /***************************************************************************\
  490. * SearchProcessHidRequestUsagePage
  491. *
  492. * Searches specific page-only TLC in the per-process page-only request.
  493. \***************************************************************************/
  494. __inline PPROCESS_HID_REQUEST SearchProcessHidRequestUsagePage(
  495. PPROCESS_HID_TABLE pHidTable,
  496. USHORT usUsagePage)
  497. {
  498. PLIST_ENTRY pList;
  499. UserAssert(pHidTable); // the caller has to validate this
  500. for (pList = pHidTable->UsagePageList.Flink; pList != &pHidTable->UsagePageList; pList = pList->Flink) {
  501. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  502. if (pHid->usUsagePage == usUsagePage /*&& pHid->usUsage == usUsage*/) {
  503. return pHid;
  504. }
  505. }
  506. return NULL;
  507. }
  508. /***************************************************************************\
  509. * SearchProcessHidRequestExclusion
  510. *
  511. * Searches specifc TLC in the per-process exclusion list.
  512. \***************************************************************************/
  513. __inline PPROCESS_HID_REQUEST SearchProcessHidRequestExclusion(
  514. PPROCESS_HID_TABLE pHidTable,
  515. USHORT usUsagePage,
  516. USHORT usUsage)
  517. {
  518. PLIST_ENTRY pList;
  519. UserAssert(pHidTable); // the caller has to validate this
  520. for (pList = pHidTable->ExclusionList.Flink; pList != &pHidTable->ExclusionList; pList = pList->Flink) {
  521. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  522. UserAssert(pHid->spwndTarget == NULL);
  523. if (pHid->usUsagePage == usUsagePage && pHid->usUsage == usUsage) {
  524. return pHid;
  525. }
  526. }
  527. return NULL;
  528. }
  529. /***************************************************************************\
  530. * SearchProcessHidRequest
  531. *
  532. * Search per-process HID request list
  533. *
  534. * Returns the pointer and the flag to indicate which list the request is in.
  535. * N.b. this function performs the simple search, should not be used
  536. * to judge whether or not the TLC is requested by the process.
  537. \***************************************************************************/
  538. PPROCESS_HID_REQUEST SearchProcessHidRequest(
  539. PPROCESSINFO ppi,
  540. USHORT usUsagePage,
  541. USHORT usUsage,
  542. PDWORD pdwFlags
  543. )
  544. {
  545. PPROCESS_HID_REQUEST pReq;
  546. if (ppi->pHidTable == NULL) {
  547. return NULL;
  548. }
  549. pReq = SearchProcessHidRequestInclusion(ppi->pHidTable, usUsagePage, usUsage);
  550. if (pReq) {
  551. *pdwFlags = HID_INCLUDE;
  552. return pReq;
  553. }
  554. if (usUsage == 0) {
  555. pReq = SearchProcessHidRequestUsagePage(ppi->pHidTable, usUsagePage);
  556. if (pReq) {
  557. *pdwFlags = HID_PAGEONLY;
  558. return pReq;
  559. }
  560. }
  561. pReq = SearchProcessHidRequestExclusion(ppi->pHidTable, usUsagePage, usUsage);
  562. if (pReq) {
  563. *pdwFlags = HID_EXCLUDE;
  564. return pReq;
  565. }
  566. *pdwFlags = 0;
  567. return NULL;
  568. }
  569. /***************************************************************************\
  570. * InProcessDeviceTypeRequestTable
  571. *
  572. * Check if the device type is in the per-process device request list.
  573. * This routine considers the returns TRUE if UsagePage/Usage is requested
  574. * by the process.
  575. \***************************************************************************/
  576. PPROCESS_HID_REQUEST InProcessDeviceTypeRequestTable(
  577. PPROCESS_HID_TABLE pHidTable,
  578. USHORT usUsagePage,
  579. USHORT usUsage)
  580. {
  581. PPROCESS_HID_REQUEST phr = NULL;
  582. PPROCESS_HID_REQUEST phrExclusive = NULL;
  583. UserAssert(pHidTable);
  584. /*
  585. * Firstly check if this is in the inclusion list.
  586. */
  587. if ((phr = SearchProcessHidRequestInclusion(pHidTable, usUsagePage, usUsage)) != NULL) {
  588. if (CONTAINING_RECORD(pHidTable->InclusionList.Flink, PROCESS_HID_REQUEST, link) != phr) {
  589. /*
  590. * Relink this phr to the list head for MRU list
  591. */
  592. RemoveEntryList(&phr->link);
  593. InsertHeadList(&pHidTable->InclusionList, &phr->link);
  594. }
  595. goto yes_this_is_requested;
  596. }
  597. /*
  598. * Secondly, check if this is in the UsagePage list.
  599. */
  600. if ((phr = SearchProcessHidRequestUsagePage(pHidTable, usUsagePage)) == NULL) {
  601. /*
  602. * If this UsagePage is not requested, we don't need
  603. * to process the input.
  604. */
  605. return NULL;
  606. }
  607. if (CONTAINING_RECORD(pHidTable->UsagePageList.Flink, PROCESS_HID_REQUEST, link) != phr) {
  608. /*
  609. * Relink this phr to the list head for MRU list
  610. */
  611. RemoveEntryList(&phr->link);
  612. InsertHeadList(&pHidTable->UsagePageList, &phr->link);
  613. }
  614. /*
  615. * Lastly, check the exclusion list.
  616. * If it's not in the exclusion list, this device is
  617. * considered as requested by this process.
  618. */
  619. if ((phrExclusive = SearchProcessHidRequestExclusion(pHidTable, usUsagePage, usUsage)) != NULL) {
  620. /*
  621. * The device in the UsagePage request, but
  622. * rejected as in the Exclusion list.
  623. */
  624. if (CONTAINING_RECORD(pHidTable->ExclusionList.Flink, PROCESS_HID_REQUEST, link) != phrExclusive) {
  625. /*
  626. * Relink this phr to the list head for MRU list
  627. */
  628. RemoveEntryList(&phrExclusive->link);
  629. InsertHeadList(&pHidTable->ExclusionList, &phrExclusive->link);
  630. }
  631. return NULL;
  632. }
  633. yes_this_is_requested:
  634. UserAssert(phr);
  635. /*
  636. * The device is in UsagePage list, and is not rejected by exslucion list.
  637. */
  638. return phr;
  639. }
  640. /***************************************************************************\
  641. * AllocateHidProcessRequest
  642. *
  643. * The caller has the responsibility to put this in the appropriate list.
  644. \***************************************************************************/
  645. PPROCESS_HID_REQUEST AllocateHidProcessRequest(
  646. USHORT usUsagePage,
  647. USHORT usUsage)
  648. {
  649. PPROCESS_HID_REQUEST pHidReq;
  650. pHidReq = UserAllocPoolWithQuota(sizeof(PROCESS_HID_REQUEST), TAG_PNP);
  651. if (pHidReq == NULL) {
  652. return NULL;
  653. }
  654. DbgInc(cProcessDeviceRequest);
  655. /*
  656. * Initialize the contents
  657. */
  658. pHidReq->usUsagePage = usUsagePage;
  659. pHidReq->usUsage = usUsage;
  660. pHidReq->ptr = NULL;
  661. pHidReq->spwndTarget = NULL;
  662. pHidReq->fExclusiveOrphaned = FALSE;
  663. #ifdef GI_SINK
  664. pHidReq->fSinkable = FALSE;
  665. #endif
  666. return pHidReq;
  667. }
  668. /***************************************************************************\
  669. * DerefIncludeRequest
  670. *
  671. \***************************************************************************/
  672. void DerefIncludeRequest(
  673. PPROCESS_HID_REQUEST pHid,
  674. PPROCESS_HID_TABLE pHidTable,
  675. BOOL fLegacyDevice,
  676. BOOL fFree)
  677. {
  678. if (fLegacyDevice) {
  679. /*
  680. * Legacy devices are not associated with TLCInfo.
  681. */
  682. UserAssert(pHid->pTLCInfo == NULL);
  683. // N.b. NoLegacy flag is set afterwards
  684. /*
  685. * If mouse is being removed, clear the captureMouse
  686. * flag.
  687. */
  688. if (pHidTable->fCaptureMouse) {
  689. if (IsMouseDevice(pHid->usUsagePage, pHid->usUsage)) {
  690. pHidTable->fCaptureMouse = FALSE;
  691. }
  692. }
  693. if (pHidTable->fNoHotKeys) {
  694. if (IsKeyboardDevice(pHid->usUsagePage, pHid->usUsage)) {
  695. pHidTable->fNoHotKeys = FALSE;
  696. }
  697. }
  698. if (pHidTable->fAppKeys) {
  699. if (IsKeyboardDevice(pHid->usUsagePage, pHid->usUsage)) {
  700. pHidTable->fAppKeys = FALSE;
  701. }
  702. }
  703. } else {
  704. /*
  705. * HID devices.
  706. * Decrement the counters in HidDeviceTypeRequest.
  707. */
  708. UserAssert(pHid->pTLCInfo);
  709. UserAssert(pHid->pTLCInfo == SearchHidTLCInfo(pHid->usUsagePage, pHid->usUsage));
  710. if (--pHid->pTLCInfo->cDirectRequest == 0 && fFree) {
  711. if (HidTLCInfoNoReference(pHid->pTLCInfo)) {
  712. /*
  713. * Currently there's no devices of this type attached to the system,
  714. * and nobody is interested in this type of device any more.
  715. * We can free it now.
  716. */
  717. FreeHidTLCInfo(pHid->pTLCInfo);
  718. }
  719. }
  720. }
  721. #ifdef GI_SINK
  722. if (pHid->fSinkable) {
  723. pHid->fSinkable = FALSE;
  724. if (!fLegacyDevice) {
  725. --pHidTable->nSinks;
  726. UserAssert(pHidTable->nSinks >= 0); // LATER: when nSinks is changed to DWORD, remove those assertions
  727. DbgFreDec(cHidSinks);
  728. }
  729. }
  730. #endif
  731. }
  732. /***************************************************************************\
  733. * DerefPageOnlyRequest
  734. *
  735. \***************************************************************************/
  736. void DerefPageOnlyRequest(
  737. PPROCESS_HID_REQUEST pHid,
  738. PPROCESS_HID_TABLE pHidTable,
  739. const BOOL fFree)
  740. {
  741. /*
  742. * Decrement the ref count in the global pageonly list.
  743. */
  744. UserAssert(pHid->pPORequest);
  745. UserAssert(pHid->pPORequest == SearchHidPageOnlyRequest(pHid->usUsagePage));
  746. UserAssert(pHid->usUsage == 0);
  747. UserAssert(!IsLegacyDevice(pHid->usUsagePage, pHid->usUsage));
  748. UserAssert(pHid->pPORequest->cRefCount >= 1);
  749. --pHid->pPORequest->cRefCount;
  750. /*
  751. * Update the POCount in TLCInfo. Does not free them if fFree is false.
  752. */
  753. SetHidPOCountToTLCInfo(pHid->usUsagePage, pHid->pPORequest->cRefCount, fFree);
  754. /*
  755. * If refcount is 0 and the caller wants it freed, do it now.
  756. */
  757. if (pHid->pPORequest->cRefCount == 0 && fFree) {
  758. FreeHidPageOnlyRequest(pHid->pPORequest);
  759. pHid->pPORequest = NULL;
  760. }
  761. #ifdef GI_SINK
  762. if (pHid->fSinkable) {
  763. pHid->fSinkable = FALSE;
  764. --pHidTable->nSinks;
  765. UserAssert(pHidTable->nSinks >= 0);
  766. DbgFreDec(cHidSinks);
  767. }
  768. /*
  769. * The legacy sink flags in pHidTable is calc'ed later.
  770. */
  771. #endif
  772. }
  773. /***************************************************************************\
  774. * DerefExcludeRequest
  775. *
  776. \***************************************************************************/
  777. void DerefExcludeRequest(
  778. PPROCESS_HID_REQUEST pHid,
  779. BOOL fLegacyDevice,
  780. BOOL fFree)
  781. {
  782. /*
  783. * Remove Exclude request.
  784. */
  785. #ifdef GI_SINK
  786. UserAssert(pHid->fSinkable == FALSE);
  787. UserAssert(pHid->spwndTarget == NULL);
  788. #endif
  789. if (!fLegacyDevice) {
  790. UserAssert(pHid->pTLCInfo);
  791. UserAssert(pHid->pTLCInfo == SearchHidTLCInfo(pHid->usUsagePage, pHid->usUsage));
  792. if (pHid->fExclusiveOrphaned) {
  793. /*
  794. * This is a orphaned exclusive request.
  795. */
  796. --pHid->pTLCInfo->cExcludeOrphaned;
  797. }
  798. if (--pHid->pTLCInfo->cExcludeRequest == 0 && fFree && HidTLCInfoNoReference(pHid->pTLCInfo)) {
  799. /*
  800. * If all the references are gone, let's free this TLCInfo.
  801. */
  802. FreeHidTLCInfo(pHid->pTLCInfo);
  803. }
  804. } else {
  805. /*
  806. * Legacy devices are not associated with TLCInfo.
  807. */
  808. UserAssert(pHid->pTLCInfo == NULL);
  809. /*
  810. * Legacy devices cannot be orphaned exclusive request.
  811. */
  812. UserAssert(pHid->fExclusiveOrphaned == FALSE);
  813. }
  814. }
  815. /***************************************************************************\
  816. * FreeHidProcessRequest
  817. *
  818. * Frees the per-process request.
  819. * This routine only manupilates the reference count of the global request list, so
  820. * the caller has to call HidDeviceStartStop().
  821. \***************************************************************************/
  822. void FreeHidProcessRequest(
  823. PPROCESS_HID_REQUEST pHid,
  824. DWORD dwFlags,
  825. PPROCESS_HID_TABLE pHidTable)
  826. {
  827. BOOL fLegacyDevice = IsLegacyDevice(pHid->usUsagePage, pHid->usUsage);
  828. CheckDeviceInfoListCritIn(); // the caller has to ensure it's in the device list crit.
  829. /*
  830. * Unlock the target window.
  831. */
  832. Unlock(&pHid->spwndTarget);
  833. if (dwFlags == HID_INCLUDE) {
  834. DerefIncludeRequest(pHid, pHidTable, fLegacyDevice, TRUE);
  835. } else if (dwFlags == HID_PAGEONLY) {
  836. DerefPageOnlyRequest(pHid, pHidTable, TRUE);
  837. } else if (dwFlags == HID_EXCLUDE) {
  838. DerefExcludeRequest(pHid, fLegacyDevice, TRUE);
  839. } else {
  840. UserAssert(FALSE);
  841. }
  842. RemoveEntryList(&pHid->link);
  843. DbgDec(cProcessDeviceRequest);
  844. CheckupHidCounter();
  845. UserFreePool(pHid);
  846. }
  847. /***************************************************************************\
  848. * AllocateProcessHidTable
  849. *
  850. * The caller has to assign the returned table to ppi.
  851. \***************************************************************************/
  852. PPROCESS_HID_TABLE AllocateProcessHidTable(void)
  853. {
  854. PPROCESS_HID_TABLE pHidTable;
  855. TAGMSG1(DBGTAG_PNP, "AllocateProcessHidTable: ppi=%p", PpiCurrent());
  856. pHidTable = UserAllocPoolWithQuotaZInit(sizeof *pHidTable, TAG_PNP);
  857. if (pHidTable == NULL) {
  858. return NULL;
  859. }
  860. DbgInc(cProcessRequestTable);
  861. InitializeListHead(&pHidTable->InclusionList);
  862. InitializeListHead(&pHidTable->UsagePageList);
  863. InitializeListHead(&pHidTable->ExclusionList);
  864. #ifdef GI_SINK
  865. InsertHeadList(&gHidRequestTable.ProcessRequestList, &pHidTable->link);
  866. #endif
  867. /*
  868. * Increment the number of process that are HID aware.
  869. * When the process goes away, this gets decremented.
  870. */
  871. ++gnHidProcess;
  872. return pHidTable;
  873. }
  874. /***************************************************************************\
  875. * FreeProcesHidTable
  876. *
  877. \***************************************************************************/
  878. void FreeProcessHidTable(PPROCESS_HID_TABLE pHidTable)
  879. {
  880. BOOL fUpdate;
  881. UserAssert(pHidTable);
  882. CheckCritIn();
  883. CheckDeviceInfoListCritIn();
  884. TAGMSG2(DBGTAG_PNP, "FreeProcessHidTable: cleaning up pHidTable=%p (possibly ppi=%p)", pHidTable, PpiCurrent());
  885. fUpdate = !IsListEmpty(&pHidTable->InclusionList) || !IsListEmpty(&pHidTable->UsagePageList) || !IsListEmpty(&pHidTable->ExclusionList);
  886. /*
  887. * Unlock the target window for legacy devices.
  888. */
  889. Unlock(&pHidTable->spwndTargetKbd);
  890. Unlock(&pHidTable->spwndTargetMouse);
  891. while (!IsListEmpty(&pHidTable->InclusionList)) {
  892. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pHidTable->InclusionList.Flink, PROCESS_HID_REQUEST, link);
  893. FreeHidProcessRequest(pHid, HID_INCLUDE, pHidTable);
  894. }
  895. while (!IsListEmpty(&pHidTable->UsagePageList)) {
  896. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pHidTable->UsagePageList.Flink, PROCESS_HID_REQUEST, link);
  897. FreeHidProcessRequest(pHid, HID_PAGEONLY, pHidTable);
  898. }
  899. while (!IsListEmpty(&pHidTable->ExclusionList)) {
  900. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pHidTable->ExclusionList.Flink, PROCESS_HID_REQUEST, link);
  901. UserAssert(pHid->spwndTarget == NULL);
  902. FreeHidProcessRequest(pHid, HID_EXCLUDE, pHidTable);
  903. }
  904. #ifdef GI_SINK
  905. UserAssert(pHidTable->nSinks == 0);
  906. RemoveEntryList(&pHidTable->link);
  907. /*
  908. * Those flags should have been cleared on the
  909. * thread destruction.
  910. */
  911. UserAssert(pHidTable->fRawKeyboardSink == FALSE);
  912. UserAssert(pHidTable->fRawMouseSink == FALSE);
  913. CheckupHidCounter();
  914. #endif
  915. UserFreePool(pHidTable);
  916. /*
  917. * Decrement the number of process that are HID aware.
  918. */
  919. --gnHidProcess;
  920. DbgDec(cProcessRequestTable);
  921. if (fUpdate) {
  922. HidDeviceStartStop();
  923. }
  924. }
  925. /***************************************************************************\
  926. * DestroyProcessHidRequests
  927. *
  928. * Upon process termination, force destroy process hid requests.
  929. \***************************************************************************/
  930. void DestroyProcessHidRequests(PPROCESSINFO ppi)
  931. {
  932. PPROCESS_HID_TABLE pHidTable;
  933. CheckCritIn();
  934. EnterDeviceInfoListCrit();
  935. #if DBG
  936. /*
  937. * Check out if there's a pwndTarget in the HidTable list.
  938. * These should be unlocked by the time the last
  939. * threadinfo is destroyed.
  940. */
  941. UserAssert(ppi->pHidTable->spwndTargetMouse == NULL);
  942. UserAssert(ppi->pHidTable->spwndTargetKbd == NULL);
  943. #ifdef GI_SINK
  944. UserAssert(ppi->pHidTable->fRawKeyboardSink == FALSE);
  945. UserAssert(ppi->pHidTable->fRawMouseSink == FALSE);
  946. #endif
  947. {
  948. PPROCESS_HID_TABLE pHidTableTmp = ppi->pHidTable;
  949. PLIST_ENTRY pList;
  950. for (pList = pHidTableTmp->InclusionList.Flink; pList != &pHidTableTmp->InclusionList; pList = pList->Flink) {
  951. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  952. UserAssert(pHid->spwndTarget == NULL);
  953. }
  954. for (pList = pHidTableTmp->UsagePageList.Flink; pList != &pHidTableTmp->UsagePageList; pList = pList->Flink) {
  955. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  956. UserAssert(pHid->spwndTarget == NULL);
  957. }
  958. for (pList = pHidTableTmp->ExclusionList.Flink; pList != &pHidTableTmp->ExclusionList; pList = pList->Flink) {
  959. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  960. UserAssert(pHid->spwndTarget == NULL);
  961. }
  962. }
  963. #endif
  964. pHidTable = ppi->pHidTable;
  965. ppi->pHidTable = NULL;
  966. FreeProcessHidTable(pHidTable);
  967. LeaveDeviceInfoListCrit();
  968. }
  969. /***************************************************************************\
  970. * DestroyThreadHidObjects
  971. *
  972. * When a thread is going away, destroys thread-related Hid objects.
  973. \***************************************************************************/
  974. void DestroyThreadHidObjects(PTHREADINFO pti)
  975. {
  976. PPROCESS_HID_TABLE pHidTable = pti->ppi->pHidTable;
  977. PLIST_ENTRY pList;
  978. UserAssert(pHidTable);
  979. /*
  980. * If the target windows belong to this thread,
  981. * unlock them now.
  982. */
  983. if (pHidTable->spwndTargetKbd && GETPTI(pHidTable->spwndTargetKbd) == pti) {
  984. RIPMSG2(RIP_WARNING, "DestroyThreadHidObjects: raw keyboard is requested pwnd=%p by pti=%p",
  985. pHidTable->spwndTargetKbd, pti);
  986. Unlock(&pHidTable->spwndTargetKbd);
  987. pHidTable->fRawKeyboard = pHidTable->fNoLegacyKeyboard = FALSE;
  988. #ifdef GI_SINK
  989. if (pHidTable->fRawKeyboardSink) {
  990. DbgFreDec(cKbdSinks);
  991. pHidTable->fRawKeyboardSink = FALSE;
  992. }
  993. #endif
  994. }
  995. if (pHidTable->spwndTargetMouse && GETPTI(pHidTable->spwndTargetMouse) == pti) {
  996. RIPMSG2(RIP_WARNING, "DestroyThreadHidObjects: raw mouse is requested pwnd=%p by pti=%p",
  997. pHidTable->spwndTargetMouse, pti);
  998. Unlock(&pHidTable->spwndTargetMouse);
  999. pHidTable->fRawMouse = pHidTable->fNoLegacyMouse = FALSE;
  1000. #ifdef GI_SINK
  1001. if (pHidTable->fRawMouseSink) {
  1002. DbgFreDec(cMouseSinks);
  1003. pHidTable->fRawMouseSink = FALSE;
  1004. }
  1005. #endif
  1006. }
  1007. /*
  1008. * Free up the cached input type, in case it's for the current thread.
  1009. * LATER: clean this up only pLastRequest belongs to this thread.
  1010. */
  1011. ClearProcessTableCache(pHidTable);
  1012. CheckCritIn();
  1013. EnterDeviceInfoListCrit();
  1014. /*
  1015. * Delete all process device requests that have
  1016. * a target window belongs to this thread.
  1017. */
  1018. for (pList = pHidTable->InclusionList.Flink; pList != &pHidTable->InclusionList;) {
  1019. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  1020. pList = pList->Flink;
  1021. if (pHid->spwndTarget && GETPTI(pHid->spwndTarget) == pti) {
  1022. RIPMSG4(RIP_WARNING, "DestroyThreadHidObjects: HID inc. request (%x,%x) pwnd=%p pti=%p",
  1023. pHid->usUsagePage, pHid->usUsage, pHid->spwndTarget, pti);
  1024. FreeHidProcessRequest(pHid, HID_INCLUDE GI_SINK_PARAM(pHidTable));
  1025. }
  1026. }
  1027. for (pList = pHidTable->UsagePageList.Flink; pList != &pHidTable->UsagePageList;) {
  1028. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  1029. pList = pList->Flink;
  1030. if (pHid->spwndTarget && GETPTI(pHid->spwndTarget) == pti) {
  1031. RIPMSG4(RIP_WARNING, "DestroyThreadHidObjects: HID page-only request (%x,%x) pwnd=%p pti=%p",
  1032. pHid->usUsagePage, pHid->usUsage, pHid->spwndTarget, pti);
  1033. FreeHidProcessRequest(pHid, HID_PAGEONLY GI_SINK_PARAM(pHidTable));
  1034. }
  1035. }
  1036. for (pList = pHidTable->ExclusionList.Flink; pList != &pHidTable->ExclusionList;) {
  1037. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  1038. pList = pList->Flink;
  1039. UserAssert(pHid->spwndTarget == NULL);
  1040. if (pHid->spwndTarget && GETPTI(pHid->spwndTarget) == pti) {
  1041. RIPMSG4(RIP_WARNING, "DestroyThreadHidObjects: HID excl. request (%x,%x) pwnd=%p pti=%p",
  1042. pHid->usUsagePage, pHid->usUsage, pHid->spwndTarget, pti);
  1043. FreeHidProcessRequest(pHid, HID_EXCLUDE GI_SINK_PARAM(pHidTable));
  1044. }
  1045. }
  1046. LeaveDeviceInfoListCrit();
  1047. }
  1048. /***************************************************************************\
  1049. * InitializeHidRequestList
  1050. *
  1051. * Global request list initialization
  1052. \***************************************************************************/
  1053. void InitializeHidRequestList()
  1054. {
  1055. InitializeListHead(&gHidRequestTable.TLCInfoList);
  1056. InitializeListHead(&gHidRequestTable.UsagePageList);
  1057. #ifdef GI_SINK
  1058. InitializeListHead(&gHidRequestTable.ProcessRequestList);
  1059. #endif
  1060. }
  1061. /***************************************************************************\
  1062. * CleanupHidRequestList
  1063. *
  1064. * Global HID requests cleanup
  1065. *
  1066. * See Win32kNtUserCleanup.
  1067. * N.b. This rountine is supposed to be called before cleaning up
  1068. * the deviceinfo list.
  1069. \***************************************************************************/
  1070. void CleanupHidRequestList()
  1071. {
  1072. PLIST_ENTRY pList;
  1073. CheckDeviceInfoListCritIn();
  1074. pList = gHidRequestTable.TLCInfoList.Flink;
  1075. while (pList != &gHidRequestTable.TLCInfoList) {
  1076. PHID_TLC_INFO pTLCInfo = CONTAINING_RECORD(pList, HID_TLC_INFO, link);
  1077. /*
  1078. * The contents may be freed later, so get the next link as the first thing.
  1079. */
  1080. pList = pList->Flink;
  1081. /*
  1082. * Set the process reference counter to zero, so that the FreeDeviceInfo() later can actually free
  1083. * this device request.
  1084. */
  1085. pTLCInfo->cDirectRequest = pTLCInfo->cUsagePageRequest = pTLCInfo->cExcludeRequest =
  1086. pTLCInfo->cExcludeOrphaned = 0;
  1087. if (pTLCInfo->cDevices == 0) {
  1088. /*
  1089. * If this has zero deviceinfo reference, it can be directly freed here.
  1090. */
  1091. FreeHidTLCInfo(pTLCInfo);
  1092. }
  1093. }
  1094. /*
  1095. * Free PageOnly list.
  1096. * Since this list is not referenced from DeviceInfo, it's safe to directly free it here.
  1097. */
  1098. while (!IsListEmpty(&gHidRequestTable.UsagePageList)) {
  1099. PHID_PAGEONLY_REQUEST pPOReq = CONTAINING_RECORD(gHidRequestTable.UsagePageList.Flink, HID_PAGEONLY_REQUEST, link);
  1100. /*
  1101. * Set the process reference count to zero.
  1102. */
  1103. pPOReq->cRefCount = 0;
  1104. /*
  1105. * No need to fixup the HidTLCInfo's page-only request
  1106. * count, as allthe TLCInfo has been freed already.
  1107. */
  1108. FreeHidPageOnlyRequest(pPOReq);
  1109. }
  1110. }
  1111. /***************************************************************************\
  1112. * GetOperationMode
  1113. *
  1114. * This function converts the RAWINPUTDEVICE::dwFlags to the internal
  1115. * operation mode.
  1116. \***************************************************************************/
  1117. __inline DWORD GetOperationMode(
  1118. PCRAWINPUTDEVICE pDev,
  1119. BOOL fLegacyDevice)
  1120. {
  1121. DWORD dwFlags = 0;
  1122. UNREFERENCED_PARAMETER(fLegacyDevice);
  1123. /*
  1124. * Prepare the information
  1125. */
  1126. if (RIDEV_EXMODE(pDev->dwFlags) == RIDEV_PAGEONLY) {
  1127. UserAssert(pDev->usUsage == 0);
  1128. /*
  1129. * The app want all the Usage in this UsagePage.
  1130. */
  1131. dwFlags = HID_PAGEONLY;
  1132. } else if (RIDEV_EXMODE(pDev->dwFlags) == RIDEV_EXCLUDE) {
  1133. UserAssert(pDev->usUsage != 0);
  1134. UserAssert(pDev->hwndTarget == NULL);
  1135. UserAssert((pDev->dwFlags & RIDEV_INPUTSINK) == 0);
  1136. dwFlags = HID_EXCLUDE;
  1137. } else if (RIDEV_EXMODE(pDev->dwFlags) == RIDEV_INCLUDE || RIDEV_EXMODE(pDev->dwFlags) == RIDEV_NOLEGACY) {
  1138. UserAssert(pDev->usUsage != 0);
  1139. /*
  1140. * NOLEGACY can be only specified for the legacy devices.
  1141. */
  1142. UserAssertMsg2(RIDEV_EXMODE(pDev->dwFlags) == RIDEV_INCLUDE || fLegacyDevice,
  1143. "RIDEV_NOLEGACY is specified for non legacy device (%x,%x)",
  1144. pDev->usUsagePage, pDev->usUsage);
  1145. dwFlags = HID_INCLUDE;
  1146. } else {
  1147. UserAssert(FALSE);
  1148. }
  1149. return dwFlags;
  1150. }
  1151. /***************************************************************************\
  1152. * SetLegacyDeviceFlags
  1153. *
  1154. * This function sets or resets the NoLegacy flags and CaptureMouse flag
  1155. * when processing each request.
  1156. \***************************************************************************/
  1157. void SetLegacyDeviceFlags(
  1158. PPROCESS_HID_TABLE pHidTable,
  1159. PCRAWINPUTDEVICE pDev)
  1160. {
  1161. UserAssert(IsLegacyDevice(pDev->usUsagePage, pDev->usUsage));
  1162. if (RIDEV_EXMODE(pDev->dwFlags) == RIDEV_INCLUDE || RIDEV_EXMODE(pDev->dwFlags) == RIDEV_NOLEGACY) {
  1163. if (IsKeyboardDevice(pDev->usUsagePage, pDev->usUsage)) {
  1164. pHidTable->fNoLegacyKeyboard = (RIDEV_EXMODE(pDev->dwFlags) == RIDEV_NOLEGACY);
  1165. pHidTable->fNoHotKeys = ((pDev->dwFlags & RIDEV_NOHOTKEYS) != 0);
  1166. pHidTable->fAppKeys = ((pDev->dwFlags & RIDEV_APPKEYS) != 0);
  1167. } else if (IsMouseDevice(pDev->usUsagePage, pDev->usUsage)) {
  1168. pHidTable->fNoLegacyMouse = RIDEV_EXMODE(pDev->dwFlags) == RIDEV_NOLEGACY;
  1169. pHidTable->fCaptureMouse = (pDev->dwFlags & RIDEV_CAPTUREMOUSE) != 0;
  1170. }
  1171. }
  1172. }
  1173. /***************************************************************************\
  1174. * InsertProcRequest
  1175. *
  1176. * This function inserts the ProcRequest into ppi->pHidTable.
  1177. * This function also maintains the reference counter of TLCInfo and
  1178. * PORequest.
  1179. \***************************************************************************/
  1180. BOOL InsertProcRequest(
  1181. PPROCESSINFO ppi,
  1182. PCRAWINPUTDEVICE pDev,
  1183. PPROCESS_HID_REQUEST pHid,
  1184. #if DBG
  1185. PPROCESS_HID_REQUEST pHidOrg,
  1186. #endif
  1187. DWORD dwFlags,
  1188. BOOL fLegacyDevice,
  1189. PWND pwnd)
  1190. {
  1191. /*
  1192. * Update the global list.
  1193. */
  1194. if (dwFlags == HID_INCLUDE) {
  1195. if (!fLegacyDevice) {
  1196. PHID_TLC_INFO pTLCInfo = SearchHidTLCInfo(pHid->usUsagePage, pHid->usUsage);
  1197. if (pTLCInfo == NULL) {
  1198. UserAssert(pHidOrg == NULL);
  1199. #if DBG
  1200. DBGValidateHidRequestIsNew(pHid->usUsagePage, pHid->usUsage);
  1201. #endif
  1202. /*
  1203. * There is no such device type request allocated yet.
  1204. * Create a new one now.
  1205. */
  1206. pTLCInfo = AllocateAndLinkHidTLCInfo(pHid->usUsagePage, pHid->usUsage);
  1207. if (pTLCInfo == NULL) {
  1208. RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "AddNewProcDeviceRequest: failed to allocate pTLCInfo.");
  1209. return FALSE;
  1210. }
  1211. }
  1212. pHid->pTLCInfo = pTLCInfo;
  1213. ++pTLCInfo->cDirectRequest;
  1214. }
  1215. /*
  1216. * Lock the target window.
  1217. */
  1218. Lock(&pHid->spwndTarget, pwnd);
  1219. /*
  1220. * Link it in.
  1221. */
  1222. InsertHeadList(&ppi->pHidTable->InclusionList, &pHid->link);
  1223. TAGMSG2(DBGTAG_PNP, "AddNewProcDeviceRequest: include (%x, %x)", pHid->usUsagePage, pHid->usUsage);
  1224. } else if (dwFlags == HID_PAGEONLY) {
  1225. PHID_PAGEONLY_REQUEST pPOReq = SearchHidPageOnlyRequest(pHid->usUsagePage);
  1226. if (pPOReq == NULL) {
  1227. UserAssert(pHidOrg == NULL);
  1228. /*
  1229. * Create a new one.
  1230. */
  1231. pPOReq = AllocateAndLinkHidPageOnlyRequest(pHid->usUsagePage);
  1232. if (pPOReq == NULL) {
  1233. RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "AddNewProcDeviceRequest: failed to allocate pPOReq");
  1234. return FALSE;
  1235. }
  1236. }
  1237. pHid->pPORequest = pPOReq;
  1238. ++pPOReq->cRefCount;
  1239. /*
  1240. * Update the page-only refcount in TLCInfo
  1241. */
  1242. SetHidPOCountToTLCInfo(pHid->usUsagePage, pPOReq->cRefCount, FALSE);
  1243. /*
  1244. * Lock the target window.
  1245. */
  1246. Lock(&pHid->spwndTarget, pwnd);
  1247. /*
  1248. * Link it in.
  1249. */
  1250. InsertHeadList(&ppi->pHidTable->UsagePageList, &pHid->link);
  1251. TAGMSG2(DBGTAG_PNP, "AddNewProcDeviceRequest: pageonly (%x, %x)", pHid->usUsagePage, pHid->usUsage);
  1252. } else if (dwFlags == HID_EXCLUDE) {
  1253. /*
  1254. * Add new Exclude request...
  1255. * N.b. this may become orphaned exclusive request later.
  1256. * For now let's pretend if it's a legit exclusive request.
  1257. */
  1258. if (!fLegacyDevice) {
  1259. PHID_TLC_INFO pTLCInfo = SearchHidTLCInfo(pHid->usUsagePage, pHid->usUsage);
  1260. if (pTLCInfo == NULL) {
  1261. UserAssert(pHidOrg == NULL);
  1262. #if DBG
  1263. DBGValidateHidRequestIsNew(pHid->usUsagePage, pHid->usUsage);
  1264. #endif
  1265. pTLCInfo = AllocateAndLinkHidTLCInfo(pHid->usUsagePage, pHid->usUsage);
  1266. if (pTLCInfo == NULL) {
  1267. RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "AddNewProcDeviceRequest: failed to allocate pTLCInfo for exlusion");
  1268. return FALSE;
  1269. }
  1270. }
  1271. pHid->pTLCInfo = pTLCInfo;
  1272. ++pTLCInfo->cExcludeRequest;
  1273. UserAssert(pHid->fExclusiveOrphaned == FALSE);
  1274. UserAssert(pHid->spwndTarget == NULL); // This is a new allocation, should be no locked pwnd.
  1275. }
  1276. /*
  1277. * Link it in.
  1278. */
  1279. InsertHeadList(&ppi->pHidTable->ExclusionList, &pHid->link);
  1280. TAGMSG2(DBGTAG_PNP, "AddNewProcDeviceRequest: exlude (%x, %x)", pHid->usUsagePage, pHid->usUsage);
  1281. }
  1282. /*
  1283. * After this point, as pHid is already linked in pHidTable,
  1284. * no simple return is allowed, without a legit cleanup.
  1285. */
  1286. #ifdef GI_SINK
  1287. /*
  1288. * Set the sinkable flag.
  1289. */
  1290. if (pDev->dwFlags & RIDEV_INPUTSINK) {
  1291. /*
  1292. * Exclude request cannot be a sink. This should have been
  1293. * checked in the validation code by now.
  1294. */
  1295. UserAssert(RIDEV_EXMODE(pDev->dwFlags) != RIDEV_EXCLUDE);
  1296. /*
  1297. * Sink request should specify the target hwnd.
  1298. * The validation is supposed to check it beforehand.
  1299. */
  1300. UserAssert(pwnd);
  1301. UserAssert(ppi->pHidTable->nSinks >= 0); // LATER
  1302. if (!fLegacyDevice) {
  1303. /*
  1304. * We count the sink for the non legacy devices only, so that
  1305. * we can save clocks to walk through the request list.
  1306. */
  1307. if (!pHid->fSinkable) {
  1308. ++ppi->pHidTable->nSinks;
  1309. DbgFreInc(cHidSinks);
  1310. }
  1311. }
  1312. /*
  1313. * Set this request as sink.
  1314. */
  1315. pHid->fSinkable = TRUE;
  1316. }
  1317. #endif
  1318. return TRUE;
  1319. }
  1320. /***************************************************************************\
  1321. * RemoveProcRequest
  1322. *
  1323. * This function temporarily removes the ProcRequest from pHidTable
  1324. * and global TLCInfo / PORequest. This function also updates the
  1325. * reference counters in TLCInfo / PORequest. The sink counter in
  1326. * pHidTable is also updated.
  1327. \***************************************************************************/
  1328. void RemoveProcRequest(
  1329. PPROCESSINFO ppi,
  1330. PPROCESS_HID_REQUEST pHid,
  1331. DWORD dwFlags,
  1332. BOOL fLegacyDevice)
  1333. {
  1334. /*
  1335. * Unlock the target window.
  1336. */
  1337. Unlock(&pHid->spwndTarget);
  1338. switch (dwFlags) {
  1339. case HID_INCLUDE:
  1340. DerefIncludeRequest(pHid, ppi->pHidTable, fLegacyDevice, FALSE);
  1341. break;
  1342. case HID_PAGEONLY:
  1343. DerefPageOnlyRequest(pHid, ppi->pHidTable, FALSE);
  1344. break;
  1345. case HID_EXCLUDE:
  1346. DerefExcludeRequest(pHid, fLegacyDevice, FALSE);
  1347. }
  1348. RemoveEntryList(&pHid->link);
  1349. }
  1350. /***************************************************************************\
  1351. * SetProcDeviceRequest
  1352. *
  1353. * This function updates the ProcHidRequest based on RAWINPUTDEVICE.
  1354. * This function also sets some of the legacy device flags, such as
  1355. * NoLegacy or CaptureMouse / NoDefSystemKeys.
  1356. \***************************************************************************/
  1357. BOOL SetProcDeviceRequest(
  1358. PPROCESSINFO ppi,
  1359. PCRAWINPUTDEVICE pDev,
  1360. PPROCESS_HID_REQUEST pHidOrg,
  1361. DWORD dwFlags)
  1362. {
  1363. PPROCESS_HID_REQUEST pHid = pHidOrg;
  1364. BOOL fLegacyDevice = IsLegacyDevice(pDev->usUsagePage, pDev->usUsage);
  1365. PWND pwnd;
  1366. DWORD dwOperation;
  1367. TAGMSG3(DBGTAG_PNP, "SetProcDeviceRequest: processing (%x, %x) to ppi=%p",
  1368. pDev->usUsagePage, pDev->usUsage, ppi);
  1369. CheckDeviceInfoListCritIn();
  1370. if (pDev->hwndTarget) {
  1371. pwnd = ValidateHwnd(pDev->hwndTarget);
  1372. if (pwnd == NULL) {
  1373. RIPMSG2(RIP_WARNING, "SetProcDeviceRequest: hwndTarget (%p) in pDev (%p) is bogus",
  1374. pDev->hwndTarget, pDev);
  1375. return FALSE;
  1376. }
  1377. } else {
  1378. pwnd = NULL;
  1379. }
  1380. dwOperation = GetOperationMode(pDev, fLegacyDevice);
  1381. if (dwFlags == 0) {
  1382. UserAssert(pHid == NULL);
  1383. } else {
  1384. UserAssert(pHid);
  1385. }
  1386. if (pHid == NULL) {
  1387. /*
  1388. * If this is a new request for this TLC, allocate it here.
  1389. */
  1390. pHid = AllocateHidProcessRequest(pDev->usUsagePage, pDev->usUsage);
  1391. if (pHid == NULL) {
  1392. RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "SetRawInputDevices: failed to allocate pHid.");
  1393. goto error_exit;
  1394. }
  1395. }
  1396. /*
  1397. * Firstly remove this guy temporarily from the list.
  1398. */
  1399. if (pHidOrg) {
  1400. UserAssert(pHidOrg->usUsagePage == pDev->usUsagePage && pHidOrg->usUsage == pDev->usUsage);
  1401. RemoveProcRequest(ppi, pHidOrg, dwFlags, fLegacyDevice);
  1402. pHid = pHidOrg;
  1403. }
  1404. if (!InsertProcRequest(ppi, pDev, pHid,
  1405. #if DBG
  1406. pHidOrg,
  1407. #endif
  1408. dwOperation, fLegacyDevice, pwnd)) {
  1409. /*
  1410. * The error case in InsertProcRequest should be TLCInfo
  1411. * allocation error, so it couldn't be legacy devices.
  1412. */
  1413. UserAssert(!fLegacyDevice);
  1414. goto error_exit;
  1415. }
  1416. if (fLegacyDevice) {
  1417. SetLegacyDeviceFlags(ppi->pHidTable, pDev);
  1418. }
  1419. /*
  1420. * Succeeded.
  1421. */
  1422. return TRUE;
  1423. error_exit:
  1424. if (pHid) {
  1425. /*
  1426. * Let's make sure it's not in the request list.
  1427. */
  1428. DBGValidateHidReqNotInList(ppi, pHid);
  1429. /*
  1430. * Free this error-prone request.
  1431. */
  1432. UserFreePool(pHid);
  1433. }
  1434. return FALSE;
  1435. }
  1436. /***************************************************************************\
  1437. * HidRequestValidityCheck
  1438. *
  1439. \***************************************************************************/
  1440. BOOL HidRequestValidityCheck(
  1441. const PRAWINPUTDEVICE pDev)
  1442. {
  1443. PWND pwnd = NULL;
  1444. if (pDev->dwFlags & ~RIDEV_VALID) {
  1445. RIPERR1(ERROR_INVALID_FLAGS, RIP_WARNING, "HidRequestValidityCheck: invalid flag %x", pDev->dwFlags);
  1446. return FALSE;
  1447. }
  1448. if (pDev->usUsagePage == 0) {
  1449. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: usUsagePage is 0");
  1450. return FALSE;
  1451. }
  1452. /*
  1453. * If hwndTarget is specified, validate it here.
  1454. */
  1455. if (pDev->hwndTarget) {
  1456. pwnd = ValidateHwnd(pDev->hwndTarget);
  1457. }
  1458. /*
  1459. * Reject invalid CaptureMouse / NoSystemKeys flags.
  1460. */
  1461. #if (RIDEV_CAPTUREMOUSE != RIDEV_NOHOTKEYS)
  1462. #error The value of RIDEV_CAPTUREMOUSE and RIDEV_NOSYSTEMKEYS should match.
  1463. #endif
  1464. if (pDev->dwFlags & RIDEV_CAPTUREMOUSE) {
  1465. if (IsMouseDevice(pDev->usUsagePage, pDev->usUsage)) {
  1466. if (RIDEV_EXMODE(pDev->dwFlags) != RIDEV_NOLEGACY ||
  1467. pwnd == NULL || GETPTI(pwnd)->ppi != PpiCurrent()) {
  1468. RIPERR4(ERROR_INVALID_FLAGS, RIP_WARNING, "HidRequestValidityCheck: invalid request (%x,%x) dwf %x hwnd %p "
  1469. "found for RIDEV_CAPTUREMOUSE",
  1470. pDev->usUsagePage, pDev->usUsage, pDev->dwFlags, pDev->hwndTarget);
  1471. return FALSE;
  1472. }
  1473. } else if (!IsKeyboardDevice(pDev->usUsagePage, pDev->usUsage)) {
  1474. RIPERR4(ERROR_INVALID_FLAGS, RIP_WARNING, "HidRequestValidityCheck: invalid request (%x,%x) dwf %x hwnd %p "
  1475. "found for RIDEV_CAPTUREMOUSE",
  1476. pDev->usUsagePage, pDev->usUsage, pDev->dwFlags, pDev->hwndTarget);
  1477. return FALSE;
  1478. }
  1479. }
  1480. if (pDev->dwFlags & RIDEV_APPKEYS) {
  1481. if (!IsKeyboardDevice(pDev->usUsagePage, pDev->usUsage) ||
  1482. (RIDEV_EXMODE(pDev->dwFlags) != RIDEV_NOLEGACY)) {
  1483. RIPERR4(ERROR_INVALID_FLAGS, RIP_WARNING, "HidRequestValidityCheck: invalid request (%x,%x) dwf %x hwnd %p "
  1484. "found for RIDEV_APPKEYS",
  1485. pDev->usUsagePage, pDev->usUsage, pDev->dwFlags, pDev->hwndTarget);
  1486. return FALSE;
  1487. }
  1488. }
  1489. /*
  1490. * RIDEV_REMOVE only takes PAGEONLY or ADD_OR_MODIFY.
  1491. */
  1492. if ((pDev->dwFlags & RIDEV_MODEMASK) == RIDEV_REMOVE) {
  1493. // LATER: too strict?
  1494. if (RIDEV_EXMODE(pDev->dwFlags) == RIDEV_EXCLUDE || RIDEV_EXMODE(pDev->dwFlags) == RIDEV_NOLEGACY) {
  1495. RIPERR0(ERROR_INVALID_FLAGS, RIP_WARNING, "HidRequestValidityCheck: remove and (exlude or nolegacy)");
  1496. return FALSE;
  1497. }
  1498. if (pDev->hwndTarget != NULL) {
  1499. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: hwndTarget is specified for remove operation.");
  1500. return FALSE;
  1501. }
  1502. }
  1503. /*
  1504. * Check EXMODE
  1505. */
  1506. switch (RIDEV_EXMODE(pDev->dwFlags)) {
  1507. case RIDEV_EXCLUDE:
  1508. #ifdef GI_SINK
  1509. if (pDev->dwFlags & RIDEV_INPUTSINK) {
  1510. RIPERR2(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: Exclude request cannot have RIDEV_INPUTSINK for UP=%x, U=%x",
  1511. pDev->usUsagePage, pDev->usUsage);
  1512. return FALSE;
  1513. }
  1514. /* FALL THROUGH */
  1515. #endif
  1516. case RIDEV_INCLUDE:
  1517. if (pDev->usUsage == 0) {
  1518. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: usUsage is 0 without RIDEV_PAGEONLY for UP=%x",
  1519. pDev->usUsagePage);
  1520. return FALSE;
  1521. }
  1522. break;
  1523. case RIDEV_PAGEONLY:
  1524. if (pDev->usUsage != 0) {
  1525. RIPERR2(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: UsagePage-only has Usage UP=%x, U=%x",
  1526. pDev->usUsagePage, pDev->usUsage);
  1527. return FALSE;
  1528. }
  1529. break;
  1530. case RIDEV_NOLEGACY:
  1531. if (!IsLegacyDevice(pDev->usUsagePage, pDev->usUsage)) {
  1532. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: NOLEGACY is specified to non legacy device.");
  1533. return FALSE;
  1534. }
  1535. break;
  1536. default:
  1537. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: invalid exmode=%x", RIDEV_EXMODE(pDev->dwFlags));
  1538. return FALSE;
  1539. }
  1540. /*
  1541. * Check if pDev->hwndTarget is a valid handle.
  1542. */
  1543. if (RIDEV_EXMODE(pDev->dwFlags) == RIDEV_EXCLUDE) {
  1544. #ifdef GI_SINK
  1545. if (pDev->dwFlags & RIDEV_INPUTSINK) {
  1546. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: input sink is specified for exclude.");
  1547. return FALSE;
  1548. }
  1549. #endif
  1550. if (pDev->hwndTarget != NULL) {
  1551. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: hwndTarget %p cannot be specified for exlusion.",
  1552. pDev->hwndTarget);
  1553. return FALSE;
  1554. }
  1555. } else {
  1556. if (pDev->hwndTarget && pwnd == NULL) {
  1557. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: hwndTarget %p is invalid.", pDev->hwndTarget);
  1558. return FALSE;
  1559. }
  1560. if (pwnd && GETPTI(pwnd)->ppi != PpiCurrent()) {
  1561. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: pwndTarget %p belongs to different process",
  1562. pwnd);
  1563. return FALSE;
  1564. }
  1565. #ifdef GI_SINK
  1566. if ((pDev->dwFlags & RIDEV_INPUTSINK) && pwnd == NULL) {
  1567. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "HidRequestValidityCheck: RIDEV_INPUTSINK requires hwndTarget");
  1568. return FALSE;
  1569. }
  1570. #endif
  1571. }
  1572. return TRUE;
  1573. }
  1574. /***************************************************************************\
  1575. * ClearProcessTableCache
  1576. *
  1577. * Clear up the input type cache in the process request table.
  1578. \***************************************************************************/
  1579. void ClearProcessTableCache(PPROCESS_HID_TABLE pHidTable)
  1580. {
  1581. pHidTable->pLastRequest = NULL;
  1582. pHidTable->UsagePageLast = pHidTable->UsageLast = 0;
  1583. }
  1584. /***************************************************************************\
  1585. * AdjustLegacyDeviceFlags
  1586. *
  1587. * Adjust the request and sink flags for legacy devices in the process
  1588. * request table, as the last thing in RegisterRawInputDevices.
  1589. * N.b. sink and raw flags need to be set at the last thing in
  1590. * RegsiterRawInputDevices, as it may be implicitly requested through the
  1591. * page-only request.
  1592. * Also this function sets up the target window for legacy devices.
  1593. \***************************************************************************/
  1594. void AdjustLegacyDeviceFlags(PPROCESSINFO ppi)
  1595. {
  1596. PPROCESS_HID_TABLE pHidTable = ppi->pHidTable;
  1597. PPROCESS_HID_REQUEST phr;
  1598. /*
  1599. * Adjust the keyboard sink flag and target window.
  1600. */
  1601. if (phr = InProcessDeviceTypeRequestTable(pHidTable,
  1602. HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_KEYBOARD)) {
  1603. TAGMSG1(DBGTAG_PNP, "AdjustLegacyDeviceFlags: raw keyboard is requested in ppi=%p", ppi);
  1604. pHidTable->fRawKeyboard = TRUE;
  1605. #ifdef GI_SINK
  1606. UserAssert(!phr->fSinkable || phr->spwndTarget);
  1607. if (pHidTable->fRawKeyboardSink != phr->fSinkable) {
  1608. TAGMSG2(DBGTAG_PNP, "AdjustLegacyDeviceFlags: kbd prevSink=%x newSink=%x",
  1609. pHidTable->fRawKeyboardSink, phr->fSinkable);
  1610. if (phr->fSinkable) {
  1611. DbgFreInc(cKbdSinks);
  1612. } else {
  1613. DbgFreDec(cKbdSinks);
  1614. }
  1615. pHidTable->fRawKeyboardSink = phr->fSinkable;
  1616. }
  1617. #endif
  1618. Lock(&pHidTable->spwndTargetKbd, phr->spwndTarget);
  1619. } else {
  1620. TAGMSG1(DBGTAG_PNP, "AdjustLegacyDeviceFlags: raw keyboard is NOT requested in ppi=%p", ppi);
  1621. pHidTable->fRawKeyboard = pHidTable->fNoLegacyKeyboard = FALSE;
  1622. pHidTable->fNoHotKeys = FALSE;
  1623. pHidTable->fAppKeys = FALSE;
  1624. #ifdef GI_SINK
  1625. if (pHidTable->fRawKeyboardSink) {
  1626. DbgFreDec(cKbdSinks);
  1627. TAGMSG0(DBGTAG_PNP, "AdjustLegacyDeviceFlags: kbd prevSink was true");
  1628. }
  1629. pHidTable->fRawKeyboardSink = FALSE;
  1630. #endif
  1631. Unlock(&pHidTable->spwndTargetKbd);
  1632. }
  1633. /*
  1634. * Adjust the mouse sink flags and target window.
  1635. */
  1636. if (phr = InProcessDeviceTypeRequestTable(pHidTable,
  1637. HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_MOUSE)) {
  1638. TAGMSG1(DBGTAG_PNP, "AdjustLegacyDeviceFlags: raw mouse is requested in ppi=%p", ppi);
  1639. pHidTable->fRawMouse = TRUE;
  1640. #ifdef GI_SINK
  1641. UserAssert(!phr->fSinkable || phr->spwndTarget);
  1642. if (pHidTable->fRawMouseSink != phr->fSinkable) {
  1643. TAGMSG2(DBGTAG_PNP, "AdjustLegacyDeviceFlags: mouse prevSink=%x newSink=%x",
  1644. pHidTable->fRawMouseSink, phr->fSinkable);
  1645. if (phr->fSinkable) {
  1646. DbgFreInc(cMouseSinks);
  1647. }
  1648. else {
  1649. DbgFreDec(cMouseSinks);
  1650. }
  1651. pHidTable->fRawMouseSink = phr->fSinkable;
  1652. }
  1653. #endif
  1654. Lock(&pHidTable->spwndTargetMouse, phr->spwndTarget);
  1655. } else {
  1656. TAGMSG1(DBGTAG_PNP, "AdjustLegacyDeviceFlags: raw mouse is NOT requested in ppi=%p", ppi);
  1657. pHidTable->fRawMouse = pHidTable->fNoLegacyMouse = pHidTable->fCaptureMouse = FALSE;
  1658. #ifdef GI_SINK
  1659. if (pHidTable->fRawMouseSink) {
  1660. TAGMSG0(DBGTAG_PNP, "AdjustLegacyDeviceFlags: mouse prevSink was true");
  1661. DbgFreDec(cMouseSinks);
  1662. }
  1663. pHidTable->fRawMouseSink = FALSE;
  1664. #endif
  1665. Unlock(&pHidTable->spwndTargetMouse);
  1666. }
  1667. #if DBG
  1668. /*
  1669. * Check NoLegacy and CaptureMouse legitimacy.
  1670. */
  1671. if (!pHidTable->fNoLegacyMouse) {
  1672. UserAssert(!pHidTable->fCaptureMouse);
  1673. }
  1674. #endif
  1675. }
  1676. /***************************************************************************\
  1677. * CleanupFreedTLCInfo
  1678. *
  1679. * This routine clears the TLCInfo and PageOnlyReq that are no longer
  1680. * ref-counted.
  1681. \***************************************************************************/
  1682. VOID CleanupFreedTLCInfo()
  1683. {
  1684. PLIST_ENTRY pList;
  1685. /*
  1686. * The caller has to ensure being in the device list critical section.
  1687. */
  1688. CheckDeviceInfoListCritIn();
  1689. /*
  1690. * Walk through the list, free the TLCInfo if it's not ref-counted.
  1691. */
  1692. for (pList = gHidRequestTable.TLCInfoList.Flink; pList != &gHidRequestTable.TLCInfoList;) {
  1693. PHID_TLC_INFO pTLCInfo = CONTAINING_RECORD(pList, HID_TLC_INFO, link);
  1694. /*
  1695. * Get the next link, before this gets freed.
  1696. */
  1697. pList = pList->Flink;
  1698. if (HidTLCInfoNoReference(pTLCInfo)) {
  1699. TAGMSG3(DBGTAG_PNP, "CleanupFreedTLCInfo: freeing TLCInfo=%p (%x, %x)", pTLCInfo,
  1700. pTLCInfo->usUsagePage, pTLCInfo->usUsage);
  1701. FreeHidTLCInfo(pTLCInfo);
  1702. }
  1703. }
  1704. /*
  1705. * Walk though the Page-only request list, free it if it's not ref-counted.
  1706. */
  1707. for (pList = gHidRequestTable.UsagePageList.Flink; pList != &gHidRequestTable.UsagePageList; ) {
  1708. PHID_PAGEONLY_REQUEST pPOReq = CONTAINING_RECORD(pList, HID_PAGEONLY_REQUEST, link);
  1709. /*
  1710. * Get the next link before it's freed.
  1711. */
  1712. pList = pList->Flink;
  1713. if (pPOReq->cRefCount == 0) {
  1714. FreeHidPageOnlyRequest(pPOReq);
  1715. }
  1716. }
  1717. }
  1718. /***************************************************************************\
  1719. * FixupOrphanedExclusiveRequests
  1720. *
  1721. * Adjust the exclusiveness counter in the global TLC info.
  1722. * Sometimes there's orphaned exclusive request that really should not take
  1723. * global effect.
  1724. \***************************************************************************/
  1725. void FixupOrphanedExclusiveRequests(PPROCESSINFO ppi)
  1726. {
  1727. PLIST_ENTRY pList;
  1728. PPROCESS_HID_TABLE pHidTable = ppi->pHidTable;
  1729. for (pList = pHidTable->ExclusionList.Flink; pList != &pHidTable->ExclusionList; pList = pList->Flink) {
  1730. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  1731. if (IsLegacyDevice(pHid->usUsagePage, pHid->usUsage)) {
  1732. UserAssert(pHid->fExclusiveOrphaned == FALSE);
  1733. } else {
  1734. PPROCESS_HID_REQUEST pPageOnly;
  1735. UserAssert(pHid->spwndTarget == NULL);
  1736. UserAssert(pHid->pTLCInfo);
  1737. /*
  1738. * Search if we have the page-only request for this UsagePage.
  1739. */
  1740. pPageOnly = SearchProcessHidRequestUsagePage(pHidTable, pHid->usUsagePage);
  1741. if (pPageOnly) {
  1742. /*
  1743. * OK, corresponding page-only request is found, this one
  1744. * is not orphaned.
  1745. */
  1746. if (pHid->fExclusiveOrphaned) {
  1747. /*
  1748. * This request was previously orphaned, but not any more.
  1749. */
  1750. UserAssert(pHid->pTLCInfo->cExcludeOrphaned >= 1);
  1751. --pHid->pTLCInfo->cExcludeOrphaned;
  1752. pHid->fExclusiveOrphaned = FALSE;
  1753. }
  1754. } else {
  1755. /*
  1756. * This one is orphaned. Let's check the previous state
  1757. * to see if we need to fix up the counter(s).
  1758. */
  1759. if (!pHid->fExclusiveOrphaned) {
  1760. /*
  1761. * This request was not orphaned, but unfortunately
  1762. * due to removal of page request or some other reasons,
  1763. * becoming an orphan.
  1764. */
  1765. ++pHid->pTLCInfo->cExcludeOrphaned;
  1766. pHid->fExclusiveOrphaned = TRUE;
  1767. }
  1768. }
  1769. UserAssert(pHid->pTLCInfo->cExcludeRequest >= pHid->pTLCInfo->cExcludeOrphaned);
  1770. }
  1771. }
  1772. }
  1773. /***************************************************************************\
  1774. * _RegisterRawInputDevices
  1775. *
  1776. * API helper
  1777. \***************************************************************************/
  1778. BOOL _RegisterRawInputDevices(
  1779. PCRAWINPUTDEVICE cczpRawInputDevices,
  1780. UINT uiNumDevices)
  1781. {
  1782. PPROCESSINFO ppi;
  1783. UINT i;
  1784. API_PROLOGUE(BOOL, FALSE);
  1785. ppi = PpiCurrent();
  1786. UserAssert(ppi);
  1787. UserAssert(uiNumDevices > 0); // should have been checked in the stub
  1788. CheckDeviceInfoListCritOut();
  1789. EnterDeviceInfoListCrit();
  1790. if (ppi->pHidTable) {
  1791. /*
  1792. * Clear the last active UsagePage/Usage, so that
  1793. * the next read operation will check the updated
  1794. * request list.
  1795. */
  1796. ClearProcessTableCache(ppi->pHidTable);
  1797. }
  1798. /*
  1799. * Firstly validate all the device request.
  1800. */
  1801. for (i = 0; i < uiNumDevices; ++i) {
  1802. RAWINPUTDEVICE ridDev;
  1803. ridDev = cczpRawInputDevices[i];
  1804. /*
  1805. * Validity check
  1806. */
  1807. if (!HidRequestValidityCheck(&ridDev)) {
  1808. /*
  1809. * Indicate no real change has made.
  1810. */
  1811. i = 0;
  1812. /*
  1813. * LastError is already set in the above function,
  1814. * so let's specify zero here.
  1815. */
  1816. API_ERROR(0);
  1817. }
  1818. }
  1819. /*
  1820. * If the process hid request table is not yet allocated, allocate it now.
  1821. */
  1822. if (ppi->pHidTable == NULL) {
  1823. ppi->pHidTable = AllocateProcessHidTable();
  1824. if (ppi->pHidTable == NULL) {
  1825. RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "_RegisterRawInputDevices: failed to allocate table");
  1826. API_ERROR(0);
  1827. }
  1828. }
  1829. UserAssert(ppi->pHidTable);
  1830. for (i = 0; i < uiNumDevices; ++i) {
  1831. PPROCESS_HID_REQUEST pHid;
  1832. DWORD dwFlags;
  1833. /*
  1834. * Check if the requested device type is already in our process hid req list here,
  1835. * for it's commonly used in the following cases.
  1836. */
  1837. pHid = SearchProcessHidRequest(
  1838. ppi,
  1839. cczpRawInputDevices[i].usUsagePage,
  1840. cczpRawInputDevices[i].usUsage,
  1841. &dwFlags);
  1842. if ((cczpRawInputDevices[i].dwFlags & RIDEV_MODEMASK) == RIDEV_ADD_OR_MODIFY) {
  1843. if (!SetProcDeviceRequest(
  1844. ppi,
  1845. cczpRawInputDevices + i,
  1846. pHid,
  1847. dwFlags)) {
  1848. API_ERROR(0);
  1849. }
  1850. } else {
  1851. /*
  1852. * Remove this device, if it's in the list
  1853. */
  1854. if (pHid) {
  1855. TAGMSG4(DBGTAG_PNP, "_RegisterRawInputDevices: removing type=%x (%x, %x) from ppi=%p",
  1856. RIDEV_EXMODE(cczpRawInputDevices[i].dwFlags),
  1857. cczpRawInputDevices[i].usUsagePage, cczpRawInputDevices[i].usUsage, ppi);
  1858. FreeHidProcessRequest(pHid, dwFlags GI_SINK_PARAM(ppi->pHidTable));
  1859. } else {
  1860. RIPMSG3(
  1861. RIP_WARNING,
  1862. "_RegisterRawInputDevices: removing... TLC (%x,%x) is not registered in ppi=%p, but just ignore it",
  1863. cczpRawInputDevices[i].usUsagePage,
  1864. cczpRawInputDevices[i].usUsage,
  1865. ppi);
  1866. }
  1867. }
  1868. }
  1869. /*
  1870. * Now that we finished updating the process device request and the global request list,
  1871. * start/stop each device.
  1872. */
  1873. retval = TRUE;
  1874. /*
  1875. * API cleanup portion
  1876. */
  1877. API_CLEANUP();
  1878. if (ppi->pHidTable) {
  1879. /*
  1880. * Adjust the legacy flags in pHidTable.
  1881. */
  1882. AdjustLegacyDeviceFlags(ppi);
  1883. /*
  1884. * Check if there's orphaned exclusive requests.
  1885. */
  1886. FixupOrphanedExclusiveRequests(ppi);
  1887. /*
  1888. * Make sure the cache is cleared right.
  1889. */
  1890. UserAssert(ppi->pHidTable->pLastRequest == NULL);
  1891. UserAssert(ppi->pHidTable->UsagePageLast == 0);
  1892. UserAssert(ppi->pHidTable->UsageLast == 0);
  1893. /*
  1894. * Free TLCInfo that are no longer ref-counted.
  1895. */
  1896. CleanupFreedTLCInfo();
  1897. /*
  1898. * Start or stop reading the HID devices.
  1899. */
  1900. HidDeviceStartStop();
  1901. }
  1902. CheckupHidCounter();
  1903. LeaveDeviceInfoListCrit();
  1904. API_EPILOGUE();
  1905. }
  1906. /***************************************************************************\
  1907. * SortRegisteredDevices
  1908. *
  1909. * API helper:
  1910. * This function sorts the registered raw input devices by the shell sort.
  1911. * O(n^1.2)
  1912. * N.b. if the array is in the user-mode, this function may raise
  1913. * an exception, which is supposed to be handled by the caller.
  1914. \***************************************************************************/
  1915. __inline BOOL IsRawInputDeviceLarger(
  1916. const PRAWINPUTDEVICE pRid1,
  1917. const PRAWINPUTDEVICE pRid2)
  1918. {
  1919. return (DWORD)MAKELONG(pRid1->usUsage, pRid1->usUsagePage) > (DWORD)MAKELONG(pRid2->usUsage, pRid2->usUsagePage);
  1920. }
  1921. void SortRegisteredDevices(
  1922. PRAWINPUTDEVICE cczpRawInputDevices,
  1923. const int iSize)
  1924. {
  1925. int h;
  1926. if (iSize <= 0) {
  1927. // give up!
  1928. return;
  1929. }
  1930. // Calculate starting block size.
  1931. for (h = 1; h < iSize / 9; h = 3 * h + 1) {
  1932. UserAssert(h > 0);
  1933. }
  1934. while (h > 0) {
  1935. int i;
  1936. for (i = h; i < iSize; ++i) {
  1937. RAWINPUTDEVICE rid = cczpRawInputDevices[i];
  1938. int j;
  1939. for (j = i - h; j >= 0 && IsRawInputDeviceLarger(&cczpRawInputDevices[j], &rid); j -= h) {
  1940. cczpRawInputDevices[j + h] = cczpRawInputDevices[j];
  1941. }
  1942. if (i != j + h) {
  1943. cczpRawInputDevices[j + h] = rid;
  1944. }
  1945. }
  1946. h /= 3;
  1947. }
  1948. #if DBG
  1949. // verify
  1950. {
  1951. int i;
  1952. for (i = 1; i < iSize; ++i) {
  1953. UserAssert(cczpRawInputDevices[i - 1].usUsagePage <= cczpRawInputDevices[i].usUsagePage ||
  1954. cczpRawInputDevices[i - 1].usUsage <= cczpRawInputDevices[i].usUsage);
  1955. }
  1956. }
  1957. #endif
  1958. }
  1959. /***************************************************************************\
  1960. * _GetRegisteredRawInputDevices
  1961. *
  1962. * API helper
  1963. \***************************************************************************/
  1964. UINT _GetRegisteredRawInputDevices(
  1965. PRAWINPUTDEVICE cczpRawInputDevices,
  1966. PUINT puiNumDevices)
  1967. {
  1968. API_PROLOGUE(UINT, (UINT)-1);
  1969. PPROCESSINFO ppi;
  1970. UINT uiNumDevices;
  1971. UINT nDevices = 0;
  1972. CheckDeviceInfoListCritOut();
  1973. EnterDeviceInfoListCrit();
  1974. ppi = PpiCurrent();
  1975. UserAssert(ppi);
  1976. if (ppi->pHidTable == NULL) {
  1977. nDevices = 0;
  1978. } else {
  1979. PLIST_ENTRY pList;
  1980. for (pList = ppi->pHidTable->InclusionList.Flink; pList != &ppi->pHidTable->InclusionList; pList = pList->Flink) {
  1981. ++nDevices;
  1982. }
  1983. TAGMSG2(DBGTAG_PNP, "_GetRawInputDevices: ppi %p # inclusion %x", ppi, nDevices);
  1984. for (pList = ppi->pHidTable->UsagePageList.Flink; pList != &ppi->pHidTable->UsagePageList; pList = pList->Flink) {
  1985. ++nDevices;
  1986. }
  1987. TAGMSG1(DBGTAG_PNP, "_GetRawInputDevices: # pageonly+inclusion %x", nDevices);
  1988. for (pList = ppi->pHidTable->ExclusionList.Flink; pList != &ppi->pHidTable->ExclusionList; pList = pList->Flink) {
  1989. ++nDevices;
  1990. }
  1991. TAGMSG1(DBGTAG_PNP, "_GetRawInputDevices: # total hid request %x", nDevices);
  1992. /*
  1993. * Check Legacy Devices.
  1994. */
  1995. UserAssert(ppi->pHidTable->fRawKeyboard || !ppi->pHidTable->fNoLegacyKeyboard);
  1996. UserAssert(ppi->pHidTable->fRawMouse || !ppi->pHidTable->fNoLegacyMouse);
  1997. TAGMSG1(DBGTAG_PNP, "_GetRawInputDevices: # request including legacy devices %x", nDevices);
  1998. }
  1999. if (cczpRawInputDevices == NULL) {
  2000. /*
  2001. * Return the number of the devices in the per-process device list.
  2002. */
  2003. try {
  2004. ProbeForWrite(puiNumDevices, sizeof(UINT), sizeof(DWORD));
  2005. *puiNumDevices = nDevices;
  2006. retval = 0;
  2007. } except (StubExceptionHandler(TRUE)) {
  2008. API_ERROR(0);
  2009. }
  2010. } else {
  2011. try {
  2012. ProbeForRead(puiNumDevices, sizeof(UINT), sizeof(DWORD));
  2013. uiNumDevices = *puiNumDevices;
  2014. if (uiNumDevices == 0) {
  2015. /*
  2016. * Non-NULL buffer is specified, but the buffer size is 0.
  2017. * To probe the buffer right, this case is treated as an error.
  2018. */
  2019. API_ERROR(ERROR_INVALID_PARAMETER);
  2020. }
  2021. ProbeForWriteBuffer(cczpRawInputDevices, uiNumDevices, sizeof(DWORD));
  2022. } except (StubExceptionHandler(TRUE)) {
  2023. API_ERROR(0);
  2024. }
  2025. if (ppi->pHidTable == NULL) {
  2026. retval = 0;
  2027. } else {
  2028. PLIST_ENTRY pList;
  2029. UINT i;
  2030. if (uiNumDevices < nDevices) {
  2031. try {
  2032. ProbeForWrite(puiNumDevices, sizeof(UINT), sizeof(DWORD));
  2033. *puiNumDevices = nDevices;
  2034. API_ERROR(ERROR_INSUFFICIENT_BUFFER);
  2035. } except (StubExceptionHandler(TRUE)) {
  2036. API_ERROR(0);
  2037. }
  2038. }
  2039. try {
  2040. for (i = 0, pList = ppi->pHidTable->InclusionList.Flink; pList != &ppi->pHidTable->InclusionList && i < uiNumDevices; pList = pList->Flink, ++i) {
  2041. RAWINPUTDEVICE device;
  2042. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  2043. device.dwFlags = 0;
  2044. #ifdef GI_SINK
  2045. device.dwFlags |= (pHid->fSinkable ? RIDEV_INPUTSINK : 0);
  2046. #endif
  2047. device.usUsagePage = pHid->usUsagePage;
  2048. device.usUsage = pHid->usUsage;
  2049. device.hwndTarget = HW(pHid->spwndTarget);
  2050. if ((IsKeyboardDevice(pHid->usUsagePage, pHid->usUsage) && ppi->pHidTable->fNoLegacyKeyboard) ||
  2051. (IsMouseDevice(pHid->usUsagePage, pHid->usUsage) && ppi->pHidTable->fNoLegacyMouse)) {
  2052. device.dwFlags |= RIDEV_NOLEGACY;
  2053. }
  2054. if (IsKeyboardDevice(pHid->usUsagePage, pHid->usUsage) && ppi->pHidTable->fNoHotKeys) {
  2055. device.dwFlags |= RIDEV_NOHOTKEYS;
  2056. }
  2057. if (IsKeyboardDevice(pHid->usUsagePage, pHid->usUsage) && ppi->pHidTable->fAppKeys) {
  2058. device.dwFlags |= RIDEV_APPKEYS;
  2059. }
  2060. if (IsMouseDevice(pHid->usUsagePage, pHid->usUsage) && ppi->pHidTable->fCaptureMouse) {
  2061. device.dwFlags |= RIDEV_CAPTUREMOUSE;
  2062. }
  2063. cczpRawInputDevices[i] = device;
  2064. }
  2065. for (pList = ppi->pHidTable->UsagePageList.Flink; pList != &ppi->pHidTable->UsagePageList && i < uiNumDevices; pList = pList->Flink, ++i) {
  2066. RAWINPUTDEVICE device;
  2067. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  2068. device.dwFlags = RIDEV_PAGEONLY;
  2069. #ifdef GI_SINK
  2070. device.dwFlags |= (pHid->fSinkable ? RIDEV_INPUTSINK : 0);
  2071. #endif
  2072. device.usUsagePage = pHid->usUsagePage;
  2073. device.usUsage = pHid->usUsage;
  2074. device.hwndTarget = HW(pHid->spwndTarget);
  2075. cczpRawInputDevices[i] = device;
  2076. }
  2077. for (pList = ppi->pHidTable->ExclusionList.Flink; pList != &ppi->pHidTable->ExclusionList && i < uiNumDevices; pList = pList->Flink, ++i) {
  2078. RAWINPUTDEVICE device;
  2079. PPROCESS_HID_REQUEST pHid = CONTAINING_RECORD(pList, PROCESS_HID_REQUEST, link);
  2080. device.dwFlags = RIDEV_EXCLUDE;
  2081. #ifdef GI_SINK
  2082. UserAssert(pHid->fSinkable == FALSE);
  2083. #endif
  2084. device.usUsagePage = pHid->usUsagePage;
  2085. device.usUsage = pHid->usUsage;
  2086. device.hwndTarget = NULL;
  2087. cczpRawInputDevices[i] = device;
  2088. }
  2089. /*
  2090. * Sort the array by UsagePage and Usage.
  2091. */
  2092. SortRegisteredDevices(cczpRawInputDevices, (int)nDevices);
  2093. retval = nDevices;
  2094. } except (StubExceptionHandler(TRUE)) {
  2095. API_ERROR(0);
  2096. }
  2097. }
  2098. }
  2099. API_CLEANUP();
  2100. LeaveDeviceInfoListCrit();
  2101. API_EPILOGUE();
  2102. }
  2103. /***************************************************************************\
  2104. * AllocateHidDesc
  2105. *
  2106. * HidDesc allocation
  2107. \***************************************************************************/
  2108. PHIDDESC AllocateHidDesc(PUNICODE_STRING pustrName,
  2109. PVOID pPreparsedData,
  2110. PHIDP_CAPS pCaps,
  2111. PHID_COLLECTION_INFORMATION pHidCollectionInfo)
  2112. {
  2113. PHIDDESC pHidDesc;
  2114. CheckCritIn();
  2115. if (pPreparsedData == NULL) {
  2116. RIPMSG0(RIP_ERROR, "AllocateHidDesc: pPreparsedData is NULL.");
  2117. return NULL;
  2118. }
  2119. if (pCaps->InputReportByteLength == 0) {
  2120. RIPMSG2(RIP_WARNING, "AllocateHidDesc: InputReportByteLength for (%02x, %02x).", pCaps->UsagePage, pCaps->Usage);
  2121. return NULL;
  2122. }
  2123. pHidDesc = UserAllocPoolZInit(sizeof(HIDDESC), TAG_HIDDESC);
  2124. if (pHidDesc == NULL) {
  2125. // Failed to allocate.
  2126. RIPMSG1(RIP_WARNING, "AllocateHidDesc: failed to allocated hiddesc. name='%ws'", pustrName->Buffer);
  2127. return NULL;
  2128. }
  2129. DbgInc(cHidDesc);
  2130. /*
  2131. * Allocate the input buffer used by the asynchronouse I/O
  2132. */
  2133. pHidDesc->hidpCaps = *pCaps;
  2134. pHidDesc->pInputBuffer = UserAllocPoolNonPaged(pHidDesc->hidpCaps.InputReportByteLength * MAXIMUM_ITEMS_READ, TAG_PNP);
  2135. TAGMSG1(DBGTAG_PNP, "AllocateHidDesc: pInputBuffer=%p", pHidDesc->pInputBuffer);
  2136. if (pHidDesc->pInputBuffer == NULL) {
  2137. RIPMSG1(RIP_WARNING, "AllocateHidDesc: failed to allocate input buffer (size=%x)", pHidDesc->hidpCaps.InputReportByteLength);
  2138. FreeHidDesc(pHidDesc);
  2139. return NULL;
  2140. }
  2141. pHidDesc->pPreparsedData = pPreparsedData;
  2142. pHidDesc->hidCollectionInfo = *pHidCollectionInfo;
  2143. TAGMSG1(DBGTAG_PNP, "AllocateHidDesc: returning %p", pHidDesc);
  2144. return pHidDesc;
  2145. UNREFERENCED_PARAMETER(pustrName);
  2146. }
  2147. /***************************************************************************\
  2148. * FreeHidDesc
  2149. *
  2150. * HidDesc destruction
  2151. \***************************************************************************/
  2152. void FreeHidDesc(PHIDDESC pDesc)
  2153. {
  2154. CheckCritIn();
  2155. UserAssert(pDesc);
  2156. TAGMSG2(DBGTAG_PNP | RIP_THERESMORE, "FreeHidDesc entered for (%x, %x)", pDesc->hidpCaps.UsagePage, pDesc->hidpCaps.Usage);
  2157. TAGMSG1(DBGTAG_PNP, "FreeHidDesc: %p", pDesc);
  2158. if (pDesc->pInputBuffer) {
  2159. UserFreePool(pDesc->pInputBuffer);
  2160. #if DBG
  2161. pDesc->pInputBuffer = NULL;
  2162. #endif
  2163. }
  2164. if (pDesc->pPreparsedData) {
  2165. UserFreePool(pDesc->pPreparsedData);
  2166. #if DBG
  2167. pDesc->pPreparsedData = NULL;
  2168. #endif
  2169. }
  2170. UserFreePool(pDesc);
  2171. DbgDec(cHidDesc);
  2172. }
  2173. /***************************************************************************\
  2174. * AllocateHidData
  2175. *
  2176. * HidData allocation
  2177. *
  2178. * This function simply calls the HMAllocateObject function.
  2179. * The rest of the initialization is the responsibility of the caller.
  2180. \***************************************************************************/
  2181. PHIDDATA AllocateHidData(
  2182. HANDLE hDevice,
  2183. DWORD dwType,
  2184. DWORD dwSize, // size of the actual data, not including RAWINPUTHEADER
  2185. WPARAM wParam,
  2186. PWND pwnd)
  2187. {
  2188. PHIDDATA pHidData;
  2189. PTHREADINFO pti;
  2190. CheckCritIn();
  2191. #if DBG
  2192. if (dwType == RIM_TYPEMOUSE) {
  2193. UserAssert(dwSize == sizeof(RAWMOUSE));
  2194. } else if (dwType == RIM_TYPEKEYBOARD) {
  2195. UserAssert(dwSize == sizeof(RAWKEYBOARD));
  2196. } else if (dwType == RIM_TYPEHID) {
  2197. UserAssert(dwSize > FIELD_OFFSET(RAWHID, bRawData));
  2198. } else {
  2199. UserAssert(FALSE);
  2200. }
  2201. #endif
  2202. /*
  2203. * N.b. The following code is copied from WakeSomeone to determine
  2204. * which thread will receive the message.
  2205. * When the code in WakeSomeone changes, the following code should be changed too.
  2206. * This pti is required for the HIDDATA is specified as thread owned
  2207. * for some reasons for now. This may be changed later.
  2208. *
  2209. * I think having similar duplicated code in pretty far places is not
  2210. * really a good idea, or HIDDATA may not suit to be thread owned (perhaps
  2211. * it'll be more clear in the future enhanced model). By making it
  2212. * thead owned, we don't have to modify the thread cleanup code...
  2213. * However, I don't see clear advantage other than that. For now,
  2214. * let's make it thread owned and we'll redo the things later... (hiroyama)
  2215. */
  2216. UserAssert(gpqForeground);
  2217. UserAssert(gpqForeground && gpqForeground->ptiKeyboard);
  2218. if (pwnd) {
  2219. pti = GETPTI(pwnd);
  2220. } else {
  2221. pti = PtiKbdFromQ(gpqForeground);
  2222. }
  2223. UserAssert(pti);
  2224. /*
  2225. * Allocate the handle.
  2226. * The next code assumes HIDDATA := HEAD + RAWINPUT.
  2227. */
  2228. pHidData = (PHIDDATA)HMAllocObject(pti, NULL, (BYTE)TYPE_HIDDATA, dwSize + FIELD_OFFSET(HIDDATA, rid.data));
  2229. /*
  2230. * Recalc the size of RAWINPUT structure.
  2231. */
  2232. dwSize += FIELD_OFFSET(RAWINPUT, data);
  2233. if (pHidData) {
  2234. DbgInc(cHidData);
  2235. /*
  2236. * Initialize some common part.
  2237. */
  2238. pHidData->spwndTarget = NULL;
  2239. Lock(&pHidData->spwndTarget, pwnd);
  2240. pHidData->rid.header.dwSize = dwSize;
  2241. pHidData->rid.header.dwType = dwType;
  2242. pHidData->rid.header.hDevice = hDevice;
  2243. pHidData->rid.header.wParam = wParam;
  2244. #if LOCK_HIDDEVICEINFO
  2245. /*
  2246. * do hDevice locking here...
  2247. */
  2248. #endif
  2249. }
  2250. return pHidData;
  2251. }
  2252. /***************************************************************************\
  2253. * FreeHidData
  2254. *
  2255. * HidData destruction
  2256. \***************************************************************************/
  2257. void FreeHidData(PHIDDATA pData)
  2258. {
  2259. CheckCritIn();
  2260. if (!HMMarkObjectDestroy(pData)) {
  2261. RIPMSG2(RIP_ERROR, "FreeHidData: HIDDATA@%p cannot be destroyed now: cLock=%x", pData, pData->head.cLockObj);
  2262. return;
  2263. }
  2264. Unlock(&pData->spwndTarget);
  2265. HMFreeObject(pData);
  2266. DbgDec(cHidData);
  2267. }
  2268. /*
  2269. * HID device info creation
  2270. */
  2271. /***************************************************************************\
  2272. * xxxHidGetCaps
  2273. *
  2274. * Get the interface through IRP and call hidparse.sys!HidP_GetCaps.
  2275. * (ported from wdm/dvd/class/codguts.c)
  2276. \***************************************************************************/
  2277. NTSTATUS xxxHidGetCaps(
  2278. IN PDEVICE_OBJECT pDeviceObject,
  2279. IN PHIDP_PREPARSED_DATA pPreparsedData,
  2280. OUT PHIDP_CAPS pHidCaps)
  2281. {
  2282. NTSTATUS status;
  2283. KEVENT event;
  2284. IO_STATUS_BLOCK iosb;
  2285. PIRP irp;
  2286. PIO_STACK_LOCATION pIrpStackNext;
  2287. PHID_INTERFACE_HIDPARSE pHidInterfaceHidParse;
  2288. PHIDP_GETCAPS pHidpGetCaps = NULL;
  2289. CheckCritIn();
  2290. CheckDeviceInfoListCritIn();
  2291. pHidInterfaceHidParse = UserAllocPoolNonPaged(sizeof *pHidInterfaceHidParse, TAG_PNP);
  2292. if (pHidInterfaceHidParse == NULL) {
  2293. RIPMSG0(RIP_WARNING, "xxxHidGetCaps: failed to allocate pHidInterfaceHidParse");
  2294. return STATUS_INSUFFICIENT_RESOURCES;
  2295. }
  2296. pHidInterfaceHidParse->Size = sizeof *pHidInterfaceHidParse;
  2297. pHidInterfaceHidParse->Version = 1;
  2298. //
  2299. // LATER: check out this comment
  2300. // There is no file object associated with this Irp, so the event may be located
  2301. // on the stack as a non-object manager object.
  2302. //
  2303. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  2304. irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  2305. pDeviceObject,
  2306. NULL,
  2307. 0,
  2308. NULL,
  2309. &event,
  2310. &iosb);
  2311. if (irp == NULL) {
  2312. RIPMSG0(RIP_WARNING, "xxxHidGetCaps: failed to allocate Irp.");
  2313. status = STATUS_INSUFFICIENT_RESOURCES;
  2314. goto Cleanup;
  2315. }
  2316. irp->RequestorMode = KernelMode;
  2317. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  2318. pIrpStackNext = IoGetNextIrpStackLocation(irp);
  2319. UserAssert(pIrpStackNext);
  2320. //
  2321. // Create an interface query out of the irp.
  2322. //
  2323. pIrpStackNext->MinorFunction = IRP_MN_QUERY_INTERFACE;
  2324. pIrpStackNext->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_HID_INTERFACE_HIDPARSE;
  2325. pIrpStackNext->Parameters.QueryInterface.Size = sizeof *pHidInterfaceHidParse;
  2326. pIrpStackNext->Parameters.QueryInterface.Version = 1;
  2327. pIrpStackNext->Parameters.QueryInterface.Interface = (PINTERFACE)pHidInterfaceHidParse;
  2328. pIrpStackNext->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  2329. status = IoCallDriver(pDeviceObject, irp);
  2330. if (status == STATUS_PENDING) {
  2331. //
  2332. // This waits using KernelMode, so that the stack, and therefore the
  2333. // event on that stack, is not paged out.
  2334. //
  2335. TAGMSG1(DBGTAG_PNP, "HidQueryInterface: pending for devobj=%p", pDeviceObject);
  2336. LeaveDeviceInfoListCrit();
  2337. LeaveCrit();
  2338. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2339. EnterCrit();
  2340. EnterDeviceInfoListCrit();
  2341. status = iosb.Status;
  2342. }
  2343. if (status == STATUS_SUCCESS) {
  2344. UserAssert(pHidInterfaceHidParse->HidpGetCaps);
  2345. status = pHidInterfaceHidParse->HidpGetCaps(pPreparsedData, pHidCaps);
  2346. } else {
  2347. RIPMSG1(RIP_WARNING, "xxxHidGetCaps: failed to get pHidpCaps for devobj=%p", pDeviceObject);
  2348. }
  2349. Cleanup:
  2350. UserFreePool(pHidInterfaceHidParse);
  2351. return status;
  2352. }
  2353. /***************************************************************************\
  2354. * GetDeviceObjectPointer
  2355. *
  2356. * Description:
  2357. * This routine returns a pointer to the device object specified by the
  2358. * object name. It also returns a pointer to the referenced file object
  2359. * that has been opened to the device that ensures that the device cannot
  2360. * go away.
  2361. * To close access to the device, the caller should dereference the file
  2362. * object pointer.
  2363. *
  2364. * Arguments:
  2365. * ObjectName - Name of the device object for which a pointer is to be
  2366. * returned.
  2367. * DesiredAccess - Access desired to the target device object.
  2368. * ShareAccess - Supplies the types of share access that the caller would like
  2369. * to the file.
  2370. * FileObject - Supplies the address of a variable to receive a pointer
  2371. * to the file object for the device.
  2372. * DeviceObject - Supplies the address of a variable to receive a pointer
  2373. * to the device object for the specified device.
  2374. * Return Value:
  2375. * The function value is a referenced pointer to the specified device
  2376. * object, if the device exists. Otherwise, NULL is returned.
  2377. \***************************************************************************/
  2378. NTSTATUS
  2379. GetDeviceObjectPointer(
  2380. IN PUNICODE_STRING ObjectName,
  2381. IN ACCESS_MASK DesiredAccess,
  2382. IN ULONG ShareAccess,
  2383. OUT PFILE_OBJECT *FileObject,
  2384. OUT PDEVICE_OBJECT *DeviceObject)
  2385. {
  2386. PFILE_OBJECT fileObject;
  2387. OBJECT_ATTRIBUTES objectAttributes;
  2388. HANDLE fileHandle;
  2389. IO_STATUS_BLOCK ioStatus;
  2390. NTSTATUS status;
  2391. /*
  2392. * Initialize the object attributes to open the device.
  2393. */
  2394. InitializeObjectAttributes(&objectAttributes,
  2395. ObjectName,
  2396. OBJ_KERNEL_HANDLE,
  2397. (HANDLE) NULL,
  2398. (PSECURITY_DESCRIPTOR) NULL);
  2399. status = ZwOpenFile(&fileHandle,
  2400. DesiredAccess,
  2401. &objectAttributes,
  2402. &ioStatus,
  2403. ShareAccess,
  2404. FILE_NON_DIRECTORY_FILE);
  2405. if (NT_SUCCESS(status)) {
  2406. /*
  2407. * The open operation was successful. Dereference the file handle
  2408. * and obtain a pointer to the device object for the handle.
  2409. */
  2410. status = ObReferenceObjectByHandle(fileHandle,
  2411. 0,
  2412. *IoFileObjectType,
  2413. KernelMode,
  2414. (PVOID *)&fileObject,
  2415. NULL);
  2416. if (NT_SUCCESS(status)) {
  2417. *FileObject = fileObject;
  2418. /*
  2419. * Get a pointer to the device object for this file.
  2420. */
  2421. *DeviceObject = IoGetRelatedDeviceObject(fileObject);
  2422. }
  2423. ZwClose(fileHandle);
  2424. }
  2425. return status;
  2426. }
  2427. /***************************************************************************\
  2428. * HidCreateDeviceInfo
  2429. *
  2430. \***************************************************************************/
  2431. PHIDDESC HidCreateDeviceInfo(PDEVICEINFO pDeviceInfo)
  2432. {
  2433. NTSTATUS status;
  2434. PFILE_OBJECT pFileObject;
  2435. PDEVICE_OBJECT pDeviceObject;
  2436. IO_STATUS_BLOCK iob;
  2437. PHIDDESC pHidDesc = NULL;
  2438. PBYTE pPreparsedData = NULL;
  2439. HIDP_CAPS caps;
  2440. PHID_TLC_INFO pTLCInfo;
  2441. HID_COLLECTION_INFORMATION hidCollection;
  2442. KEVENT event;
  2443. PIRP irp;
  2444. UserAssert(pDeviceInfo->type == DEVICE_TYPE_HID);
  2445. CheckCritIn();
  2446. CheckDeviceInfoListCritIn();
  2447. BEGINATOMICCHECK();
  2448. TAGMSG0(DBGTAG_PNP, "HidCreateDeviceInfo");
  2449. status = GetDeviceObjectPointer(&pDeviceInfo->ustrName,
  2450. FILE_READ_DATA,
  2451. FILE_SHARE_READ,
  2452. &pFileObject,
  2453. &pDeviceObject);
  2454. if (!NT_SUCCESS(status)) {
  2455. RIPMSGF1(RIP_WARNING, "failed to get the device object pointer. stat=%x", status);
  2456. goto CleanUp0;
  2457. }
  2458. /*
  2459. * Reference the device object.
  2460. */
  2461. UserAssert(pDeviceObject);
  2462. ObReferenceObject(pDeviceObject);
  2463. /*
  2464. * Remove the reference IoGetDeviceObjectPointer() has put
  2465. * on the file object.
  2466. */
  2467. UserAssert(pFileObject);
  2468. ObDereferenceObject(pFileObject);
  2469. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2470. irp = IoBuildDeviceIoControlRequest(IOCTL_HID_GET_COLLECTION_INFORMATION,
  2471. pDeviceObject,
  2472. NULL,
  2473. 0, // No Input buffer
  2474. &hidCollection,
  2475. sizeof(hidCollection), // Output buffer
  2476. FALSE, // no internal device control
  2477. &event,
  2478. &iob);
  2479. if (irp == NULL) {
  2480. RIPMSGF0(RIP_WARNING, "failed to build IRP 1");
  2481. goto CleanUpDeviceObject;
  2482. }
  2483. status = IoCallDriver(pDeviceObject, irp);
  2484. if (status == STATUS_PENDING) {
  2485. TAGMSGF0(DBGTAG_PNP, "pending IRP 1.");
  2486. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2487. status = iob.Status;
  2488. }
  2489. if (status != STATUS_SUCCESS) {
  2490. RIPMSGF0(RIP_WARNING, "IoCallDriver failed!");
  2491. goto CleanUpDeviceObject;
  2492. }
  2493. /*
  2494. * Get the preparsed data for this device
  2495. */
  2496. pPreparsedData = UserAllocPoolNonPaged(hidCollection.DescriptorSize, TAG_PNP);
  2497. if (pPreparsedData == NULL) {
  2498. RIPMSGF0(RIP_WARNING, "failed to allocate preparsed data.");
  2499. goto CleanUpDeviceObject;
  2500. }
  2501. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2502. irp = IoBuildDeviceIoControlRequest(IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
  2503. pDeviceObject,
  2504. NULL, 0, // No input buffer
  2505. pPreparsedData,
  2506. hidCollection.DescriptorSize, // Output
  2507. FALSE,
  2508. &event,
  2509. &iob);
  2510. if (irp == NULL) {
  2511. RIPMSGF0(RIP_WARNING, "failed to build IRP 2");
  2512. goto CleanUpPreparsedData;
  2513. }
  2514. status = IoCallDriver(pDeviceObject, irp);
  2515. if (status == STATUS_PENDING) {
  2516. RIPMSGF0(RIP_WARNING, "pending 2.");
  2517. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2518. status = iob.Status;
  2519. }
  2520. if (status != STATUS_SUCCESS) {
  2521. RIPMSGF1(RIP_WARNING, "failed IoCallDriver(2). st=%x", status);
  2522. goto CleanUpPreparsedData;
  2523. }
  2524. /*
  2525. * Get the HID Caps, check it, and store it in HIDDESC.
  2526. */
  2527. status = xxxHidGetCaps(pDeviceObject, (PHIDP_PREPARSED_DATA)pPreparsedData, &caps);
  2528. if (status != HIDP_STATUS_SUCCESS) {
  2529. RIPMSGF2(RIP_WARNING, "failed to get caps for devobj=%p. status=%x",
  2530. pDeviceObject, status);
  2531. goto CleanUpPreparsedData;
  2532. }
  2533. TAGMSGF2(DBGTAG_PNP | RIP_THERESMORE, "UsagePage=%x, Usage=%x", caps.UsagePage, caps.Usage);
  2534. TAGMSG2(DBGTAG_PNP, "InputReportByteLength=0x%x, FeatureByteLengt=0x%x",
  2535. caps.InputReportByteLength,
  2536. caps.FeatureReportByteLength);
  2537. /*
  2538. * Check the UsagePage/Usage to reject mice and keyboard devices as HID
  2539. */
  2540. if (caps.UsagePage == HID_USAGE_PAGE_GENERIC) {
  2541. switch (caps.Usage) {
  2542. case HID_USAGE_GENERIC_KEYBOARD:
  2543. case HID_USAGE_GENERIC_MOUSE:
  2544. case HID_USAGE_GENERIC_POINTER:
  2545. case HID_USAGE_GENERIC_SYSTEM_CTL: // LATER: what is this really?
  2546. TAGMSGF2(DBGTAG_PNP, "(%x, %x) will be ignored.",
  2547. caps.UsagePage, caps.Usage);
  2548. goto CleanUpPreparsedData;
  2549. }
  2550. }
  2551. #ifdef OBSOLETE
  2552. else if (caps.UsagePage == HID_USAGE_PAGE_CONSUMER) {
  2553. TAGMSGF0(DBGTAG_PNP, "Consumer device, ignored.");
  2554. goto CleanUpPreparsedData;
  2555. }
  2556. #endif
  2557. pHidDesc = AllocateHidDesc(&pDeviceInfo->ustrName, pPreparsedData, &caps, &hidCollection);
  2558. if (pHidDesc == NULL) {
  2559. TAGMSGF2(DBGTAG_PNP, "AllocateHidDesc returned NULL for (%x, %x)", caps.UsagePage, caps.Usage);
  2560. goto CleanUpPreparsedData;
  2561. }
  2562. /*
  2563. * Check if there's already a HID request for this type of device.
  2564. */
  2565. pTLCInfo = SearchHidTLCInfo(caps.UsagePage, caps.Usage);
  2566. if (pTLCInfo) {
  2567. /*
  2568. * Found the one.
  2569. */
  2570. TAGMSGF3(DBGTAG_PNP, "Usage (%x, %x) is already allocated at pTLCInfo=%p.", caps.UsagePage, caps.Usage, pTLCInfo);
  2571. } else {
  2572. /*
  2573. * HID request for this device type is not yet created,
  2574. * so create it now.
  2575. */
  2576. pTLCInfo = AllocateAndLinkHidTLCInfo(caps.UsagePage, caps.Usage);
  2577. if (pTLCInfo == NULL) {
  2578. RIPMSGF1(RIP_WARNING, "failed to allocate pTLCInfo for DevInfo=%p. Bailing out.",
  2579. pDeviceInfo);
  2580. goto CleanUpHidDesc;
  2581. }
  2582. TAGMSGF3(DBGTAG_PNP, "HidRequest=%p allocated for (%x, %x)",
  2583. pTLCInfo, caps.UsagePage, caps.Usage);
  2584. }
  2585. /*
  2586. * Increment the device ref count of the Hid Request.
  2587. */
  2588. ++pTLCInfo->cDevices;
  2589. TAGMSGF3(DBGTAG_PNP, "new cDevices of (%x, %x) is 0x%x",
  2590. caps.UsagePage, caps.Usage,
  2591. pTLCInfo->cDevices);
  2592. /*
  2593. * Link the Hid request to pDeviceInfo.
  2594. */
  2595. pDeviceInfo->hid.pTLCInfo = pTLCInfo;
  2596. UserAssert(pHidDesc != NULL);
  2597. ObDereferenceObject(pDeviceObject);
  2598. goto Succeeded;
  2599. CleanUpHidDesc:
  2600. UserAssert(pHidDesc);
  2601. FreeHidDesc(pHidDesc);
  2602. pHidDesc = NULL;
  2603. /*
  2604. * The ownership of pPreparsedData was passed to pHidDesc,
  2605. * so it's freed in FreeHidDesc. To avoid the double
  2606. * free, let's skip to the next cleanup code.
  2607. */
  2608. goto CleanUpDeviceObject;
  2609. CleanUpPreparsedData:
  2610. UserAssert(pPreparsedData);
  2611. UserFreePool(pPreparsedData);
  2612. CleanUpDeviceObject:
  2613. UserAssert(pDeviceObject);
  2614. ObDereferenceObject(pDeviceObject);
  2615. CleanUp0:
  2616. UserAssert(pHidDesc == NULL);
  2617. Succeeded:
  2618. ENDATOMICCHECK();
  2619. return pHidDesc;
  2620. }
  2621. /***************************************************************************\
  2622. * HidIsRequestedByThisProcess
  2623. *
  2624. * Returns TRUE if the device type is requested by the process.
  2625. * This routines looks up the cached device type for faster processing.
  2626. *
  2627. * N.b. this routine also updates the cache locally.
  2628. \***************************************************************************/
  2629. PPROCESS_HID_REQUEST HidIsRequestedByThisProcess(
  2630. PDEVICEINFO pDeviceInfo,
  2631. PPROCESS_HID_TABLE pHidTable)
  2632. {
  2633. PPROCESS_HID_REQUEST phr;
  2634. USAGE usUsagePage, usUsage;
  2635. if (pHidTable == NULL) {
  2636. TAGMSG0(DBGTAG_PNP, "ProcessHidInput: the process is not HID aware.");
  2637. return FALSE;
  2638. }
  2639. usUsagePage = pDeviceInfo->hid.pHidDesc->hidpCaps.UsagePage;
  2640. usUsage = pDeviceInfo->hid.pHidDesc->hidpCaps.Usage;
  2641. if (pHidTable->UsagePageLast == usUsagePage && pHidTable->UsageLast == usUsage) {
  2642. /*
  2643. * The same device type as the last input.
  2644. */
  2645. UserAssert(pHidTable->UsagePageLast && pHidTable->UsageLast);
  2646. UserAssert(pHidTable->pLastRequest);
  2647. return pHidTable->pLastRequest;
  2648. }
  2649. phr = InProcessDeviceTypeRequestTable(pHidTable, usUsagePage, usUsage);
  2650. if (phr) {
  2651. pHidTable->UsagePageLast = usUsagePage;
  2652. pHidTable->UsageLast = usUsage;
  2653. pHidTable->pLastRequest = phr;
  2654. }
  2655. return phr;
  2656. }
  2657. #ifdef GI_SINK
  2658. BOOL PostHidInput(
  2659. PDEVICEINFO pDeviceInfo,
  2660. PQ pq,
  2661. PWND pwnd,
  2662. WPARAM wParam)
  2663. {
  2664. DWORD dwSizeData = (DWORD)pDeviceInfo->hid.pHidDesc->hidpCaps.InputReportByteLength;
  2665. DWORD dwLength = (DWORD)pDeviceInfo->iosb.Information;
  2666. DWORD dwSize;
  2667. DWORD dwCount;
  2668. PHIDDATA pHidData;
  2669. UserAssert(dwSizeData != 0);
  2670. #if DBG
  2671. if (dwLength > dwSizeData) {
  2672. TAGMSG2(DBGTAG_PNP, "PostHidInput: multiple input; %x / %x", pDeviceInfo->iosb.Information, dwSizeData);
  2673. }
  2674. #endif
  2675. /*
  2676. * Validate the input length.
  2677. */
  2678. if (dwLength % dwSizeData != 0) {
  2679. /*
  2680. * Input report has invalid length.
  2681. */
  2682. RIPMSG0(RIP_WARNING, "PostHidInput: multiple input: unexpected report size.");
  2683. return FALSE;
  2684. }
  2685. dwCount = dwLength / dwSizeData;
  2686. UserAssert(dwCount <= MAXIMUM_ITEMS_READ);
  2687. if (dwCount == 0) {
  2688. RIPMSG0(RIP_WARNING, "PostHidInput: dwCount == 0");
  2689. return FALSE;
  2690. }
  2691. UserAssert(dwSizeData * dwCount == dwLength);
  2692. /*
  2693. * Calculate the required size for RAWHID.
  2694. */
  2695. dwSize = FIELD_OFFSET(RAWHID, bRawData) + dwLength;
  2696. /*
  2697. * Allocate the input data handle.
  2698. */
  2699. pHidData = AllocateHidData(PtoH(pDeviceInfo), RIM_TYPEHID, dwSize, wParam, pwnd);
  2700. if (pHidData == NULL) {
  2701. RIPMSG0(RIP_WARNING, "PostHidInput: failed to allocate HIDDATA.");
  2702. return FALSE;
  2703. }
  2704. /*
  2705. * Fill the data in.
  2706. */
  2707. pHidData->rid.data.hid.dwSizeHid = dwSizeData;
  2708. pHidData->rid.data.hid.dwCount = dwCount;
  2709. RtlCopyMemory(pHidData->rid.data.hid.bRawData, pDeviceInfo->hid.pHidDesc->pInputBuffer, dwLength);
  2710. #if DBG
  2711. {
  2712. PBYTE pSrc = pDeviceInfo->hid.pHidDesc->pInputBuffer;
  2713. PBYTE pDest = pHidData->rid.data.hid.bRawData;
  2714. DWORD dwCountTmp = 0;
  2715. while ((ULONG)(pSrc - (PBYTE)pDeviceInfo->hid.pHidDesc->pInputBuffer) < dwLength) {
  2716. TAGMSG3(DBGTAG_PNP, "PostHidInput: storing %x th message from %p to %p",
  2717. dwCountTmp, pSrc, pDest);
  2718. pSrc += dwSizeData;
  2719. pDest += dwSizeData;
  2720. ++dwCountTmp;
  2721. }
  2722. UserAssert(pHidData->rid.data.hid.dwCount == dwCountTmp);
  2723. }
  2724. #endif
  2725. /*
  2726. * All the data are ready to fly.
  2727. */
  2728. if (!PostInputMessage(pq, pwnd, WM_INPUT, wParam, (LPARAM)PtoH(pHidData), 0, 0)) {
  2729. /*
  2730. * Failed to post the message, hHidData needs to be freed.
  2731. */
  2732. RIPMSG2(RIP_WARNING, "PostInputMessage: failed to post WM_INPUT (%p) to pq=%p",
  2733. wParam, pq);
  2734. FreeHidData(pHidData);
  2735. return FALSE;
  2736. }
  2737. return TRUE;
  2738. }
  2739. /***************************************************************************\
  2740. * ProcessHidInput (RIT)
  2741. *
  2742. * Called from InputAPC for all input from HID devices.
  2743. \***************************************************************************/
  2744. VOID ProcessHidInput(PDEVICEINFO pDeviceInfo)
  2745. {
  2746. PPROCESSINFO ppiForeground = NULL;
  2747. BOOL fProcessed = FALSE;
  2748. TAGMSG1(DBGTAG_PNP, "ProcessHidInput: pDeviceInfo=%p", pDeviceInfo);
  2749. CheckCritOut();
  2750. UserAssert(pDeviceInfo->type == DEVICE_TYPE_HID);
  2751. if (!NT_SUCCESS(pDeviceInfo->iosb.Status)) {
  2752. RIPMSG1(RIP_WARNING, "ProcessHidInput: unsuccessful input apc. status=%x",
  2753. pDeviceInfo->iosb.Status);
  2754. return;
  2755. }
  2756. EnterCrit();
  2757. TAGMSG2(DBGTAG_PNP, "ProcessHidInput: max:%x info:%x",
  2758. pDeviceInfo->hid.pHidDesc->hidpCaps.InputReportByteLength, pDeviceInfo->iosb.Information);
  2759. UserAssert(pDeviceInfo->handle);
  2760. if (gpqForeground == NULL) {
  2761. TAGMSG0(DBGTAG_PNP, "ProcessHidInput: gpqForeground is NULL.");
  2762. } else {
  2763. PWND pwnd = NULL;
  2764. PPROCESS_HID_REQUEST pHidRequest;
  2765. UserAssert(PtiKbdFromQ(gpqForeground) != NULL);
  2766. ppiForeground = PtiKbdFromQ(gpqForeground)->ppi;
  2767. pHidRequest = HidIsRequestedByThisProcess(pDeviceInfo, ppiForeground->pHidTable);
  2768. if (pHidRequest) {
  2769. PQ pq = gpqForeground;
  2770. pwnd = pHidRequest->spwndTarget;
  2771. if (pwnd) {
  2772. /*
  2773. * Adjust the foreground queue, if the app specified
  2774. * the target window.
  2775. */
  2776. pq = GETPTI(pwnd)->pq;
  2777. }
  2778. if (pwnd && TestWF(pwnd, WFINDESTROY)) {
  2779. /*
  2780. * If the target window is in destroy, let's not post
  2781. * a message, it's just waste of time.
  2782. */
  2783. goto check_sinks;
  2784. }
  2785. if (PostHidInput(pDeviceInfo, pq, pwnd, RIM_INPUT)) {
  2786. fProcessed = TRUE;
  2787. }
  2788. } else {
  2789. /*
  2790. * No request for this device from the foreground process.
  2791. */
  2792. TAGMSG3(DBGTAG_PNP, "ProcessHidInput: (%x, %x) is ignored for ppi=%p.",
  2793. pDeviceInfo->hid.pHidDesc->hidpCaps.UsagePage,
  2794. pDeviceInfo->hid.pHidDesc->hidpCaps.Usage,
  2795. PtiKbdFromQ(gpqForeground)->ppi);
  2796. }
  2797. }
  2798. check_sinks:
  2799. #ifdef LATER
  2800. /*
  2801. * Check if multiple process requests this type of devices.
  2802. */
  2803. if (IsSinkRequestedFor(pDeviceInfo))
  2804. #endif
  2805. {
  2806. /*
  2807. * Walk through the global sink list and find the sinkable request.
  2808. */
  2809. PLIST_ENTRY pList = gHidRequestTable.ProcessRequestList.Flink;
  2810. for (; pList != &gHidRequestTable.ProcessRequestList; pList = pList->Flink) {
  2811. PPROCESS_HID_TABLE pProcessHidTable = CONTAINING_RECORD(pList, PROCESS_HID_TABLE, link);
  2812. PPROCESS_HID_REQUEST pHidRequest;
  2813. UserAssert(pProcessHidTable);
  2814. if (pProcessHidTable->nSinks <= 0) {
  2815. /*
  2816. * No sinkable request in this table.
  2817. */
  2818. continue;
  2819. }
  2820. pHidRequest = HidIsRequestedByThisProcess(pDeviceInfo, pProcessHidTable);
  2821. if (pHidRequest) {
  2822. PWND pwnd;
  2823. UserAssert(pHidRequest->spwndTarget);
  2824. if (!pHidRequest->fSinkable) {
  2825. /*
  2826. * It's not a sink.
  2827. */
  2828. continue;
  2829. }
  2830. pwnd = pHidRequest->spwndTarget;
  2831. if (GETPTI(pwnd)->ppi == ppiForeground) {
  2832. /*
  2833. * We should have already processed this guy.
  2834. */
  2835. continue;
  2836. }
  2837. if (pwnd->head.rpdesk != grpdeskRitInput) {
  2838. /*
  2839. * This guy belongs to the other desktop, let's skip it.
  2840. */
  2841. continue;
  2842. }
  2843. if (TestWF(pwnd, WFINDESTROY) || TestWF(pwnd, WFDESTROYED)) {
  2844. /*
  2845. * The window is being destroyed, let's save some time.
  2846. */
  2847. continue;
  2848. }
  2849. /*
  2850. * OK, this guy has the right to receive the sink input.
  2851. */
  2852. TAGMSG2(DBGTAG_PNP, "ProcessRequestList: posting SINK to pwnd=%p pq=%p", pwnd, GETPTI(pwnd)->pq);
  2853. if (!PostHidInput(pDeviceInfo, GETPTI(pwnd)->pq, pwnd, RIM_INPUTSINK)) {
  2854. /*
  2855. * Something went bad... let's bail out.
  2856. */
  2857. break;
  2858. }
  2859. fProcessed = TRUE;
  2860. }
  2861. }
  2862. }
  2863. if (fProcessed) {
  2864. /*
  2865. * Exit the video power down mode.
  2866. */
  2867. if (glinp.dwFlags & LINP_POWERTIMEOUTS) {
  2868. /*
  2869. * Call video driver here to exit power down mode.
  2870. */
  2871. TAGMSG0(DBGTAG_Power, "Exit video power down mode");
  2872. DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
  2873. }
  2874. /*
  2875. * Prevents power off:
  2876. * LATER: devices with possible chattering???
  2877. */
  2878. glinp.dwFlags = (glinp.dwFlags & ~(LINP_INPUTTIMEOUTS | LINP_INPUTSOURCES)) | LINP_KEYBOARD;
  2879. glinp.timeLastInputMessage = gpsi->dwLastRITEventTickCount = NtGetTickCount();
  2880. /*
  2881. * N.b. when win32k starts to support HID input injection,
  2882. * timeLastInputMessage should only be set after checking gbBlockSendInputResets
  2883. * and the injection flag.
  2884. */
  2885. CLEAR_SRVIF(SRVIF_LASTRITWASKEYBOARD);
  2886. }
  2887. LeaveCrit();
  2888. }
  2889. #else
  2890. // without SINK
  2891. /***************************************************************************\
  2892. * ProcessHidInput (RIT)
  2893. *
  2894. * Called from InputAPC for all input from HID devices.
  2895. \***************************************************************************/
  2896. VOID ProcessHidInput(PDEVICEINFO pDeviceInfo)
  2897. {
  2898. TAGMSG1(DBGTAG_PNP, "ProcessHidInput: pDeviceInfo=%p", pDeviceInfo);
  2899. CheckCritOut();
  2900. UserAssert(pDeviceInfo->type == DEVICE_TYPE_HID);
  2901. if (!NT_SUCCESS(pDeviceInfo->iosb.Status)) {
  2902. RIPMSG1(RIP_WARNING, "ProcessHidInput: unsuccessful input apc. status=%x",
  2903. pDeviceInfo->iosb.Status);
  2904. return;
  2905. }
  2906. EnterCrit();
  2907. TAGMSG2(DBGTAG_PNP, "ProcessHidInput: max:%x info:%x",
  2908. pDeviceInfo->hid.pHidDesc->hidpCaps.InputReportByteLength, pDeviceInfo->iosb.Information);
  2909. UserAssert(pDeviceInfo->handle);
  2910. if (gpqForeground == NULL) {
  2911. RIPMSG0(RIP_WARNING, "ProcessHidInput: gpqForeground is NULL, bailing out.");
  2912. } else {
  2913. PWND pwnd = NULL;
  2914. PPROCESSINFO ppi;
  2915. PPROCESS_HID_REQUEST pHidRequest;
  2916. UserAssert(PtiKbdFromQ(gpqForeground) != NULL);
  2917. ppi = PtiKbdFromQ(gpqForeground)->ppi;
  2918. pHidRequest = HidIsRequestedByThisProcess(pDeviceInfo, ppi->pHidTable);
  2919. if (pHidRequest) {
  2920. /*
  2921. * The foreground thread has requested the raw input from this type of device.
  2922. */
  2923. PHIDDATA pHidData;
  2924. DWORD dwSizeData; // size of each report
  2925. DWORD dwSize; // size of HIDDATA
  2926. DWORD dwCount; // number of report
  2927. DWORD dwLength; // length of all input reports
  2928. PQ pq;
  2929. pwnd = pHidRequest->spwndTarget;
  2930. pq = gpqForeground;
  2931. if (pwnd) {
  2932. /*
  2933. * Adjust the foreground queue, if the app specified
  2934. * the target window.
  2935. */
  2936. pq = GETPTI(pwnd)->pq;
  2937. }
  2938. if (pwnd && TestWF(pwnd, WFINDESTROY)) {
  2939. /*
  2940. * If the target window is in destroy, let's not post
  2941. * a message, it's just waste of time.
  2942. */
  2943. goto exit;
  2944. }
  2945. dwSizeData = (DWORD)pDeviceInfo->hid.pHidDesc->hidpCaps.InputReportByteLength;
  2946. UserAssert(dwSizeData != 0);
  2947. dwLength = (DWORD)pDeviceInfo->iosb.Information;
  2948. #if DBG
  2949. if (dwLength > dwSizeData) {
  2950. TAGMSG2(DBGTAG_PNP, "ProcessHidInput: multiple input; %x / %x", pDeviceInfo->iosb.Information, dwSizeData);
  2951. }
  2952. #endif
  2953. /*
  2954. * Validate the input length.
  2955. */
  2956. if (dwLength % dwSizeData != 0) {
  2957. /*
  2958. * Input report has invalid length.
  2959. */
  2960. RIPMSG0(RIP_WARNING, "ProcessHidInput: multiple input: unexpected report size.");
  2961. goto exit;
  2962. }
  2963. dwCount = dwLength / dwSizeData;
  2964. UserAssert(dwCount <= MAXIMUM_ITEMS_READ);
  2965. if (dwCount == 0) {
  2966. RIPMSG0(RIP_WARNING, "ProcessHidInput: dwCount == 0");
  2967. goto exit;
  2968. }
  2969. UserAssert(dwSizeData * dwCount == dwLength);
  2970. /*
  2971. * Calculate the required size for RAWHID.
  2972. */
  2973. dwSize = FIELD_OFFSET(RAWHID, bRawData) + dwLength;
  2974. /*
  2975. * Allocate the input data handle.
  2976. */
  2977. pHidData = AllocateHidData(PtoH(pDeviceInfo), RIM_TYPEHID, dwSize, RIM_INPUT, pwnd);
  2978. if (pHidData == NULL) {
  2979. RIPMSG0(RIP_WARNING, "ProcessHidInput: failed to allocate HIDDATA.");
  2980. goto exit;
  2981. }
  2982. /*
  2983. * Fill the data in.
  2984. */
  2985. pHidData->rid.data.hid.dwSizeHid = dwSizeData;
  2986. pHidData->rid.data.hid.dwCount = dwCount;
  2987. RtlCopyMemory(pHidData->rid.data.hid.bRawData, pDeviceInfo->hid.pHidDesc->pInputBuffer, dwLength);
  2988. #if DBG
  2989. {
  2990. PBYTE pSrc = pDeviceInfo->hid.pHidDesc->pInputBuffer;
  2991. PBYTE pDest = pHidData->rid.data.hid.bRawData;
  2992. DWORD dwCountTmp = 0;
  2993. while ((ULONG)(pSrc - (PBYTE)pDeviceInfo->hid.pHidDesc->pInputBuffer) < dwLength) {
  2994. TAGMSG3(DBGTAG_PNP, "ProcessHidInput: storing %x th message from %p to %p",
  2995. dwCountTmp, pSrc, pDest);
  2996. pSrc += dwSizeData;
  2997. pDest += dwSizeData;
  2998. ++dwCountTmp;
  2999. }
  3000. UserAssert(pHidData->rid.data.hid.dwCount == dwCountTmp);
  3001. }
  3002. #endif
  3003. /*
  3004. * All the data are ready to fly.
  3005. */
  3006. if (!PostInputMessage(pq, pwnd, WM_INPUT, RIM_INPUT, (LPARAM)PtoH(pHidData), 0, 0)) {
  3007. /*
  3008. * Failed to post the message, hHidData needs to be freed.
  3009. */
  3010. FreeHidData(pHidData);
  3011. }
  3012. /*
  3013. * Prevents power off:
  3014. * LATER: devices with possible chattering???
  3015. */
  3016. glinp.dwFlags &= ~(LINP_INPUTTIMEOUTS | LINP_INPUTSOURCES);
  3017. glinp.timeLastInputMessage = gpsi->dwLastRITEventTickCount = NtGetTickCount();
  3018. if (gpsi->dwLastRITEventTickCount - gpsi->dwLastSystemRITEventTickCountUpdate > SYSTEM_RIT_EVENT_UPDATE_PERIOD) {
  3019. SharedUserData->LastSystemRITEventTickCount = gpsi->dwLastRITEventTickCount;
  3020. gpsi->dwLastSystemRITEventTickCountUpdate = gpsi->dwLastRITEventTickCount;
  3021. }
  3022. CLEAR_SRVIF(SRVIF_LASTRITWASKEYBOARD);
  3023. } else {
  3024. /*
  3025. * No request for this device from the foreground process.
  3026. */
  3027. TAGMSG3(DBGTAG_PNP, "ProcessHidInput: (%x, %x) is ignored for ppi=%p.",
  3028. pDeviceInfo->hid.pHidDesc->hidpCaps.UsagePage,
  3029. pDeviceInfo->hid.pHidDesc->hidpCaps.Usage,
  3030. PtiKbdFromQ(gpqForeground)->ppi);
  3031. }
  3032. }
  3033. exit:
  3034. LeaveCrit();
  3035. }
  3036. #endif // GI_SINK
  3037. #endif // GENERIC_INPUT