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.

727 lines
25 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. (len == (sizeof(TEXT("MEDIA"))))) {
  251. if (lstrcmpi(TEXT("MEDIA"), buf) == 0) {
  252. hidDevice->Speakers = TRUE;
  253. }
  254. }
  255. } // else - definitely not speakers
  256. }
  257. //
  258. // </HACK>
  259. //
  260. // Do we already have this device open?
  261. {
  262. PHID_DEVICE pCurrent = (PHID_DEVICE)HidDeviceList.pNext;
  263. while (pCurrent) {
  264. if (pCurrent->DevInst == hidDevice->DevInst) break;
  265. pCurrent = pCurrent->pNext;
  266. }
  267. if (pCurrent) {
  268. // Yes. Mark it and bail on the new node.
  269. pCurrent->Active = TRUE;
  270. INFO(("Device (DevInst = %x) already open.", DevInfoData.DevInst));
  271. goto OpenHidDeviceError;
  272. } else {
  273. // No. Mark the new node and continue.
  274. INFO(("Device (DevInst = %x) is new.", DevInfoData.DevInst));
  275. hidDevice->Active = TRUE;
  276. }
  277. }
  278. hidDevice->HidDevice = CreateFile (
  279. functionClassDeviceData->DevicePath,
  280. GENERIC_READ,
  281. FILE_SHARE_READ | FILE_SHARE_WRITE,
  282. NULL, // no SECURITY_ATTRIBUTES structure
  283. OPEN_EXISTING, // No special create flags
  284. FILE_FLAG_OVERLAPPED, // Do overlapped read/write
  285. NULL); // No template file
  286. if (INVALID_HANDLE_VALUE == hidDevice->HidDevice) {
  287. INFO(("CreateFile failed - %x (%S)", GetLastError(), functionClassDeviceData->DevicePath));
  288. goto OpenHidDeviceError;
  289. } else {
  290. INFO(("CreateFile succeeded Handle(%x) - %S", hidDevice->HidDevice, functionClassDeviceData->DevicePath));
  291. }
  292. if (!HidD_GetPreparsedData (hidDevice->HidDevice, &hidDevice->Ppd)) {
  293. WARN(("HidD_GetPreparsedData failed"));
  294. goto OpenHidDeviceError;
  295. }
  296. if (!HidD_GetAttributes (hidDevice->HidDevice, &hidDevice->Attributes)) {
  297. WARN(("HidD_GetAttributes failed"));
  298. goto OpenHidDeviceError;
  299. }
  300. if (!HidP_GetCaps (hidDevice->Ppd, &hidDevice->Caps)) {
  301. WARN(("HidP_GetCaps failed"));
  302. goto OpenHidDeviceError;
  303. }
  304. // ***Instructive comment from KenRay:
  305. // At this point the client has a choice. It may chose to look at the
  306. // Usage and Page of the top level collection found in the HIDP_CAPS
  307. // structure. In this way it could just use the usages it knows about.
  308. // If either HidP_GetUsages or HidP_GetUsageValue return an error then
  309. // that particular usage does not exist in the report.
  310. // This is most likely the preferred method as the application can only
  311. // use usages of which it already knows.
  312. // In this case the app need not even call GetButtonCaps or GetValueCaps.
  313. // If this is a collection we care about, continue. Else, we get out now.
  314. if (hidDevice->Caps.UsagePage != HIDSERV_USAGE_PAGE) {
  315. TRACE(("This device is not for us (%x)", hidDevice));
  316. goto OpenHidDeviceError;
  317. }
  318. //
  319. // setup Input Data buffers.
  320. //
  321. TRACE(("NumberLinkCollectionNodes = %d", hidDevice->Caps.NumberLinkCollectionNodes));
  322. {
  323. ULONG numNodes = hidDevice->Caps.NumberLinkCollectionNodes;
  324. if (!(LinkCollectionNodes = LocalAlloc(LPTR, hidDevice->Caps.NumberLinkCollectionNodes*sizeof(HIDP_LINK_COLLECTION_NODE)))) {
  325. WARN(("LinkCollectionNodes alloc failed."));
  326. goto OpenHidDeviceError;
  327. }
  328. HidP_GetLinkCollectionNodes(LinkCollectionNodes,
  329. &numNodes,
  330. hidDevice->Ppd);
  331. for (i=0; i<hidDevice->Caps.NumberLinkCollectionNodes; i++) {
  332. INFO(("Link Collection [%d] Type = %x, Alias = %x", i, LinkCollectionNodes[i].CollectionType, LinkCollectionNodes[i].IsAlias));
  333. INFO(("Link Collection [%d] Page = %x, Usage = %x", i, LinkCollectionNodes[i].LinkUsagePage, LinkCollectionNodes[i].LinkUsage));
  334. }
  335. }
  336. //
  337. // Allocate memory to hold on input report
  338. //
  339. if (!(hidDevice->InputReportBuffer = (PCHAR)
  340. LocalAlloc (LPTR, hidDevice->Caps.InputReportByteLength * sizeof (CHAR)))) {
  341. WARN(("InputReportBuffer alloc failed."));
  342. goto OpenHidDeviceError;
  343. }
  344. //
  345. // Allocate memory to hold the button and value capabilities.
  346. // NumberXXCaps is in terms of array elements.
  347. //
  348. if (!(pButtonCaps = (PHIDP_BUTTON_CAPS)
  349. LocalAlloc (LPTR, hidDevice->Caps.NumberInputButtonCaps*sizeof (HIDP_BUTTON_CAPS)))) {
  350. WARN(("buttoncaps alloc failed."));
  351. goto OpenHidDeviceError;
  352. }
  353. if (!(pValueCaps = (PHIDP_VALUE_CAPS)
  354. LocalAlloc (LPTR, hidDevice->Caps.NumberInputValueCaps*sizeof (HIDP_VALUE_CAPS)))) {
  355. WARN(("valuecaps alloc failed."));
  356. goto OpenHidDeviceError;
  357. }
  358. //
  359. // Have the HidP_X functions fill in the capability structure arrays.
  360. //
  361. numCaps = hidDevice->Caps.NumberInputButtonCaps;
  362. TRACE(("NumberInputButtonCaps = %d", numCaps));
  363. HidP_GetButtonCaps (HidP_Input,
  364. pButtonCaps,
  365. &numCaps,
  366. hidDevice->Ppd);
  367. numCaps = hidDevice->Caps.NumberInputValueCaps;
  368. TRACE(("NumberInputValueCaps = %d", numCaps));
  369. HidP_GetValueCaps (HidP_Input,
  370. pValueCaps,
  371. &numCaps,
  372. hidDevice->Ppd);
  373. TRACE(("Buttons:"));
  374. for (i=0; i<hidDevice->Caps.NumberInputButtonCaps; i++) {
  375. TRACE(("UsagePage = 0x%x", pButtonCaps[i].UsagePage));
  376. TRACE(("LinkUsage = 0x%x", pButtonCaps[i].LinkUsage));
  377. TRACE(("LinkUsagePage = 0x%x\n", pButtonCaps[i].LinkUsagePage));
  378. }
  379. //
  380. // Allocate a buffer to hold the struct _HID_DATA structures.
  381. //
  382. hidDevice->InputDataLength = hidDevice->Caps.NumberLinkCollectionNodes +
  383. hidDevice->Caps.NumberInputValueCaps;
  384. if (!(hidDevice->InputData = data = (PHID_DATA)
  385. LocalAlloc (LPTR, hidDevice->InputDataLength * sizeof (HID_DATA)))) {
  386. WARN(("InputData alloc failed."));
  387. goto OpenHidDeviceError;
  388. }
  389. TRACE(("InputDataLength = %d", hidDevice->InputDataLength));
  390. //
  391. // Fill in the button data
  392. // Group button sets by link collection.
  393. //
  394. for (i = 0; i < hidDevice->Caps.NumberLinkCollectionNodes; i++, data++) {
  395. data->IsButtonData = TRUE;
  396. data->LinkUsage = LinkCollectionNodes[i].LinkUsage;
  397. data->UsagePage = LinkCollectionNodes[i].LinkUsagePage;
  398. if (i)
  399. data->LinkCollection = i;
  400. else
  401. data->LinkCollection = HIDP_LINK_COLLECTION_ROOT;
  402. INFO(("Button Link Usage = %x", data->LinkUsage));
  403. INFO(("Button Link Usage Page = %x", data->UsagePage));
  404. INFO(("Button Link Collection = %x", data->LinkCollection));
  405. data->Status = HIDP_STATUS_SUCCESS;
  406. data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
  407. HidP_Input,
  408. hidDevice->Caps.UsagePage,
  409. hidDevice->Ppd);
  410. //make room for the terminator
  411. data->ButtonData.MaxUsageLength++;
  412. if (!(data->ButtonData.Usages = (PUSAGE_AND_PAGE)
  413. LocalAlloc (LPTR, data->ButtonData.MaxUsageLength * sizeof (USAGE_AND_PAGE)))) {
  414. WARN(("Usages alloc failed."));
  415. goto OpenHidDeviceError;
  416. }
  417. if (!(data->ButtonData.PrevUsages = (PUSAGE_AND_PAGE)
  418. LocalAlloc (LPTR, data->ButtonData.MaxUsageLength * sizeof (USAGE_AND_PAGE)))) {
  419. WARN(("PrevUsages alloc failed."));
  420. goto OpenHidDeviceError;
  421. }
  422. }
  423. //
  424. // Fill in the value data
  425. //
  426. for (i = 0; i < hidDevice->Caps.NumberInputValueCaps; i++, data++) {
  427. if (pValueCaps[i].IsRange) {
  428. WARN(("Can't handle value ranges!!"));
  429. }
  430. data->IsButtonData = FALSE;
  431. data->LinkUsage = pValueCaps[i].LinkUsage;
  432. data->UsagePage = pValueCaps[i].LinkUsagePage;
  433. if (pValueCaps[i].LinkCollection)
  434. data->LinkCollection = pValueCaps[i].LinkCollection;
  435. else
  436. data->LinkCollection = HIDP_LINK_COLLECTION_ROOT;
  437. INFO(("Value Link Usage = %x", data->LinkUsage));
  438. INFO(("Value Link Usage Page = %x", data->UsagePage));
  439. INFO(("Value Link Collection = %x", data->LinkCollection));
  440. INFO(("Value LogicalMin = %x", pValueCaps[i].LogicalMin));
  441. INFO(("Value LogicalMax = %x", pValueCaps[i].LogicalMax));
  442. data->ValueData.LogicalRange = pValueCaps[i].LogicalMax - pValueCaps[i].LogicalMin;
  443. data->Status = HIDP_STATUS_SUCCESS;
  444. data->ValueData.Usage = pValueCaps[i].NotRange.Usage;
  445. }
  446. LocalFree(pButtonCaps);
  447. LocalFree(pValueCaps);
  448. LocalFree(LinkCollectionNodes);
  449. LocalFree(functionClassDeviceData);
  450. *HidDevice = hidDevice;
  451. return TRUE;
  452. OpenHidDeviceError:
  453. if (data) {
  454. for (i = 0; i < hidDevice->Caps.NumberLinkCollectionNodes; i++, data++) {
  455. if (data->ButtonData.Usages) {
  456. LocalFree(data->ButtonData.Usages);
  457. }
  458. if (data->ButtonData.PrevUsages) {
  459. LocalFree(data->ButtonData.PrevUsages);
  460. }
  461. }
  462. LocalFree(data);
  463. }
  464. if (pValueCaps) {
  465. LocalFree(pValueCaps);
  466. }
  467. if (pButtonCaps) {
  468. LocalFree (pButtonCaps);
  469. }
  470. if (hidDevice->InputReportBuffer) {
  471. LocalFree (hidDevice->InputReportBuffer);
  472. }
  473. if (LinkCollectionNodes) {
  474. LocalFree (LinkCollectionNodes);
  475. }
  476. if (hidDevice->Ppd) {
  477. HidD_FreePreparsedData (hidDevice->Ppd);
  478. }
  479. if (hidDevice->HidDevice &&
  480. hidDevice->HidDevice != INVALID_HANDLE_VALUE) {
  481. CloseHandle (hidDevice->HidDevice);
  482. }
  483. if (functionClassDeviceData) {
  484. LocalFree (functionClassDeviceData);
  485. }
  486. LocalFree (hidDevice);
  487. return FALSE;
  488. }
  489. BOOL
  490. StartHidDevice(
  491. PHID_DEVICE pHidDevice
  492. )
  493. /*++
  494. RoutineDescription:
  495. Create a work thread to go with the new hid device. This thread lives
  496. as long as the associated hid device is open.
  497. --*/
  498. {
  499. //
  500. // Init read sync objects
  501. //
  502. pHidDevice->ReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  503. if (!pHidDevice->ReadEvent) {
  504. WARN(("Failed creating read event."));
  505. return FALSE;
  506. }
  507. pHidDevice->CompletionEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  508. if (!pHidDevice->CompletionEvent) {
  509. CloseHandle(pHidDevice->ReadEvent);
  510. WARN(("Failed creating read event."));
  511. return FALSE;
  512. }
  513. // event handle for overlap.
  514. pHidDevice->Overlap.hEvent = pHidDevice->CompletionEvent;
  515. //
  516. // Create hid work thread
  517. //
  518. pHidDevice->fThreadEnabled = TRUE;
  519. pHidDevice->ThreadHandle =
  520. CreateThread(
  521. NULL, // pointer to thread security attributes
  522. 0, // initial thread stack size, in bytes (0 = default)
  523. HidThreadProc, // pointer to thread function
  524. pHidDevice, // argument for new thread
  525. 0, // creation flags
  526. &pHidDevice->ThreadId // pointer to returned thread identifier
  527. );
  528. if (!pHidDevice->ThreadHandle) {
  529. CloseHandle(pHidDevice->ReadEvent);
  530. CloseHandle(pHidDevice->CompletionEvent);
  531. WARN(("Failed creating hid work thread."));
  532. return FALSE;
  533. }
  534. // Register device nofication for this file handle
  535. // This only required for NT5
  536. {
  537. DEV_BROADCAST_HANDLE DevHdr;
  538. ZeroMemory(&DevHdr, sizeof(DevHdr));
  539. DevHdr.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  540. DevHdr.dbch_devicetype = DBT_DEVTYP_HANDLE;
  541. DevHdr.dbch_handle = pHidDevice->HidDevice;
  542. pHidDevice->hNotify =
  543. RegisterDeviceNotification( hWndHidServ,
  544. &DevHdr,
  545. DEVICE_NOTIFY_WINDOW_HANDLE);
  546. if (!pHidDevice->hNotify) {
  547. WARN(("RegisterDeviceNotification failure (%x).", GetLastError()));
  548. }
  549. }
  550. //
  551. // Start the read
  552. //
  553. SetEvent(pHidDevice->ReadEvent);
  554. return TRUE;
  555. }
  556. BOOL
  557. StopHidDevice(
  558. PHID_DEVICE pHidDevice
  559. )
  560. /*++
  561. RoutineDescription:
  562. Eaxh device has a thread that needs to be cleaned up when the device
  563. is "stopped". Here we signal the thread to exit and clean up.
  564. --*/
  565. {
  566. HANDLE hThreadHandle;
  567. DWORD dwResult;
  568. TRACE(("StopHidDevice (%x)", pHidDevice));
  569. // without a device, nothing can be done.
  570. if (!pHidDevice) return FALSE;
  571. // Doing this here prevents us from seeing
  572. // DBT_DEVICEQUERYREMOVEFAILED since the notify handle
  573. // is gone. However, this is acceptable since there is
  574. // nothing useful we will do in response to that event
  575. // anyway.
  576. UnregisterDeviceNotification(pHidDevice->hNotify);
  577. hThreadHandle = pHidDevice->ThreadHandle;
  578. //
  579. // Allow the hid work thread to exit.
  580. //
  581. pHidDevice->fThreadEnabled = FALSE;
  582. // Signal the read event, in case thread is waiting there
  583. INFO(("Set Read Event."));
  584. SetEvent(pHidDevice->ReadEvent);
  585. INFO(("Waiting for work thread to exit..."));
  586. WaitForSingleObject(hThreadHandle, INFINITE);
  587. TRACE(("StopHidDevice (%x) done.", pHidDevice));
  588. return TRUE;
  589. }
  590. BOOL
  591. DestroyHidDeviceList(
  592. void
  593. )
  594. /*++
  595. RoutineDescription:
  596. Unlike a rebuild, all devices here are closed so the process can
  597. exit.
  598. --*/
  599. {
  600. PHID_DEVICE pNext, pCurrent = (PHID_DEVICE)HidDeviceList.pNext;
  601. while (pCurrent) {
  602. RemoveEntryList((PLIST_NODE)&HidDeviceList, (PLIST_NODE)pCurrent);
  603. pNext = pCurrent->pNext;
  604. StopHidDevice(pCurrent);
  605. pCurrent = pNext;
  606. }
  607. return TRUE;
  608. }
  609. BOOL
  610. DestroyDeviceByHandle(
  611. HANDLE hDevice
  612. )
  613. /*++
  614. RoutineDescription:
  615. Here we need to remove a specific device.
  616. --*/
  617. {
  618. PHID_DEVICE pCurrent = (PHID_DEVICE)HidDeviceList.pNext;
  619. while (pCurrent) {
  620. if (hDevice == pCurrent->HidDevice) {
  621. RemoveEntryList((PLIST_NODE)&HidDeviceList, (PLIST_NODE)pCurrent);
  622. #if WIN95_BUILD
  623. //
  624. // Can't do the UnregisterDeviceNotification in the same context
  625. // as when we receive the WM_DEVICECHANGE DBT_REMOVEDEVICECOMPLETE
  626. // for a DBT_DEVTYP_HANDLE
  627. //
  628. PostMessage(hWndHidServ, WM_HIDSERV_STOP_DEVICE, 0, (LPARAM)pCurrent);
  629. #else
  630. StopHidDevice(pCurrent);
  631. #endif // WIN95_BUILD
  632. break;
  633. }
  634. pCurrent = pCurrent->pNext;
  635. }
  636. return TRUE;
  637. }