Source code of Windows XP (NT5)
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.

726 lines
24 KiB

  1. /*++
  2. *
  3. * Component: hidserv.exe
  4. * File: pnp.c
  5. * Purpose: routines to support pnp hid devices.
  6. *
  7. * Copyright (C) Microsoft Corporation 1997,1998. All rights reserved.
  8. *
  9. * WGJ
  10. --*/
  11. #include "hidserv.h"
  12. #include <cfgmgr32.h>
  13. #include <tchar.h>
  14. BOOL
  15. OpenHidDevice (
  16. IN HDEVINFO HardwareDeviceInfo,
  17. IN PSP_DEVICE_INTERFACE_DATA DeviceInfoData,
  18. IN OUT PHID_DEVICE *HidDevice
  19. );
  20. BOOL
  21. RebuildHidDeviceList (
  22. void
  23. )
  24. /*++
  25. Routine Description:
  26. Do the required PnP things in order to find, the all the HID devices in
  27. the system at this time.
  28. --*/
  29. {
  30. HDEVINFO hardwareDeviceInfo;
  31. SP_DEVICE_INTERFACE_DATA deviceInfoData;
  32. PHID_DEVICE hidDeviceInst;
  33. GUID hidGuid;
  34. DWORD i=0;
  35. PHID_DEVICE pCurrent, pTemp;
  36. HidD_GetHidGuid (&hidGuid);
  37. TRACE(("Getting class devices"));
  38. //
  39. // Open a handle to the plug and play dev node.
  40. //
  41. hardwareDeviceInfo = SetupDiGetClassDevs (
  42. &hidGuid,
  43. NULL, // Define no enumerator (global)
  44. NULL, // Define no
  45. (DIGCF_PRESENT | // Only Devices present
  46. DIGCF_DEVICEINTERFACE)); // Function class devices.
  47. if (!hardwareDeviceInfo) {
  48. TRACE(("Get class devices failed"));
  49. return FALSE;
  50. }
  51. //
  52. // Take a wild guess to start
  53. //
  54. deviceInfoData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
  55. TRACE(("Marking existing devnodes"));
  56. // Unmark all existing nodes. They will be remarked if the device still exists.
  57. pCurrent = (PHID_DEVICE)HidDeviceList.pNext;
  58. while (pCurrent) {
  59. pCurrent->Active = FALSE;
  60. pCurrent = pCurrent->pNext;
  61. }
  62. TRACE(("Entering loop"));
  63. while (TRUE) {
  64. TRACE(("Enumerating device interfaces"));
  65. if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, //HDEVINFO
  66. 0, // No care about specific PDOs //PSP_DEVINFO_DATA
  67. &hidGuid, // LPGUID
  68. i, //DWORD MemberIndex
  69. &deviceInfoData)) { //PSP_DEVICE_INTERFACE_DATA
  70. TRACE(("Got an item"));
  71. if (!OpenHidDevice (hardwareDeviceInfo, &deviceInfoData, &hidDeviceInst)) {
  72. TRACE(("Open hid device failed"));
  73. } else {
  74. if (StartHidDevice(hidDeviceInst)) {
  75. TRACE(("Start hid device succeeded."));
  76. InsertTailList((PLIST_NODE)&HidDeviceList, (PLIST_NODE)hidDeviceInst);
  77. } else {
  78. WARN(("Failed to start hid device. (%x)", hidDeviceInst));
  79. HidFreeDevice(hidDeviceInst);
  80. }
  81. }
  82. } else {
  83. DWORD error = GetLastError();
  84. if (ERROR_NO_MORE_ITEMS == error) {
  85. TRACE(("No more items. Exitting"));
  86. break;
  87. } else {
  88. WARN(("Unexpected error getting device interface: 0x%xh", error));
  89. }
  90. break;
  91. }
  92. i++;
  93. }
  94. TRACE(("Removing unmarked device nodes"));
  95. // RemoveUnmarkedNodes();
  96. pCurrent = (PHID_DEVICE)HidDeviceList.pNext;
  97. while (pCurrent) {
  98. pTemp = pCurrent->pNext;
  99. if (!pCurrent->Active) {
  100. INFO(("Device (DevInst = %x) is gone.", pCurrent->DevInst));
  101. RemoveEntryList((PLIST_NODE)&HidDeviceList, (PLIST_NODE)pCurrent);
  102. StopHidDevice(pCurrent); // this frees pCurrent
  103. }
  104. pCurrent = pTemp;
  105. }
  106. TRACE(("Destroying device info list"));
  107. SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
  108. return TRUE;
  109. }
  110. VOID
  111. HidFreeDevice(PHID_DEVICE HidDevice)
  112. {
  113. PHID_DATA data;
  114. UCHAR j;
  115. HidD_FreePreparsedData (HidDevice->Ppd);
  116. data = HidDevice->InputData;
  117. //
  118. // Release the button data
  119. //
  120. for (j = 0; j < HidDevice->Caps.NumberLinkCollectionNodes; j++, data++) {
  121. LocalFree(data->ButtonData.PrevUsages);
  122. LocalFree(data->ButtonData.Usages);
  123. }
  124. LocalFree(HidDevice->InputData);
  125. LocalFree(HidDevice->InputReportBuffer);
  126. LocalFree(HidDevice);
  127. }
  128. BOOL
  129. OpenHidDevice (
  130. IN HDEVINFO HardwareDeviceInfo,
  131. IN PSP_DEVICE_INTERFACE_DATA DeviceInfoData,
  132. IN OUT PHID_DEVICE *HidDevice
  133. )
  134. /*++
  135. RoutineDescription:
  136. Given the HardwareDeviceInfo, representing a handle to the plug and
  137. play information, and deviceInfoData, representing a specific hid device,
  138. open that device and fill in all the relivant information in the given
  139. HID_DEVICE structure.
  140. return if the open and initialization was successfull or not.
  141. --*/
  142. {
  143. PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL;
  144. SP_DEVINFO_DATA DevInfoData;
  145. ULONG predictedLength = 0;
  146. ULONG requiredLength = 0;
  147. UCHAR i = 0;
  148. PHID_DATA data = NULL;
  149. PHIDP_BUTTON_CAPS pButtonCaps = NULL;
  150. PHIDP_VALUE_CAPS pValueCaps = NULL;
  151. USHORT numCaps;
  152. PHIDP_LINK_COLLECTION_NODE LinkCollectionNodes = NULL;
  153. PHID_DEVICE hidDevice = NULL;
  154. WCHAR buf[512];
  155. CONFIGRET cr = CR_SUCCESS;
  156. DEVINST devInst, parentDevInst;
  157. DWORD len = 0;
  158. if (!(hidDevice = LocalAlloc (LPTR, sizeof (HID_DEVICE)))) {
  159. //
  160. // Alloc failed. Drop out of the loop and let the device list
  161. // get deleted.
  162. //
  163. WARN(("Alloc HID_DEVICE struct failed."));
  164. return FALSE;
  165. }
  166. TRACE(("Creating Device Node (%x)", hidDevice));
  167. //
  168. // allocate a function class device data structure to receive the
  169. // goods about this particular device.
  170. //
  171. SetupDiGetDeviceInterfaceDetail (
  172. HardwareDeviceInfo,
  173. DeviceInfoData,
  174. NULL, // probing so no output buffer yet
  175. 0, // probing so output buffer length of zero
  176. &requiredLength,
  177. NULL); // get the specific dev-node
  178. predictedLength = requiredLength;
  179. // sizeof (SP_FNCLASS_DEVICE_DATA) + 512;
  180. if (!(functionClassDeviceData = LocalAlloc (LPTR, predictedLength))) {
  181. WARN(("Allocation failed, our of resources!"));
  182. goto OpenHidDeviceError;
  183. }
  184. functionClassDeviceData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
  185. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  186. DevInfoData.DevInst = 0;
  187. //
  188. // Retrieve the information from Plug and Play.
  189. //
  190. if (! SetupDiGetDeviceInterfaceDetail (
  191. HardwareDeviceInfo,
  192. DeviceInfoData, // PSP_DEVICE_INTERFACE_DATA
  193. functionClassDeviceData, // PSP_DEVICE_INTERFACE_DETAIL_DATA
  194. predictedLength,
  195. &requiredLength,
  196. &DevInfoData)) { //PSP_DEVINFO_DATA
  197. WARN(("SetupDiGetDeviceInterfaceDetail failed"));
  198. goto OpenHidDeviceError;
  199. }
  200. INFO(("Just got interface detail for %S", functionClassDeviceData->DevicePath));
  201. hidDevice->DevInst = DevInfoData.DevInst;
  202. //
  203. // <HACK>
  204. //
  205. // Find out it this is a set of speakers with buttons on it. This is for
  206. // but 136800. We want to only emit WM_APPCOMMANDs for speakers, not the
  207. // VK. This is because certain games leave the opening movie scene when
  208. // you press any key, so if someone presses volume down on their speakers
  209. // it will leave the scene. They just want that to affect volume.
  210. //
  211. cr = CM_Get_Parent(&parentDevInst,
  212. DevInfoData.DevInst,
  213. 0);
  214. //
  215. // We need to get the grandparent, then get the child, to make sure that
  216. // we get the first child in the set. From there, if the child we've got
  217. // is the same parent of the devnode that we started with, we want to
  218. // look at its sibling. But if the devnode we've got is different from
  219. // the parent, then we've got the right one to look at!
  220. //
  221. if (cr == CR_SUCCESS) {
  222. cr = CM_Get_Parent(&devInst,
  223. parentDevInst,
  224. 0);
  225. }
  226. if (cr == CR_SUCCESS) {
  227. cr = CM_Get_Child(&devInst,
  228. devInst,
  229. 0);
  230. }
  231. if (cr == CR_SUCCESS) {
  232. if (devInst == parentDevInst) {
  233. //
  234. // Only look at the first sibling, because this covers all sets
  235. // of speakers currently on the market.
  236. //
  237. cr = CM_Get_Sibling(&devInst,
  238. devInst,
  239. 0);
  240. }
  241. if (cr == CR_SUCCESS) {
  242. len = sizeof(buf);
  243. cr = CM_Get_DevNode_Registry_Property(devInst,
  244. CM_DRP_CLASS,
  245. NULL,
  246. buf,
  247. &len,
  248. 0);
  249. if (cr == CR_SUCCESS) {
  250. if (lstrcmpi(TEXT("MEDIA"), buf) == 0) {
  251. hidDevice->Speakers = TRUE;
  252. }
  253. }
  254. } // else - definitely not speakers
  255. }
  256. //
  257. // </HACK>
  258. //
  259. // Do we already have this device open?
  260. {
  261. PHID_DEVICE pCurrent = (PHID_DEVICE)HidDeviceList.pNext;
  262. while (pCurrent) {
  263. if (pCurrent->DevInst == hidDevice->DevInst) break;
  264. pCurrent = pCurrent->pNext;
  265. }
  266. if (pCurrent) {
  267. // Yes. Mark it and bail on the new node.
  268. pCurrent->Active = TRUE;
  269. INFO(("Device (DevInst = %x) already open.", DevInfoData.DevInst));
  270. goto OpenHidDeviceError;
  271. } else {
  272. // No. Mark the new node and continue.
  273. INFO(("Device (DevInst = %x) is new.", DevInfoData.DevInst));
  274. hidDevice->Active = TRUE;
  275. }
  276. }
  277. hidDevice->HidDevice = CreateFile (
  278. functionClassDeviceData->DevicePath,
  279. GENERIC_READ,
  280. FILE_SHARE_READ | FILE_SHARE_WRITE,
  281. NULL, // no SECURITY_ATTRIBUTES structure
  282. OPEN_EXISTING, // No special create flags
  283. FILE_FLAG_OVERLAPPED, // Do overlapped read/write
  284. NULL); // No template file
  285. if (INVALID_HANDLE_VALUE == hidDevice->HidDevice) {
  286. INFO(("CreateFile failed - %x (%S)", GetLastError(), functionClassDeviceData->DevicePath));
  287. goto OpenHidDeviceError;
  288. } else {
  289. INFO(("CreateFile succeeded Handle(%x) - %S", hidDevice->HidDevice, functionClassDeviceData->DevicePath));
  290. }
  291. if (!HidD_GetPreparsedData (hidDevice->HidDevice, &hidDevice->Ppd)) {
  292. WARN(("HidD_GetPreparsedData failed"));
  293. goto OpenHidDeviceError;
  294. }
  295. if (!HidD_GetAttributes (hidDevice->HidDevice, &hidDevice->Attributes)) {
  296. WARN(("HidD_GetAttributes failed"));
  297. goto OpenHidDeviceError;
  298. }
  299. if (!HidP_GetCaps (hidDevice->Ppd, &hidDevice->Caps)) {
  300. WARN(("HidP_GetCaps failed"));
  301. goto OpenHidDeviceError;
  302. }
  303. // ***Instructive comment from KenRay:
  304. // At this point the client has a choice. It may chose to look at the
  305. // Usage and Page of the top level collection found in the HIDP_CAPS
  306. // structure. In this way it could just use the usages it knows about.
  307. // If either HidP_GetUsages or HidP_GetUsageValue return an error then
  308. // that particular usage does not exist in the report.
  309. // This is most likely the preferred method as the application can only
  310. // use usages of which it already knows.
  311. // In this case the app need not even call GetButtonCaps or GetValueCaps.
  312. // If this is a collection we care about, continue. Else, we get out now.
  313. if (hidDevice->Caps.UsagePage != HIDSERV_USAGE_PAGE) {
  314. TRACE(("This device is not for us (%x)", hidDevice));
  315. goto OpenHidDeviceError;
  316. }
  317. //
  318. // setup Input Data buffers.
  319. //
  320. TRACE(("NumberLinkCollectionNodes = %d", hidDevice->Caps.NumberLinkCollectionNodes));
  321. {
  322. ULONG numNodes = hidDevice->Caps.NumberLinkCollectionNodes;
  323. if (!(LinkCollectionNodes = LocalAlloc(LPTR, hidDevice->Caps.NumberLinkCollectionNodes*sizeof(HIDP_LINK_COLLECTION_NODE)))) {
  324. WARN(("LinkCollectionNodes alloc failed."));
  325. goto OpenHidDeviceError;
  326. }
  327. HidP_GetLinkCollectionNodes(LinkCollectionNodes,
  328. &numNodes,
  329. hidDevice->Ppd);
  330. for (i=0; i<hidDevice->Caps.NumberLinkCollectionNodes; i++) {
  331. INFO(("Link Collection [%d] Type = %x, Alias = %x", i, LinkCollectionNodes[i].CollectionType, LinkCollectionNodes[i].IsAlias));
  332. INFO(("Link Collection [%d] Page = %x, Usage = %x", i, LinkCollectionNodes[i].LinkUsagePage, LinkCollectionNodes[i].LinkUsage));
  333. }
  334. }
  335. //
  336. // Allocate memory to hold on input report
  337. //
  338. if (!(hidDevice->InputReportBuffer = (PCHAR)
  339. LocalAlloc (LPTR, hidDevice->Caps.InputReportByteLength * sizeof (CHAR)))) {
  340. WARN(("InputReportBuffer alloc failed."));
  341. goto OpenHidDeviceError;
  342. }
  343. //
  344. // Allocate memory to hold the button and value capabilities.
  345. // NumberXXCaps is in terms of array elements.
  346. //
  347. if (!(pButtonCaps = (PHIDP_BUTTON_CAPS)
  348. LocalAlloc (LPTR, hidDevice->Caps.NumberInputButtonCaps*sizeof (HIDP_BUTTON_CAPS)))) {
  349. WARN(("buttoncaps alloc failed."));
  350. goto OpenHidDeviceError;
  351. }
  352. if (!(pValueCaps = (PHIDP_VALUE_CAPS)
  353. LocalAlloc (LPTR, hidDevice->Caps.NumberInputValueCaps*sizeof (HIDP_VALUE_CAPS)))) {
  354. WARN(("valuecaps alloc failed."));
  355. goto OpenHidDeviceError;
  356. }
  357. //
  358. // Have the HidP_X functions fill in the capability structure arrays.
  359. //
  360. numCaps = hidDevice->Caps.NumberInputButtonCaps;
  361. TRACE(("NumberInputButtonCaps = %d", numCaps));
  362. HidP_GetButtonCaps (HidP_Input,
  363. pButtonCaps,
  364. &numCaps,
  365. hidDevice->Ppd);
  366. numCaps = hidDevice->Caps.NumberInputValueCaps;
  367. TRACE(("NumberInputValueCaps = %d", numCaps));
  368. HidP_GetValueCaps (HidP_Input,
  369. pValueCaps,
  370. &numCaps,
  371. hidDevice->Ppd);
  372. TRACE(("Buttons:"));
  373. for (i=0; i<hidDevice->Caps.NumberInputButtonCaps; i++) {
  374. TRACE(("UsagePage = 0x%x", pButtonCaps[i].UsagePage));
  375. TRACE(("LinkUsage = 0x%x", pButtonCaps[i].LinkUsage));
  376. TRACE(("LinkUsagePage = 0x%x\n", pButtonCaps[i].LinkUsagePage));
  377. }
  378. //
  379. // Allocate a buffer to hold the struct _HID_DATA structures.
  380. //
  381. hidDevice->InputDataLength = hidDevice->Caps.NumberLinkCollectionNodes +
  382. hidDevice->Caps.NumberInputValueCaps;
  383. if (!(hidDevice->InputData = data = (PHID_DATA)
  384. LocalAlloc (LPTR, hidDevice->InputDataLength * sizeof (HID_DATA)))) {
  385. WARN(("InputData alloc failed."));
  386. goto OpenHidDeviceError;
  387. }
  388. TRACE(("InputDataLength = %d", hidDevice->InputDataLength));
  389. //
  390. // Fill in the button data
  391. // Group button sets by link collection.
  392. //
  393. for (i = 0; i < hidDevice->Caps.NumberLinkCollectionNodes; i++, data++) {
  394. data->IsButtonData = TRUE;
  395. data->LinkUsage = LinkCollectionNodes[i].LinkUsage;
  396. data->UsagePage = LinkCollectionNodes[i].LinkUsagePage;
  397. if (i)
  398. data->LinkCollection = i;
  399. else
  400. data->LinkCollection = HIDP_LINK_COLLECTION_ROOT;
  401. INFO(("Button Link Usage = %x", data->LinkUsage));
  402. INFO(("Button Link Usage Page = %x", data->UsagePage));
  403. INFO(("Button Link Collection = %x", data->LinkCollection));
  404. data->Status = HIDP_STATUS_SUCCESS;
  405. data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
  406. HidP_Input,
  407. hidDevice->Caps.UsagePage,
  408. hidDevice->Ppd);
  409. //make room for the terminator
  410. data->ButtonData.MaxUsageLength++;
  411. if (!(data->ButtonData.Usages = (PUSAGE_AND_PAGE)
  412. LocalAlloc (LPTR, data->ButtonData.MaxUsageLength * sizeof (USAGE_AND_PAGE)))) {
  413. WARN(("Usages alloc failed."));
  414. goto OpenHidDeviceError;
  415. }
  416. if (!(data->ButtonData.PrevUsages = (PUSAGE_AND_PAGE)
  417. LocalAlloc (LPTR, data->ButtonData.MaxUsageLength * sizeof (USAGE_AND_PAGE)))) {
  418. WARN(("PrevUsages alloc failed."));
  419. goto OpenHidDeviceError;
  420. }
  421. }
  422. //
  423. // Fill in the value data
  424. //
  425. for (i = 0; i < hidDevice->Caps.NumberInputValueCaps; i++, data++) {
  426. if (pValueCaps[i].IsRange) {
  427. WARN(("Can't handle value ranges!!"));
  428. }
  429. data->IsButtonData = FALSE;
  430. data->LinkUsage = pValueCaps[i].LinkUsage;
  431. data->UsagePage = pValueCaps[i].LinkUsagePage;
  432. if (pValueCaps[i].LinkCollection)
  433. data->LinkCollection = pValueCaps[i].LinkCollection;
  434. else
  435. data->LinkCollection = HIDP_LINK_COLLECTION_ROOT;
  436. INFO(("Value Link Usage = %x", data->LinkUsage));
  437. INFO(("Value Link Usage Page = %x", data->UsagePage));
  438. INFO(("Value Link Collection = %x", data->LinkCollection));
  439. INFO(("Value LogicalMin = %x", pValueCaps[i].LogicalMin));
  440. INFO(("Value LogicalMax = %x", pValueCaps[i].LogicalMax));
  441. data->ValueData.LogicalRange = pValueCaps[i].LogicalMax - pValueCaps[i].LogicalMin;
  442. data->Status = HIDP_STATUS_SUCCESS;
  443. data->ValueData.Usage = pValueCaps[i].NotRange.Usage;
  444. }
  445. LocalFree(pButtonCaps);
  446. LocalFree(pValueCaps);
  447. LocalFree(LinkCollectionNodes);
  448. LocalFree(functionClassDeviceData);
  449. *HidDevice = hidDevice;
  450. return TRUE;
  451. OpenHidDeviceError:
  452. if (data) {
  453. for (i = 0; i < hidDevice->Caps.NumberLinkCollectionNodes; i++, data++) {
  454. if (data->ButtonData.Usages) {
  455. LocalFree(data->ButtonData.Usages);
  456. }
  457. if (data->ButtonData.PrevUsages) {
  458. LocalFree(data->ButtonData.PrevUsages);
  459. }
  460. }
  461. LocalFree(data);
  462. }
  463. if (pValueCaps) {
  464. LocalFree(pValueCaps);
  465. }
  466. if (pButtonCaps) {
  467. LocalFree (pButtonCaps);
  468. }
  469. if (hidDevice->InputReportBuffer) {
  470. LocalFree (hidDevice->InputReportBuffer);
  471. }
  472. if (LinkCollectionNodes) {
  473. LocalFree (LinkCollectionNodes);
  474. }
  475. if (hidDevice->Ppd) {
  476. HidD_FreePreparsedData (hidDevice->Ppd);
  477. }
  478. if (hidDevice->HidDevice &&
  479. hidDevice->HidDevice != INVALID_HANDLE_VALUE) {
  480. CloseHandle (hidDevice->HidDevice);
  481. }
  482. if (functionClassDeviceData) {
  483. LocalFree (functionClassDeviceData);
  484. }
  485. LocalFree (hidDevice);
  486. return FALSE;
  487. }
  488. BOOL
  489. StartHidDevice(
  490. PHID_DEVICE pHidDevice
  491. )
  492. /*++
  493. RoutineDescription:
  494. Create a work thread to go with the new hid device. This thread lives
  495. as long as the associated hid device is open.
  496. --*/
  497. {
  498. //
  499. // Init read sync objects
  500. //
  501. pHidDevice->ReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  502. if (!pHidDevice->ReadEvent) {
  503. WARN(("Failed creating read event."));
  504. return FALSE;
  505. }
  506. pHidDevice->CompletionEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  507. if (!pHidDevice->CompletionEvent) {
  508. CloseHandle(pHidDevice->ReadEvent);
  509. WARN(("Failed creating read event."));
  510. return FALSE;
  511. }
  512. // event handle for overlap.
  513. pHidDevice->Overlap.hEvent = pHidDevice->CompletionEvent;
  514. //
  515. // Create hid work thread
  516. //
  517. pHidDevice->fThreadEnabled = TRUE;
  518. pHidDevice->ThreadHandle =
  519. CreateThread(
  520. NULL, // pointer to thread security attributes
  521. 0, // initial thread stack size, in bytes (0 = default)
  522. HidThreadProc, // pointer to thread function
  523. pHidDevice, // argument for new thread
  524. 0, // creation flags
  525. &pHidDevice->ThreadId // pointer to returned thread identifier
  526. );
  527. if (!pHidDevice->ThreadHandle) {
  528. CloseHandle(pHidDevice->ReadEvent);
  529. CloseHandle(pHidDevice->CompletionEvent);
  530. WARN(("Failed creating hid work thread."));
  531. return FALSE;
  532. }
  533. // Register device nofication for this file handle
  534. // This only required for NT5
  535. {
  536. DEV_BROADCAST_HANDLE DevHdr;
  537. ZeroMemory(&DevHdr, sizeof(DevHdr));
  538. DevHdr.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  539. DevHdr.dbch_devicetype = DBT_DEVTYP_HANDLE;
  540. DevHdr.dbch_handle = pHidDevice->HidDevice;
  541. pHidDevice->hNotify =
  542. RegisterDeviceNotification( hWndHidServ,
  543. &DevHdr,
  544. DEVICE_NOTIFY_WINDOW_HANDLE);
  545. if (!pHidDevice->hNotify) {
  546. WARN(("RegisterDeviceNotification failure (%x).", GetLastError()));
  547. }
  548. }
  549. //
  550. // Start the read
  551. //
  552. SetEvent(pHidDevice->ReadEvent);
  553. return TRUE;
  554. }
  555. BOOL
  556. StopHidDevice(
  557. PHID_DEVICE pHidDevice
  558. )
  559. /*++
  560. RoutineDescription:
  561. Eaxh device has a thread that needs to be cleaned up when the device
  562. is "stopped". Here we signal the thread to exit and clean up.
  563. --*/
  564. {
  565. HANDLE hThreadHandle;
  566. DWORD dwResult;
  567. TRACE(("StopHidDevice (%x)", pHidDevice));
  568. // without a device, nothing can be done.
  569. if (!pHidDevice) return FALSE;
  570. // Doing this here prevents us from seeing
  571. // DBT_DEVICEQUERYREMOVEFAILED since the notify handle
  572. // is gone. However, this is acceptable since there is
  573. // nothing useful we will do in response to that event
  574. // anyway.
  575. UnregisterDeviceNotification(pHidDevice->hNotify);
  576. hThreadHandle = pHidDevice->ThreadHandle;
  577. //
  578. // Allow the hid work thread to exit.
  579. //
  580. pHidDevice->fThreadEnabled = FALSE;
  581. // Signal the read event, in case thread is waiting there
  582. INFO(("Set Read Event."));
  583. SetEvent(pHidDevice->ReadEvent);
  584. INFO(("Waiting for work thread to exit..."));
  585. WaitForSingleObject(hThreadHandle, INFINITE);
  586. TRACE(("StopHidDevice (%x) done.", pHidDevice));
  587. return TRUE;
  588. }
  589. BOOL
  590. DestroyHidDeviceList(
  591. void
  592. )
  593. /*++
  594. RoutineDescription:
  595. Unlike a rebuild, all devices here are closed so the process can
  596. exit.
  597. --*/
  598. {
  599. PHID_DEVICE pNext, pCurrent = (PHID_DEVICE)HidDeviceList.pNext;
  600. while (pCurrent) {
  601. RemoveEntryList((PLIST_NODE)&HidDeviceList, (PLIST_NODE)pCurrent);
  602. pNext = pCurrent->pNext;
  603. StopHidDevice(pCurrent);
  604. pCurrent = pNext;
  605. }
  606. return TRUE;
  607. }
  608. BOOL
  609. DestroyDeviceByHandle(
  610. HANDLE hDevice
  611. )
  612. /*++
  613. RoutineDescription:
  614. Here we need to remove a specific device.
  615. --*/
  616. {
  617. PHID_DEVICE pCurrent = (PHID_DEVICE)HidDeviceList.pNext;
  618. while (pCurrent) {
  619. if (hDevice == pCurrent->HidDevice) {
  620. RemoveEntryList((PLIST_NODE)&HidDeviceList, (PLIST_NODE)pCurrent);
  621. #if WIN95_BUILD
  622. //
  623. // Can't do the UnregisterDeviceNotification in the same context
  624. // as when we receive the WM_DEVICECHANGE DBT_REMOVEDEVICECOMPLETE
  625. // for a DBT_DEVTYP_HANDLE
  626. //
  627. PostMessage(hWndHidServ, WM_HIDSERV_STOP_DEVICE, 0, (LPARAM)pCurrent);
  628. #else
  629. StopHidDevice(pCurrent);
  630. #endif // WIN95_BUILD
  631. break;
  632. }
  633. pCurrent = pCurrent->pNext;
  634. }
  635. return TRUE;
  636. }