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.

2038 lines
63 KiB

  1. /*****************************************************************************
  2. *
  3. * DIHidEnm.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Support functions for HID enumeration.
  10. *
  11. * Contents:
  12. *
  13. * DIHid_BuildHidList
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. /*****************************************************************************
  18. *
  19. * The sqiffle for this file.
  20. *
  21. *****************************************************************************/
  22. #define sqfl sqflHid
  23. /*****************************************************************************
  24. *
  25. * @doc INTERNAL
  26. *
  27. * @global PHIDDEVICELIST | g_hdl |
  28. *
  29. * List of known HID devices.
  30. *
  31. * @global DWORD | g_tmLastHIDRebuild |
  32. *
  33. * The time we last rebuilt the HID list. Zero means that the
  34. * HID list has never been rebuilt. Watch out for wraparound;
  35. * a 32-bit value rolls over after about 30 days.
  36. *
  37. *****************************************************************************/
  38. #define MSREBUILDRATE 20000 /* Twenty seconds */
  39. #define MSREBUILDRATE_FIFTH 5000 /* Two seconds */
  40. PHIDDEVICELIST g_phdl;
  41. DWORD g_tmLastHIDRebuild;
  42. TCHAR g_tszIdLastRemoved[MAX_PATH];
  43. DWORD g_tmLastRemoved = 0;
  44. TCHAR g_tszIdLastUnknown[MAX_PATH];
  45. DWORD g_tmLastUnknown = 0;
  46. #pragma BEGIN_CONST_DATA
  47. /*****************************************************************************
  48. *
  49. * @doc INTERNAL
  50. *
  51. * @func PHIDDEVICEINFO | phdiFindHIDInstanceGUID |
  52. *
  53. * Locates information given an instance GUID for a HID device.
  54. *
  55. * The parameters have already been validated.
  56. *
  57. * The DLL critical must be held across the call; once the
  58. * critical section is released, the returned pointer becomes
  59. * invalid.
  60. *
  61. * @parm IN PCGUID | pguid |
  62. *
  63. * The instance GUID to be located.
  64. *
  65. * @returns
  66. *
  67. * Pointer to the <t HIDDEVICEINFO> that describes
  68. * the device.
  69. *
  70. *****************************************************************************/
  71. PHIDDEVICEINFO EXTERNAL
  72. phdiFindHIDInstanceGUID(PCGUID pguid)
  73. {
  74. PHIDDEVICEINFO phdi;
  75. AssertF(InCrit());
  76. if(g_phdl)
  77. {
  78. int ihdi;
  79. for(ihdi = 0, phdi = g_phdl->rghdi;
  80. ihdi < g_phdl->chdi;
  81. ihdi++, phdi++)
  82. {
  83. if(IsEqualGUID(pguid, &phdi->guid) )
  84. {
  85. goto done;
  86. }
  87. }
  88. /*
  89. * Memphis Bug#68994. App does not detect USB device.
  90. * App was using product guid.
  91. * Fix: We allow match to HID guid, if product guid is specfied
  92. */
  93. for(ihdi = 0, phdi = g_phdl->rghdi;
  94. ihdi < g_phdl->chdi;
  95. ihdi++, phdi++)
  96. {
  97. if(IsEqualGUID(pguid, &phdi->guidProduct) )
  98. {
  99. RPF("Warning: Use instance GUID (NOT product GUID) to refer to a device.");
  100. goto done;
  101. }
  102. }
  103. #ifdef WINNT
  104. /*
  105. * NT Bug#351951.
  106. * If they are directly asking for one of the predefined joystick
  107. * IDs then see if we have a device mapped to that ID. If so,
  108. * pretend they asked for that GUID instead.
  109. */
  110. /*
  111. * Weakly Assert the range of predefined static joystick instance GUIDs
  112. */
  113. AssertF( ( rgGUID_Joystick[0].Data1 & 0x0f ) == 0 );
  114. AssertF( ( rgGUID_Joystick[0x0f].Data1 & 0x0f ) == 0x0f );
  115. /*
  116. * Check the GUID is the same as the first static one ignoring LS 4 bits
  117. */
  118. if( ( (pguid->Data1 & 0xf0) == (rgGUID_Joystick[0].Data1 & 0xf0) )
  119. && !memcmp( ((PBYTE)&rgGUID_Joystick)+1, ((PBYTE)pguid)+1, sizeof(*pguid) - 1 ) )
  120. {
  121. RPF("Using predefined instance GUIDs is bad and should not work!");
  122. phdi = phdiFindJoyId( pguid->Data1 & 0x0f );
  123. goto done;
  124. }
  125. #endif
  126. }
  127. phdi = 0;
  128. done:;
  129. return phdi;
  130. }
  131. /*****************************************************************************
  132. *
  133. * @doc INTERNAL
  134. *
  135. * @func HRESULT | hresFindHIDInstanceGUID |
  136. *
  137. * Locates information given an instance GUID for a HID device.
  138. *
  139. * The parameters have already been validated.
  140. *
  141. * @parm IN PCGUID | pguid |
  142. *
  143. * The instance GUID to be located.
  144. *
  145. * @parm OUT CREATEDCB * | pcdcb |
  146. *
  147. * Receives pointer to the <f CreateDcb> function for the object.
  148. *
  149. *****************************************************************************/
  150. STDMETHODIMP
  151. hresFindHIDInstanceGUID(PCGUID pguid, CREATEDCB *pcdcb)
  152. {
  153. HRESULT hres;
  154. PHIDDEVICEINFO phdi;
  155. EnterProc(hresFindHIDInstanceGUID, (_ "G", pguid));
  156. AssertF(SUCCEEDED(hresFullValidGuid(pguid, 0)));
  157. DllEnterCrit();
  158. phdi = phdiFindHIDInstanceGUID(pguid);
  159. if(phdi)
  160. {
  161. *pcdcb = CHid_New;
  162. hres = S_OK;
  163. } else
  164. {
  165. hres = DIERR_DEVICENOTREG;
  166. }
  167. DllLeaveCrit();
  168. /*
  169. * Don't use ExitOleProcPpv because that will validate that
  170. * *pcdcb == 0 if FAILED(hres), but that's not our job.
  171. */
  172. ExitOleProc();
  173. return hres;
  174. }
  175. /*****************************************************************************
  176. *
  177. * @doc INTERNAL
  178. *
  179. * @func PHIDDEVICEINFO | phdiFindHIDDeviceId |
  180. *
  181. * Locates information given a deviceID
  182. * (in other words, <enumerator>\<enumerator-specific-device-ID>) for a HID device.
  183. *
  184. * The parameters have already been validated.
  185. *
  186. * The DLL critical must be held across the call; once the
  187. * critical section is released, the returned pointer becomes
  188. * invalid.
  189. *
  190. * @parm IN LPCTSTR | ptszId |
  191. *
  192. * The interface device to be located.
  193. *
  194. * @returns
  195. *
  196. * Pointer to the <t HIDDEVICEINFO> that describes
  197. * the device.
  198. *
  199. *****************************************************************************/
  200. PHIDDEVICEINFO EXTERNAL
  201. phdiFindHIDDeviceId(LPCTSTR ptszId)
  202. {
  203. PHIDDEVICEINFO phdi;
  204. AssertF(InCrit());
  205. if(g_phdl)
  206. {
  207. int ihdi;
  208. for(ihdi = 0, phdi = g_phdl->rghdi; ihdi < g_phdl->chdi;
  209. ihdi++, phdi++)
  210. {
  211. if(phdi->pdidd &&
  212. lstrcmpi(phdi->ptszId, ptszId) == 0)
  213. {
  214. goto done;
  215. }
  216. }
  217. }
  218. phdi = 0;
  219. done:;
  220. return phdi;
  221. }
  222. /*****************************************************************************
  223. *
  224. * @doc INTERNAL
  225. *
  226. * @func PHIDDEVICEINFO | phdiFindHIDDeviceInterface |
  227. *
  228. * Locates information given a device interface
  229. * (in other words, a \\.\... thing) for a HID device.
  230. *
  231. * The parameters have already been validated.
  232. *
  233. * The DLL critical must be held across the call; once the
  234. * critical section is released, the returned pointer becomes
  235. * invalid.
  236. *
  237. * @parm IN LPCTSTR | ptszPath |
  238. *
  239. * The interface device to be located.
  240. *
  241. * @returns
  242. *
  243. * Pointer to the <t HIDDEVICEINFO> that describes
  244. * the device.
  245. *
  246. *****************************************************************************/
  247. PHIDDEVICEINFO EXTERNAL
  248. phdiFindHIDDeviceInterface(LPCTSTR ptszPath)
  249. {
  250. PHIDDEVICEINFO phdi;
  251. AssertF(InCrit());
  252. if(g_phdl)
  253. {
  254. int ihdi;
  255. for(ihdi = 0, phdi = g_phdl->rghdi; ihdi < g_phdl->chdi;
  256. ihdi++, phdi++)
  257. {
  258. if(phdi->pdidd &&
  259. lstrcmpi(phdi->pdidd->DevicePath, ptszPath) == 0)
  260. {
  261. goto done;
  262. }
  263. }
  264. }
  265. phdi = 0;
  266. done:;
  267. return phdi;
  268. }
  269. /*****************************************************************************
  270. *
  271. * @doc INTERNAL
  272. *
  273. * @func HRESULT | hresFindHIDDeviceInterface |
  274. *
  275. * Locates information given a device interface
  276. * (in other words, a \\.\... thing) for a HID device.
  277. *
  278. * The parameters have already been validated.
  279. *
  280. * @parm IN LPCTSTR | ptszPath |
  281. *
  282. * The interface device to be located.
  283. *
  284. * @parm OUT LPGUID | pguidOut |
  285. *
  286. * Receives the instance GUID of the device found.
  287. *
  288. *****************************************************************************/
  289. STDMETHODIMP
  290. hresFindHIDDeviceInterface(LPCTSTR ptszPath, LPGUID pguidOut)
  291. {
  292. HRESULT hres;
  293. PHIDDEVICEINFO phdi;
  294. EnterProc(hresFindHIDDeviceInterface, (_ "s", ptszPath));
  295. DllEnterCrit();
  296. phdi = phdiFindHIDDeviceInterface(ptszPath);
  297. if(phdi)
  298. {
  299. *pguidOut = phdi->guid;
  300. hres = S_OK;
  301. } else
  302. {
  303. hres = DIERR_DEVICENOTREG;
  304. }
  305. DllLeaveCrit();
  306. ExitOleProc();
  307. return hres;
  308. }
  309. /*****************************************************************************
  310. *
  311. * @doc INTERNAL
  312. *
  313. * @func void | DIHid_ProbeMouse |
  314. *
  315. * That this function exists at all is a total hack to work
  316. * around bugs in Memphis and NT5.
  317. *
  318. * If you call GetSystemMetrics(SM_WHEELPRESENT) or
  319. * GetSystemMetrics(SM_MOUSEBUTTONS), USER32 does not
  320. * return the correct values if your HID mouse is
  321. * not the same as your PS/2 mouse (if any).
  322. *
  323. * For example, if your PS/2 mouse is a regular two-button
  324. * mouse but your HID mouse is a wheel mouse, GetSystemMetrics
  325. * will still say "No wheel, 2 buttons" even though it's wrong.
  326. *
  327. * So what we have to do is wander through all the HID mice in
  328. * the system and record the number of buttons they have,
  329. * and whether they have a wheel.
  330. *
  331. * That way, when we create a system mouse, we can take the
  332. * maximum of every supported device.
  333. *
  334. *****************************************************************************/
  335. void INTERNAL
  336. DIHid_ProbeMouse(PHIDDEVICEINFO phdi, PHIDP_CAPS pcaps,
  337. PHIDP_PREPARSED_DATA ppd)
  338. {
  339. LPVOID pvReport;
  340. HRESULT hres;
  341. /*
  342. * Get the number of buttons in the generic button page.
  343. * This is the only page the MOUHID uses.
  344. */
  345. phdi->osd.uiButtons =
  346. HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, ppd);
  347. /*
  348. * See if there is a HID_USAGE_GENERIC_WHEEL.
  349. * This is the way that MOUHID detects a wheel.
  350. */
  351. hres = AllocCbPpv(pcaps->InputReportByteLength, &pvReport);
  352. if(SUCCEEDED(hres))
  353. {
  354. ULONG ul;
  355. NTSTATUS stat;
  356. stat = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0,
  357. HID_USAGE_GENERIC_WHEEL, &ul, ppd,
  358. pvReport,
  359. pcaps->InputReportByteLength);
  360. if(SUCCEEDED(stat))
  361. {
  362. phdi->osd.uiAxes = 3;
  363. }
  364. FreePv(pvReport);
  365. }
  366. }
  367. /*****************************************************************************
  368. *
  369. * @doc INTERNAL
  370. *
  371. * @func void | DIHid_ParseUsagePage |
  372. *
  373. * ISSUE-2001/02/06-TimGill Enumeration needs to know device type
  374. * Parse the usage page information and create a first pass at DI
  375. * style type information.
  376. * This really is not enough information to be useful as
  377. * enumeration needs to know the final device type.
  378. *
  379. *****************************************************************************/
  380. void INTERNAL
  381. DIHid_ParseUsagePage(PHIDDEVICEINFO phdi, PHIDP_CAPS pcaps,
  382. PHIDP_PREPARSED_DATA ppd)
  383. {
  384. switch(pcaps->UsagePage)
  385. {
  386. case HID_USAGE_PAGE_GENERIC:
  387. switch(pcaps->Usage)
  388. {
  389. /*
  390. * MouHID accepts either HID_USAGE_GENERIC_MOUSE or
  391. * HID_USAGE_GENERIC_POINTER, so we will do the same.
  392. */
  393. case HID_USAGE_GENERIC_MOUSE:
  394. case HID_USAGE_GENERIC_POINTER:
  395. DIHid_ProbeMouse(phdi, pcaps, ppd);
  396. phdi->osd.dwDevType =
  397. MAKE_DIDEVICE_TYPE(DI8DEVTYPE_MOUSE,
  398. DI8DEVTYPEMOUSE_UNKNOWN) |
  399. DIDEVTYPE_HID;
  400. break;
  401. case HID_USAGE_GENERIC_JOYSTICK:
  402. phdi->osd.dwDevType =
  403. MAKE_DIDEVICE_TYPE(DI8DEVTYPE_JOYSTICK,
  404. DI8DEVTYPEJOYSTICK_STANDARD) |
  405. DIDEVTYPE_HID;
  406. break;
  407. case HID_USAGE_GENERIC_GAMEPAD:
  408. phdi->osd.dwDevType =
  409. MAKE_DIDEVICE_TYPE(DI8DEVTYPE_GAMEPAD,
  410. DI8DEVTYPEGAMEPAD_STANDARD) |
  411. DIDEVTYPE_HID;
  412. break;
  413. case HID_USAGE_GENERIC_KEYBOARD:
  414. phdi->osd.dwDevType =
  415. MAKE_DIDEVICE_TYPE(DI8DEVTYPE_KEYBOARD,
  416. DI8DEVTYPEKEYBOARD_UNKNOWN) |
  417. DIDEVTYPE_HID;
  418. break;
  419. default:
  420. phdi->osd.dwDevType = DI8DEVTYPE_DEVICE | DIDEVTYPE_HID;
  421. break;
  422. }
  423. break;
  424. default:
  425. phdi->osd.dwDevType = DI8DEVTYPE_DEVICE | DIDEVTYPE_HID;
  426. break;
  427. }
  428. }
  429. /*****************************************************************************
  430. *
  431. * @doc INTERNAL
  432. *
  433. * @func BOOL | DIHid_GetDevicePath |
  434. *
  435. * Obtain the path for the device. This is a simple wrapper
  436. * function to keep DIHid_BuildHidListEntry from getting too
  437. * annoying.
  438. *
  439. * This also gets the devinfo so we can get the
  440. * instance ID string for subsequent use to get the
  441. * friendly name, etc.
  442. *
  443. *****************************************************************************/
  444. BOOL EXTERNAL
  445. DIHid_GetDevicePath(HDEVINFO hdev,
  446. PSP_DEVICE_INTERFACE_DATA pdid,
  447. PSP_DEVICE_INTERFACE_DETAIL_DATA *ppdidd,
  448. OPTIONAL PSP_DEVINFO_DATA pdinf)
  449. {
  450. HRESULT hres;
  451. BOOL fRc;
  452. DWORD cbRequired;
  453. EnterProcI(DIHid_GetDevicePath, (_ "xp", hdev, pdid));
  454. AssertF(*ppdidd == 0);
  455. /*
  456. * Ask for the required size then allocate it then fill it.
  457. *
  458. * Note that we don't need to free the memory on the failure
  459. * path; our caller will do the necessary memory freeing.
  460. *
  461. * Sigh. Windows NT and Windows 98 implement
  462. * SetupDiGetDeviceInterfaceDetail differently if you are
  463. * querying for the buffer size.
  464. *
  465. * Windows 98 returns FALSE, and GetLastError() returns
  466. * ERROR_INSUFFICIENT_BUFFER.
  467. *
  468. * Windows NT returns TRUE.
  469. *
  470. * So we allow the cases either where the call succeeds or
  471. * the call fails with ERROR_INSUFFICIENT_BUFFER.
  472. */
  473. if(SetupDiGetDeviceInterfaceDetail(hdev, pdid, 0, 0,
  474. &cbRequired, 0) ||
  475. GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  476. {
  477. hres = AllocCbPpv(cbRequired, ppdidd);
  478. // Keep prefix happy, manbug 29341
  479. if(SUCCEEDED(hres) && ( *ppdidd != NULL) )
  480. {
  481. PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = *ppdidd;
  482. /*
  483. * Note, The cbSize field always contains the size of the fixed
  484. * part of the data structure, not a size reflecting the
  485. * variable-length string at the end.
  486. */
  487. pdidd->cbSize = cbX(SP_DEVICE_INTERFACE_DETAIL_DATA);
  488. fRc = SetupDiGetDeviceInterfaceDetail(hdev, pdid, pdidd,
  489. cbRequired, &cbRequired, pdinf);
  490. if(!fRc)
  491. {
  492. FreePpv(ppdidd);
  493. /*
  494. * Set fRc = FALSE again, so the compiler doesn't need
  495. * to blow a register to cache the value zero.
  496. */
  497. fRc = FALSE;
  498. }
  499. } else
  500. {
  501. fRc = FALSE;
  502. }
  503. } else
  504. {
  505. SquirtSqflPtszV(sqfl | sqflError,
  506. TEXT("%hs: SetupDiGetDeviceInterfaceDetail failed 1, ")
  507. TEXT("Error = %d"),
  508. s_szProc, GetLastError());
  509. fRc = FALSE;
  510. }
  511. ExitProcF(fRc);
  512. return fRc;
  513. }
  514. /*****************************************************************************
  515. *
  516. * @doc INTERNAL
  517. *
  518. * @func BOOL | DIHid_GetDeviceInstanceId |
  519. *
  520. * Obtain the instance ID for the device.
  521. *
  522. * The instance ID allows us to get access to device
  523. * properties later.
  524. *
  525. *****************************************************************************/
  526. BOOL EXTERNAL
  527. DIHid_GetDeviceInstanceId(HDEVINFO hdev,
  528. PSP_DEVINFO_DATA pdinf, LPTSTR *pptszId)
  529. {
  530. BOOL fRc;
  531. DWORD ctchRequired;
  532. AssertF(*pptszId == 0);
  533. /*
  534. * Ask for the required size then allocate it then fill it.
  535. *
  536. * Note that we don't need to free the memory on the failure
  537. * path; our caller will do the necessary memory freeing.
  538. */
  539. if(SetupDiGetDeviceInstanceId(hdev, pdinf, NULL, 0,
  540. &ctchRequired) == 0 &&
  541. GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  542. {
  543. HRESULT hres;
  544. hres = AllocCbPpv(cbCtch(ctchRequired), pptszId);
  545. if(SUCCEEDED(hres))
  546. {
  547. fRc = SetupDiGetDeviceInstanceId(hdev, pdinf, *pptszId,
  548. ctchRequired, NULL);
  549. } else
  550. {
  551. fRc = FALSE;
  552. }
  553. } else
  554. {
  555. fRc = FALSE;
  556. }
  557. return fRc;
  558. }
  559. /*****************************************************************************
  560. *
  561. * @doc INTERNAL
  562. *
  563. * @func BOOL | DIHid_GetInstanceGUID |
  564. *
  565. * Read the instance GUID from the registry, or create one if
  566. * necessary.
  567. *
  568. *****************************************************************************/
  569. BOOL INTERNAL
  570. DIHid_GetInstanceGUID(HKEY hk, LPGUID pguid)
  571. {
  572. LONG lRc;
  573. DWORD cb;
  574. cb = cbX(GUID);
  575. lRc = RegQueryValueEx(hk, TEXT("GUID"), 0, 0, (PV)pguid, &cb);
  576. if(lRc != ERROR_SUCCESS)
  577. {
  578. DICreateGuid(pguid);
  579. lRc = RegSetValueEx(hk, TEXT("GUID"), 0, REG_BINARY,
  580. (PV)pguid, cbX(GUID));
  581. }
  582. return lRc == ERROR_SUCCESS;
  583. }
  584. /*****************************************************************************
  585. *
  586. * @doc INTERNAL
  587. *
  588. * @func void | DIHid_EmptyHidList |
  589. *
  590. * Empty the list of HID devices.
  591. *
  592. * This function must be called under the DLL critical section.
  593. *
  594. *****************************************************************************/
  595. void EXTERNAL
  596. DIHid_EmptyHidList(void)
  597. {
  598. AssertF(InCrit());
  599. /*
  600. * Free all the old strings and things in the HIDDEVICEINFO's.
  601. */
  602. if(g_phdl)
  603. {
  604. int ihdi;
  605. for(ihdi = 0; ihdi < g_phdl->chdi; ihdi++)
  606. {
  607. FreePpv(&g_phdl->rghdi[ihdi].pdidd);
  608. FreePpv(&g_phdl->rghdi[ihdi].ptszId);
  609. if(g_phdl->rghdi[ihdi].hk)
  610. {
  611. RegCloseKey(g_phdl->rghdi[ihdi].hk);
  612. }
  613. }
  614. /*
  615. * We invalidated all the pointers, so make sure
  616. * nobody looks at them.
  617. */
  618. g_phdl->chdi = 0;
  619. }
  620. }
  621. /*****************************************************************************
  622. *
  623. * @doc INTERNAL
  624. *
  625. * @func void | DIHid_CheckHidList |
  626. *
  627. * Check the list of HID devices, and free whose what can not be opened
  628. *
  629. * This function must be called under the DLL critical section.
  630. *
  631. *****************************************************************************/
  632. void INTERNAL
  633. DIHid_CheckHidList(void)
  634. {
  635. HANDLE hf;
  636. EnterProcI(DIHid_CheckList, (_ "x", 0x0) );
  637. AssertF(InCrit());
  638. /*
  639. * Free all the information of the device cannot be opened
  640. */
  641. if(g_phdl)
  642. {
  643. int ihdi;
  644. for(ihdi = 0, g_phdl->chdi = 0; ihdi < g_phdl->chdiAlloc; ihdi++)
  645. {
  646. if( g_phdl->rghdi[ihdi].pdidd )
  647. {
  648. /*
  649. * Open the device
  650. */
  651. hf = CreateFile(g_phdl->rghdi[ihdi].pdidd->DevicePath,
  652. GENERIC_READ | GENERIC_WRITE,
  653. FILE_SHARE_READ | FILE_SHARE_WRITE,
  654. 0, /* no SECURITY_ATTRIBUTES */
  655. OPEN_EXISTING,
  656. 0, /* attributes */
  657. 0); /* template */
  658. if(hf == INVALID_HANDLE_VALUE)
  659. {
  660. #if 0
  661. PHIDDEVICEINFO phdi;
  662. PBUSDEVICEINFO pbdi;
  663. CloseHandle(hf);
  664. phdi = &g_phdl->rghdi[ihdi];
  665. DllEnterCrit();
  666. phdi = phdiFindHIDDeviceInterface(g_phdl->rghdi[ihdi].pdidd->DevicePath);
  667. AssertF(phdi != NULL);
  668. pbdi = pbdiFromphdi(phdi);
  669. DllLeaveCrit();
  670. if( pbdi != NULL )
  671. {
  672. if( pbdi->fDeleteIfNotConnected == TRUE )
  673. {
  674. lstrcpy( g_tszIdLastRemoved, pbdi->ptszId );
  675. g_tmLastRemoved = GetTickCount();
  676. DIBusDevice_Remove(pbdi);
  677. pbdi->fDeleteIfNotConnected = FALSE;
  678. }
  679. }
  680. #endif
  681. FreePpv(&g_phdl->rghdi[ihdi].pdidd);
  682. FreePpv(&g_phdl->rghdi[ihdi].ptszId);
  683. if(g_phdl->rghdi[ihdi].hk)
  684. {
  685. RegCloseKey(g_phdl->rghdi[ihdi].hk);
  686. }
  687. ZeroX( g_phdl->rghdi[ihdi] );
  688. SquirtSqflPtszV(sqfl | sqflError,
  689. TEXT("%hs: CreateFile(%s) failed? le=%d"),
  690. s_szProc, g_phdl->rghdi[ihdi].pdidd->DevicePath, GetLastError());
  691. /* Skip erroneous items */
  692. } else
  693. {
  694. CloseHandle(hf);
  695. g_phdl->chdi++;
  696. }
  697. }
  698. }
  699. //re-order the existing devices, put them at the front of the hid list.
  700. for(ihdi = 0; ihdi < g_phdl->chdi; ihdi++)
  701. {
  702. if( !g_phdl->rghdi[ihdi].pdidd )
  703. {
  704. int ihdi2;
  705. //find the existing device from the biggest index in the hid list.
  706. for( ihdi2 = g_phdl->chdiAlloc; ihdi2 >= ihdi+1; ihdi2-- )
  707. {
  708. if( g_phdl->rghdi[ihdi2].pdidd )
  709. {
  710. memcpy( &g_phdl->rghdi[ihdi], &g_phdl->rghdi[ihdi2], sizeof(HIDDEVICEINFO) );
  711. ZeroX( g_phdl->rghdi[ihdi2] );
  712. }
  713. }
  714. }
  715. }
  716. }
  717. ExitProc();
  718. return;
  719. }
  720. /*****************************************************************************
  721. *
  722. * @doc INTERNAL
  723. *
  724. * @func HRESULT | DIHid_CreateDeviceInstanceKeys |
  725. *
  726. * Create the keys associaciated with a particular device.
  727. *
  728. * @parm IN OUT PHIDDEVICEINFO | phdi |
  729. *
  730. * HIDDEVICEINFO we to use/update.
  731. *
  732. * @returns
  733. *
  734. * S_OK for a success
  735. * A COM error for a failure
  736. *
  737. *****************************************************************************/
  738. #define DIHES_UNDEFINED 0
  739. #define DIHES_UNKNOWN 1
  740. #define DIHES_KNOWN 2
  741. HRESULT INTERNAL
  742. DIHid_CreateDeviceInstanceKeys( PHIDDEVICEINFO phdi, PBYTE pState )
  743. {
  744. HRESULT hres;
  745. HKEY hkDin;
  746. USHORT uVid, uPid;
  747. TCHAR tszName[MAX_PATH];
  748. PTCHAR ptszInstance = NULL;
  749. EnterProcI(DIHid_CreateDeviceInstanceKeys, (_ "p", phdi));
  750. /*
  751. * Unfortunately, we need to open our registry keys before we can open
  752. * the device so rather than ask the device for its VID and PID, we
  753. * parse it from the
  754. */
  755. /*
  756. * ISSUE-2001/01/27-MarcAnd Should avoid parsing device ID ourselves
  757. * Need to find some documented way to parse out the three parts of the
  758. * device ID: class, device and instance in case the form changes.
  759. */
  760. /*
  761. * The format of the device ID is a set of strings in the form
  762. * "<class>\<device>\<instance>" with variable case.
  763. * For HID devices, the class should be "hid" and the instance is a set
  764. * of hex values separated by ampersands. The device string should be
  765. * of the form vid_9999&pid_9999 but devices exposed via a gameport can
  766. * use any string that PnP accepts.
  767. */
  768. AssertF( ( phdi->ptszId[0] == TEXT('H') ) || ( phdi->ptszId[0] == TEXT('h') ) );
  769. AssertF( ( phdi->ptszId[1] == TEXT('I') ) || ( phdi->ptszId[1] == TEXT('i') ) );
  770. AssertF( ( phdi->ptszId[2] == TEXT('D') ) || ( phdi->ptszId[2] == TEXT('d') ) );
  771. /*
  772. * Assert that a defined state and a valid VID/PID on entry must both be
  773. * true or both false (so we can use the state after getting VID/PID).
  774. */
  775. if( ( phdi->ProductID != 0 ) && ( phdi->VendorID !=0 ) )
  776. {
  777. AssertF( *pState != DIHES_UNDEFINED );
  778. }
  779. else
  780. {
  781. AssertF( *pState == DIHES_UNDEFINED );
  782. }
  783. if( phdi->ptszId[3] == TEXT('\\') )
  784. {
  785. PTCHAR ptcSrc;
  786. PTCHAR ptDevId;
  787. ptcSrc = ptDevId = &phdi->ptszId[4];
  788. if( ( phdi->ProductID != 0 ) && ( phdi->VendorID !=0 ) )
  789. {
  790. int iLen;
  791. /*
  792. * Create the key name from VID / PID (because it may be
  793. * different from the value derived from the device ID).
  794. */
  795. iLen = wsprintf(tszName, VID_PID_TEMPLATE, phdi->VendorID, phdi->ProductID);
  796. while( *ptcSrc != TEXT('\\') )
  797. {
  798. if( *ptcSrc == TEXT('\0') )
  799. {
  800. break;
  801. }
  802. ptcSrc++;
  803. }
  804. if( ( *ptcSrc != TEXT('\0') )
  805. && ( ptcSrc != ptDevId ) )
  806. {
  807. ptszInstance = &tszName[iLen+2];
  808. lstrcpy( ptszInstance, ptcSrc+1 );
  809. }
  810. }
  811. else
  812. {
  813. PTCHAR ptcDest;
  814. BOOL fFirstAmpersand = FALSE;
  815. /*
  816. * Copy the device ID (minus "HID\") so we can corrupt the copy.
  817. * Convert to upper case and find the other slash on the way.
  818. * Terminate the string at either the separator slash or a second
  819. * ampersand if one is found (VID_1234&PID_1234&COL_12 or REV_12).
  820. * These are device IDs so we're only really interested in keeping
  821. * real VID\PID style IDs in upper case so we don't care if this
  822. * is imperfect for other cases as long as it is reproducable.
  823. */
  824. for( ptcDest = tszName; *ptcSrc != TEXT('\0'); ptcSrc++, ptcDest++ )
  825. {
  826. if( ( *ptcSrc >= TEXT('a') ) && ( *ptcSrc <= TEXT('z') ) )
  827. {
  828. *ptcDest = *ptcSrc - ( TEXT('a') - TEXT('A') );
  829. }
  830. else if( *ptcSrc == TEXT('&') )
  831. {
  832. if( ( ptszInstance != NULL )
  833. || !fFirstAmpersand )
  834. {
  835. fFirstAmpersand = TRUE;
  836. *ptcDest = TEXT('&');
  837. }
  838. else
  839. {
  840. *ptcDest = TEXT('\0');
  841. }
  842. }
  843. else if( *ptcSrc != TEXT('\\') )
  844. {
  845. *ptcDest = *ptcSrc;
  846. }
  847. else
  848. {
  849. /*
  850. * Only one slash and not the first char
  851. */
  852. if( ( ptszInstance != NULL )
  853. || ( ptcDest == tszName ) )
  854. {
  855. ptszInstance = NULL;
  856. break;
  857. }
  858. /*
  859. * Separate the device ID and the instance
  860. */
  861. *ptcDest = TEXT('\0');
  862. ptszInstance = ptcDest + 1;
  863. }
  864. }
  865. if( ptszInstance != NULL )
  866. {
  867. #ifndef UNICODE
  868. /*
  869. * ISSUE-2001/02/06-MarcAnd Should have a ParseVIDPIDA
  870. * ParseVIDPID is going to convert this string back to ANSI ifndef UNICODE
  871. */
  872. WCHAR wszName[cbszVIDPID];
  873. AToU( wszName, cA(wszName), ptDevId );
  874. if( ( ptszInstance - tszName == cbszVIDPID )
  875. && ( ParseVIDPID( &uVid, &uPid, wszName ) ) )
  876. #else
  877. if( ( ptszInstance - tszName == cbszVIDPID )
  878. && ( ParseVIDPID( &uVid, &uPid, ptDevId ) ) )
  879. #endif
  880. {
  881. phdi->VendorID = uVid;
  882. phdi->ProductID = uPid;
  883. }
  884. else
  885. {
  886. SquirtSqflPtszV(sqfl | sqflBenign,
  887. TEXT("%hs: ID %s, len %d not VID PID"),
  888. s_szProc, ptDevId, ptszInstance - tszName );
  889. }
  890. /*
  891. * Terminate the instance string
  892. */
  893. *ptcDest = TEXT('\0');
  894. }
  895. }
  896. }
  897. if( ptszInstance == NULL )
  898. {
  899. hres = E_INVALIDARG;
  900. RPF( "Ignoring invalid device ID handle \"%s\" enumerated by system" );
  901. }
  902. else
  903. {
  904. //Open our own reg key under MediaProperties\DirectInput,
  905. //creating it if necessary.
  906. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  907. REGSTR_PATH_DITYPEPROP,
  908. DI_KEY_ALL_ACCESS,
  909. REG_OPTION_NON_VOLATILE,
  910. &hkDin);
  911. if( SUCCEEDED(hres) )
  912. {
  913. HKEY hkVidPid;
  914. hres = hresMumbleKeyEx(hkDin,
  915. (LPTSTR)tszName,
  916. DI_KEY_ALL_ACCESS,
  917. REG_OPTION_NON_VOLATILE,
  918. &hkVidPid);
  919. if( SUCCEEDED(hres) )
  920. {
  921. HKEY hkDevInsts;
  922. /*
  923. * Need to create user subkeys even if the device ID is not
  924. * VID/PID as an auto-detect device could use the auto-detect
  925. * HW ID for whatever device it detects.
  926. */
  927. //Create the key for Calibration
  928. HKEY hkCal;
  929. hres = hresMumbleKeyEx(hkVidPid,
  930. TEXT("Calibration"),
  931. DI_KEY_ALL_ACCESS,
  932. REG_OPTION_NON_VOLATILE,
  933. &hkCal);
  934. if (SUCCEEDED(hres))
  935. {
  936. //Create the key for the instance (as the user sees it).
  937. //For this, need to find out how many instances of the particular device
  938. //we have already enumerated.
  939. int ihdi;
  940. int iNum = 0;
  941. TCHAR tszInst[3];
  942. for( ihdi = 0; ihdi < g_phdl->chdi; ihdi++)
  943. {
  944. if ((g_phdl->rghdi[ihdi].VendorID == phdi->VendorID) && (g_phdl->rghdi[ihdi].ProductID == phdi->ProductID))
  945. {
  946. iNum++;
  947. }
  948. }
  949. wsprintf(tszInst, TEXT("%u"), iNum);
  950. hres = hresMumbleKeyEx(hkCal,
  951. tszInst,
  952. DI_KEY_ALL_ACCESS,
  953. REG_OPTION_NON_VOLATILE,
  954. &phdi->hk);
  955. if (SUCCEEDED(hres))
  956. {
  957. DIHid_GetInstanceGUID(phdi->hk, &phdi->guid);
  958. }
  959. else
  960. {
  961. SquirtSqflPtszV(sqfl | sqflError,
  962. TEXT("%hs: RegCreateKeyEx failed on Instance reg key"),
  963. s_szProc);
  964. }
  965. RegCloseKey(hkCal);
  966. }
  967. else
  968. {
  969. SquirtSqflPtszV(sqfl | sqflError,
  970. TEXT("%hs: RegCreateKeyEx failed on Calibration reg key"),
  971. s_szProc);
  972. }
  973. /*
  974. * Try to open the device (plug) instances to find out or
  975. * update the staus of processing on this device but don't
  976. * return any failures.
  977. */
  978. if( SUCCEEDED( hresMumbleKeyEx(hkVidPid,
  979. TEXT("DeviceInstances"),
  980. DI_KEY_ALL_ACCESS,
  981. REG_OPTION_NON_VOLATILE,
  982. &hkDevInsts) ) )
  983. {
  984. LONG lRc;
  985. if( *pState == DIHES_UNDEFINED )
  986. {
  987. DWORD cb = cbX( *pState );
  988. lRc = RegQueryValueEx( hkDevInsts,
  989. ptszInstance, 0, 0, pState, &cb );
  990. if( lRc != ERROR_SUCCESS )
  991. {
  992. SquirtSqflPtszV(sqfl | sqflBenign,
  993. TEXT("%hs: RegQueryValueEx failed (%d) to get state for instance %s"),
  994. s_szProc, lRc, ptszInstance );
  995. /*
  996. * Make sure it was not trashed in the failure
  997. */
  998. *pState = DIHES_UNDEFINED;
  999. }
  1000. }
  1001. else
  1002. {
  1003. lRc = RegSetValueEx( hkDevInsts,
  1004. ptszInstance, 0, REG_BINARY, pState, cbX( *pState ) );
  1005. if( lRc != ERROR_SUCCESS)
  1006. {
  1007. SquirtSqflPtszV(sqfl | sqflBenign,
  1008. TEXT("%hs: RegSetValueEx failed (%d) to update state for instance %S"),
  1009. s_szProc, lRc, ptszInstance );
  1010. }
  1011. }
  1012. RegCloseKey(hkDevInsts);
  1013. }
  1014. else
  1015. {
  1016. SquirtSqflPtszV(sqfl | sqflBenign,
  1017. TEXT("%hs: Failed to open DeviceInstances key"),
  1018. s_szProc );
  1019. }
  1020. RegCloseKey(hkVidPid);
  1021. }
  1022. else
  1023. {
  1024. SquirtSqflPtszV(sqfl | sqflError,
  1025. TEXT("%hs: RegCreateKeyEx failed on Device reg key"),
  1026. s_szProc);
  1027. }
  1028. RegCloseKey(hkDin);
  1029. }
  1030. else
  1031. {
  1032. SquirtSqflPtszV(sqfl | sqflError,
  1033. TEXT("%hs: RegOpenKeyEx failed on DirectInput reg key"),
  1034. s_szProc);
  1035. }
  1036. }
  1037. ExitOleProc();
  1038. return hres;
  1039. }
  1040. /*****************************************************************************
  1041. *
  1042. * @doc INTERNAL
  1043. *
  1044. * @func void | DIHid_GetDevInfo |
  1045. *
  1046. * Get the HIDDEVICEINFO info from the device
  1047. *
  1048. * @parm HDEVINFO | hdev |
  1049. *
  1050. * Device to get information
  1051. *
  1052. * @parm PSP_DEVICE_INTERFACE_DATA | pdid |
  1053. *
  1054. * Describes the device
  1055. *
  1056. * @parm OUT PHIDDEVICEINFO | phdi |
  1057. *
  1058. * HIDDEVICEINFO we need to collect
  1059. *
  1060. * @returns
  1061. *
  1062. * Nonzero on success.
  1063. *
  1064. *****************************************************************************/
  1065. BOOL INTERNAL
  1066. DIHid_GetDevInfo( HDEVINFO hdev, PSP_DEVICE_INTERFACE_DATA pdid, PHIDDEVICEINFO phdi )
  1067. {
  1068. BOOL fRc = FALSE;
  1069. SP_DEVINFO_DATA dinf;
  1070. EnterProcI(DIHid_GetDevInfo, (_ "xpp", hdev, pdid, phdi));
  1071. /*
  1072. * Open the registry key for the device so we can obtain
  1073. * auxiliary information.
  1074. */
  1075. dinf.cbSize = cbX(SP_DEVINFO_DATA);
  1076. /*
  1077. * Get the instance GUID and the path to
  1078. * the HID device so we can talk to it.
  1079. */
  1080. if (DIHid_GetDevicePath(hdev, pdid, &phdi->pdidd, &dinf) &&
  1081. DIHid_GetDeviceInstanceId(hdev, &dinf, &phdi->ptszId))
  1082. {
  1083. HANDLE hf;
  1084. TCHAR tszName[MAX_PATH];
  1085. ULONG len = sizeof(tszName);
  1086. BOOL fCreateOK = FALSE;
  1087. BYTE bNewState = DIHES_UNDEFINED;
  1088. BYTE bPreviousState = DIHES_UNDEFINED;
  1089. DIHid_CreateDeviceInstanceKeys( phdi, &bPreviousState );
  1090. //////////////////// BEGIN OF PATCH ////////////////////////
  1091. /*
  1092. * This part is to keep the compatibility with Win2k Gold.
  1093. * Some driver, like Thrustmaster driver, tries to get Joystick ID
  1094. * from old registry key:
  1095. * HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{4d1e55b2-f16f-11cf-88cb-001111000030}\<?????????>\#\Device Parameters\DirectX
  1096. * See Windows bug 395416 for detail.
  1097. */
  1098. {
  1099. HKEY hkDev;
  1100. HRESULT hres;
  1101. /*
  1102. * Open the registry key for the device so we can obtain
  1103. * auxiliary information, creating it if necessary.
  1104. */
  1105. hkDev = SetupDiCreateDeviceInterfaceRegKey(hdev, pdid, 0,
  1106. MAXIMUM_ALLOWED, NULL, NULL);
  1107. if(hkDev && hkDev != INVALID_HANDLE_VALUE)
  1108. {
  1109. hres = hresMumbleKeyEx(hkDev,
  1110. TEXT("DirectX"),
  1111. KEY_ALL_ACCESS,
  1112. REG_OPTION_NON_VOLATILE,
  1113. &phdi->hkOld);
  1114. if(SUCCEEDED(hres) )
  1115. {
  1116. LONG lRc;
  1117. lRc = RegSetValueEx(phdi->hkOld, TEXT("GUID"), 0, REG_BINARY,
  1118. (PV)&phdi->guid, cbX(GUID));
  1119. }
  1120. }
  1121. }
  1122. /////////////////// END OF PATCH /////////////////////
  1123. /*
  1124. * Before we CreateFile on the device, we need to make sure the
  1125. * device is not in the middle of the setup process. If a device has
  1126. * no device description it is probably still being setup (plugged
  1127. * in) so delay opening it to avoid having an open handle on a device
  1128. * that setup is trying to update. If that happens, setup will prompt
  1129. * the user to reboot to use the device.
  1130. * Since HIDs are "RAW" devices (don't need drivers) don't ignore
  1131. * such a device forever.
  1132. */
  1133. if( CM_Get_DevNode_Registry_Property(dinf.DevInst,
  1134. CM_DRP_DEVICEDESC,
  1135. NULL,
  1136. tszName,
  1137. &len,
  1138. 0) == CR_SUCCESS)
  1139. {
  1140. /*
  1141. * Known device.
  1142. */
  1143. fCreateOK = TRUE;
  1144. bNewState = DIHES_KNOWN;
  1145. }
  1146. else
  1147. {
  1148. /*
  1149. * Unknown device. This either means that setup has not yet
  1150. * completed processing the HID or that no device description
  1151. * was set for the device where it matched.
  1152. *
  1153. * For now, see if we've seen this device instance before.
  1154. * If we have, then if it was previously unknown assume it's
  1155. * going to stay that way and start using the device. If it
  1156. * was previously known or we've never seen it before wait for
  1157. * a while in case setup is just taking it's time.
  1158. *
  1159. * If the device was the last one we tried to remove, then it's
  1160. * OK to open it while it's still showing up.
  1161. * ISSUE-2001/02/06-MarcAnd Opening removed devices
  1162. * I assume this is so we get a read failure when it really goes
  1163. * away but I don't know how that's better than ignoring it.
  1164. */
  1165. /*
  1166. * ISSUE-2001/01/27-MarcAnd Should keep real list with status
  1167. * We should keep a complete list of all the devices we know
  1168. * about with status indicating things like "pending on
  1169. * setup since X" or "removed" not these globals.
  1170. */
  1171. if( lstrcmpi(phdi->ptszId, g_tszIdLastRemoved) == 0 )
  1172. {
  1173. fCreateOK = TRUE;
  1174. bNewState = bPreviousState;
  1175. }
  1176. else
  1177. {
  1178. if( bPreviousState == DIHES_UNKNOWN )
  1179. {
  1180. /*
  1181. * We've seen this device before and it was Unknown so
  1182. * don't expect that to change (as Setup does not retry
  1183. * the ID search through the INFs) so just use it.
  1184. */
  1185. fCreateOK = TRUE;
  1186. bNewState = DIHES_UNKNOWN;
  1187. }
  1188. else
  1189. {
  1190. if( lstrcmpi(phdi->ptszId, g_tszIdLastUnknown) == 0 )
  1191. {
  1192. if( GetTickCount() - g_tmLastUnknown < MSREBUILDRATE )
  1193. {
  1194. SquirtSqflPtszV(sqfl | sqflBenign,
  1195. TEXT("%hs: DIHid_BuildHidListEntry: %s pending on setup."),
  1196. s_szProc, phdi->ptszId );
  1197. fRc = FALSE;
  1198. }
  1199. else
  1200. {
  1201. /*
  1202. * Don't wait any longer but we'll need to update
  1203. * the state to "Unknown".
  1204. */
  1205. fCreateOK = TRUE;
  1206. bNewState = DIHES_UNKNOWN;
  1207. g_tszIdLastUnknown[0] = TEXT('0');
  1208. #ifdef XDEBUG
  1209. if( bPreviousState == DIHES_KNOWN )
  1210. {
  1211. SquirtSqflPtszV(sqfl | sqflBenign,
  1212. TEXT("%hs: %s was known but is now unknown!"),
  1213. s_szProc, phdi->ptszId );
  1214. }
  1215. #endif
  1216. }
  1217. }
  1218. else
  1219. {
  1220. lstrcpy( g_tszIdLastUnknown, phdi->ptszId );
  1221. g_tmLastUnknown = GetTickCount();
  1222. fRc = FALSE;
  1223. }
  1224. }
  1225. }
  1226. }
  1227. if( fCreateOK )
  1228. {
  1229. /*
  1230. * bNewState should always have been set if OK to create
  1231. */
  1232. AssertF( bNewState != DIHES_UNDEFINED );
  1233. /*
  1234. * Open the device so we can get its (real) usage page / usage.
  1235. */
  1236. hf = CreateFile(phdi->pdidd->DevicePath,
  1237. GENERIC_READ | GENERIC_WRITE,
  1238. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1239. 0, /* no SECURITY_ATTRIBUTES */
  1240. OPEN_EXISTING,
  1241. 0, /* attributes */
  1242. 0); /* template */
  1243. if(hf != INVALID_HANDLE_VALUE)
  1244. {
  1245. PHIDP_PREPARSED_DATA ppd;
  1246. HIDD_ATTRIBUTES attr;
  1247. if(HidD_GetPreparsedData(hf, &ppd))
  1248. {
  1249. HIDP_CAPS caps;
  1250. if( SUCCEEDED(HidP_GetCaps(ppd, &caps)) )
  1251. {
  1252. DIHid_ParseUsagePage(phdi, &caps, ppd);
  1253. SquirtSqflPtszV(sqfl,
  1254. TEXT("%hs: Have %s"),
  1255. s_szProc, phdi->pdidd->DevicePath);
  1256. /*
  1257. * ISSUE-2001/02/06-MarcAnd Incorrect return possible
  1258. * There's nothing to reset this to false if any of
  1259. * the following code fails.
  1260. */
  1261. fRc = TRUE;
  1262. }
  1263. else
  1264. {
  1265. SquirtSqflPtszV(sqfl | sqflError,
  1266. TEXT("%hs: HidP_GetCaps(%s) failed, le= %d"),
  1267. s_szProc, phdi->pdidd->DevicePath, GetLastError());
  1268. }
  1269. HidD_FreePreparsedData(ppd);
  1270. }
  1271. else
  1272. {
  1273. SquirtSqflPtszV(sqfl | sqflError,
  1274. TEXT("%hs: GetPreparsedData(%s) failed, le= %d"),
  1275. s_szProc, phdi->pdidd->DevicePath, GetLastError());
  1276. }
  1277. attr.Size = cbX(attr);
  1278. if( HidD_GetAttributes(hf, &attr) )
  1279. {
  1280. if( ( phdi->ProductID != attr.ProductID )
  1281. || ( phdi->VendorID != attr.VendorID ) )
  1282. {
  1283. SquirtSqflPtszV(sqfl | sqflBenign,
  1284. TEXT("%hs: Device changed from VID_%04X&PID_%04X to VID_%04X&PID_%04X"),
  1285. s_szProc, phdi->VendorID, phdi->ProductID, attr.VendorID, attr.ProductID );
  1286. phdi->ProductID = attr.ProductID;
  1287. phdi->VendorID = attr.VendorID;
  1288. /*
  1289. * Make sure we update the registry.
  1290. */
  1291. bPreviousState = DIHES_UNDEFINED;
  1292. }
  1293. if( bPreviousState != bNewState )
  1294. {
  1295. DIHid_CreateDeviceInstanceKeys( phdi, &bNewState );
  1296. }
  1297. }
  1298. else
  1299. {
  1300. SquirtSqflPtszV(sqfl | sqflError,
  1301. TEXT("%hs: HidD_GetAttributes(%s) failed"),
  1302. s_szProc, phdi->pdidd->DevicePath);
  1303. }
  1304. DICreateStaticGuid(&phdi->guidProduct, attr.ProductID, attr.VendorID);
  1305. CloseHandle(hf);
  1306. }
  1307. else
  1308. {
  1309. SquirtSqflPtszV(sqfl | sqflError,
  1310. TEXT("%hs: CreateFile(%s) failed? le=%d"),
  1311. s_szProc, phdi->pdidd->DevicePath, GetLastError());
  1312. }
  1313. }
  1314. #ifndef WINNT
  1315. /*
  1316. * The following part is to resolve the swap id problem in OSR.
  1317. * If a USB joystick is not in the lowest available id, after unplug and replug,
  1318. * VJOYD will assign the same joystick to the lowest available id, but DINPUT still
  1319. * remembers its last id. To resolve this conflict, we need this code.
  1320. */
  1321. {
  1322. VXDINITPARMS vip;
  1323. CHAR sz[MAX_PATH];
  1324. LPSTR pszPath;
  1325. BOOL fFindIt = FALSE;
  1326. for( phdi->idJoy = 0; phdi->idJoy < cJoyMax; phdi->idJoy++ )
  1327. {
  1328. pszPath = JoyReg_JoyIdToDeviceInterface_95(phdi->idJoy, &vip, sz);
  1329. if(pszPath)
  1330. {
  1331. if( lstrcmpiA(pszPath, (PCHAR)phdi->pdidd->DevicePath) == 0x0 ) {
  1332. fFindIt = TRUE;
  1333. break;
  1334. }
  1335. }
  1336. }
  1337. if( fFindIt )
  1338. {
  1339. if( phdi->hk != 0x0 )
  1340. {
  1341. /*
  1342. * Don't worry if the registry write fails
  1343. */
  1344. RegSetValueEx(phdi->hk, TEXT("Joystick Id"), 0, 0, (PV)&phdi->idJoy, cbX(phdi->idJoy) );
  1345. }
  1346. }
  1347. else
  1348. {
  1349. /*
  1350. * Post Dx7 Patch. Win9x only
  1351. * Some IHVs have created VJoyD mini drivers for their
  1352. * USB game controllers that are used instead of JoyHID.
  1353. * Since the interface to communicate hot-plugging with
  1354. * VJoyD has not been made public, these devices cannot
  1355. * be matched with a HID alias. To avoid both instances
  1356. * of the same device being enumerated, mark any HID
  1357. * game controller that does not have a VJoyD alias as
  1358. * a (unknown) device type.
  1359. *
  1360. * Post DX7a! Only do this for game controllers
  1361. */
  1362. if( GET_DIDEVICE_TYPE( phdi->osd.dwDevType ) >= DI8DEVTYPE_GAMEMIN )
  1363. {
  1364. /*
  1365. * Change type from joystick to device
  1366. */
  1367. phdi->osd.dwDevType &= ~(DIDEVTYPE_TYPEMASK | DIDEVTYPE_SUBTYPEMASK);
  1368. phdi->osd.dwDevType |= DI8DEVTYPE_DEVICE;
  1369. }
  1370. /*
  1371. * Set to the invalid id anyway
  1372. */
  1373. phdi->idJoy = -1;
  1374. }
  1375. }
  1376. #else
  1377. // Executed only on WINNT
  1378. if( phdi->hk != 0x0 )
  1379. {
  1380. DWORD cb;
  1381. cb = cbX(phdi->idJoy);
  1382. if( RegQueryValueEx(phdi->hk, TEXT("Joystick Id"),
  1383. 0, 0, (PV)&phdi->idJoy, &cb ) != ERROR_SUCCESS )
  1384. {
  1385. phdi->idJoy = JOY_BOGUSID;
  1386. }
  1387. }
  1388. #endif // WINNT
  1389. }
  1390. else
  1391. {
  1392. SquirtSqflPtszV(sqfl | sqflError,
  1393. TEXT("%hs: Unable to get GUID or device path"),
  1394. s_szProc);
  1395. }
  1396. /*
  1397. * If we failed, then free the goo we already got.
  1398. */
  1399. if(!fRc)
  1400. {
  1401. if( phdi->hk )
  1402. {
  1403. RegCloseKey(phdi->hk);
  1404. }
  1405. phdi->hk = 0;
  1406. FreePpv(&phdi->pdidd);
  1407. FreePpv(&phdi->ptszId);
  1408. }
  1409. ExitProcF(fRc);
  1410. return fRc;
  1411. }
  1412. #undef DIHES_UNDEFINED
  1413. #undef DIHES_UNKNOWN
  1414. #undef DIHES_KNOWN
  1415. /*****************************************************************************
  1416. *
  1417. * @doc INTERNAL
  1418. *
  1419. * @func void | DIHid_BuildHidListEntry |
  1420. *
  1421. * Builds a single entry in the list of HID devices.
  1422. *
  1423. * @parm HDEVINFO | hdev |
  1424. *
  1425. * Device list being enumerated.
  1426. *
  1427. * @parm PSP_DEVICE_INTERFACE_DATA | pdid |
  1428. *
  1429. * Describes the device that was enumerated.
  1430. *
  1431. * @returns
  1432. *
  1433. * Nonzero on success.
  1434. *
  1435. *****************************************************************************/
  1436. BOOL INTERNAL
  1437. DIHid_BuildHidListEntry(HDEVINFO hdev, PSP_DEVICE_INTERFACE_DATA pdid)
  1438. {
  1439. BOOL fRc = TRUE;
  1440. BOOL fAlreadyExist = FALSE;
  1441. PHIDDEVICEINFO phdi;
  1442. HIDDEVICEINFO hdi;
  1443. EnterProcI(DIHid_BuildHidListEntry, (_ "xp", hdev, pdid));
  1444. if(g_phdl)
  1445. {
  1446. PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd;
  1447. /* GetDevicePath is expecting a NULL */
  1448. pdidd = NULL;
  1449. if( DIHid_GetDevicePath(hdev, pdid, &pdidd, NULL) )
  1450. {
  1451. PHIDDEVICEINFO phdi;
  1452. int ihdi;
  1453. //Check whether the device has been in the list
  1454. for(ihdi = 0, phdi = g_phdl->rghdi;
  1455. ihdi < g_phdl->chdi;
  1456. ihdi++, phdi++)
  1457. {
  1458. if( phdi->pdidd )
  1459. {
  1460. if( lstrcmp( pdidd->DevicePath, phdi->pdidd->DevicePath ) == 0 )
  1461. {
  1462. //already in the list
  1463. fAlreadyExist = TRUE;
  1464. #ifdef WINNT
  1465. // Id may be changed, so refresh here.
  1466. // See Windows bug 321711. -qzheng
  1467. if( phdi->hk != 0x0 )
  1468. {
  1469. DWORD cb;
  1470. cb = cbX(phdi->idJoy);
  1471. if( RegQueryValueEx(phdi->hk, TEXT("Joystick Id"),
  1472. 0, 0, (PV)&phdi->idJoy, &cb ) != ERROR_SUCCESS )
  1473. {
  1474. phdi->idJoy = JOY_BOGUSID;
  1475. }
  1476. }
  1477. #endif
  1478. SquirtSqflPtszV(sqfl | sqflTrace,
  1479. TEXT("%hs: Device %s Already Exists in HID List "), s_szProc, pdidd->DevicePath);
  1480. break;
  1481. }
  1482. }
  1483. }
  1484. FreePpv(&pdidd);
  1485. }
  1486. else
  1487. {
  1488. SquirtSqflPtszV(sqfl | sqflError,
  1489. TEXT("%hs: DIHid_GetDevicePath failed"), s_szProc, pdidd->DevicePath);
  1490. }
  1491. if( fAlreadyExist )
  1492. {
  1493. //device is already there, needn't do anything, just leave
  1494. } else
  1495. {
  1496. PBUSDEVICEINFO pbdi;
  1497. if( g_phdl->chdi >= g_phdl->chdiAlloc )
  1498. {
  1499. /*
  1500. * Make sure there is room for this device in the list.
  1501. * Grow by doubling.
  1502. */
  1503. HRESULT hres;
  1504. /*
  1505. * Prefix warns that g_phdl would be NULL if the requested
  1506. * size is zero (mb:35353). Assert that it is never zero.
  1507. */
  1508. AssertF( cbHdlChdi(g_phdl->chdiAlloc * 2) );
  1509. hres = ReallocCbPpv(cbHdlChdi(g_phdl->chdiAlloc * 2), &g_phdl);
  1510. if(FAILED(hres))
  1511. {
  1512. SquirtSqflPtszV(sqfl | sqflError,
  1513. TEXT("%hs: Realloc failed"), s_szProc);
  1514. fRc = FALSE;
  1515. goto done;
  1516. }
  1517. g_phdl->chdiAlloc *= 2;
  1518. }
  1519. phdi = &g_phdl->rghdi[g_phdl->chdi];
  1520. memset( &hdi, 0, sizeof(hdi) );
  1521. if( DIHid_GetDevInfo(hdev, pdid, &hdi) )
  1522. {
  1523. hdi.fAttached = TRUE;
  1524. pbdi = pbdiFromphdi(&hdi);
  1525. if( pbdi != NULL )
  1526. {
  1527. /*
  1528. * If the devices is just being removed, and PnP is working on the
  1529. * removing, then we won't include it in our list.
  1530. */
  1531. if( lstrcmpi(pbdi->ptszId, g_tszIdLastRemoved) == 0 &&
  1532. GetTickCount() - g_tmLastRemoved < MSREBUILDRATE_FIFTH )
  1533. {
  1534. SquirtSqflPtszV(sqfl | sqflBenign,
  1535. TEXT("%hs: DIHid_BuildHidListEntry: %s pending on removal."),
  1536. s_szProc, pbdi->ptszId );
  1537. fRc = FALSE;
  1538. } else {
  1539. BUS_REGDATA RegData;
  1540. memcpy( phdi, &hdi, sizeof(hdi) );
  1541. g_phdl->chdi++;
  1542. if( SUCCEEDED(DIBusDevice_GetRegData(pbdi->hk, &RegData)) )
  1543. {
  1544. RegData.fAttachOnReboot = TRUE;
  1545. DIBusDevice_SetRegData(pbdi->hk, &RegData);
  1546. }
  1547. }
  1548. } else {
  1549. memcpy( phdi, &hdi, sizeof(hdi) );
  1550. g_phdl->chdi++;
  1551. }
  1552. }
  1553. else
  1554. {
  1555. SquirtSqflPtszV(sqfl | sqflBenign,
  1556. TEXT("%hs: DIHid_GetDevInfo failed, ignoring device"), s_szProc );
  1557. fRc = FALSE;
  1558. }
  1559. }
  1560. } // end of if(g_phdl)
  1561. done:
  1562. ExitProcF(fRc);
  1563. return fRc;
  1564. }
  1565. /*****************************************************************************
  1566. *
  1567. * @doc INTERNAL
  1568. *
  1569. * @func void | DIHid_BuildHidList |
  1570. *
  1571. * Builds the list of HID devices.
  1572. *
  1573. * @parm BOOL | fForce |
  1574. *
  1575. * If nonzero, we force a rebuild of the HID list.
  1576. * Otherwise, we rebuild only if the list hasn't
  1577. * been rebuilt recently.
  1578. *
  1579. *****************************************************************************/
  1580. void EXTERNAL
  1581. DIHid_BuildHidList(BOOL fForce)
  1582. {
  1583. HRESULT hres;
  1584. DWORD dwTick;
  1585. EnterProcI(DIHid_BuildHidList, (_ "u", fForce));
  1586. DllEnterCrit();
  1587. // Force implies a complete rebuild of the list
  1588. // No hanging onto old entries.
  1589. if( fForce )
  1590. {
  1591. DIHid_EmptyHidList();
  1592. }
  1593. //ISSUE-2001/03/29-timgill Meltdown code change may be unnecessary
  1594. dwTick = GetTickCount();
  1595. if(!(g_flEmulation & 0x80000000) && /* Not disabled by emulation */
  1596. HidD_GetHidGuid && /* HID actually exists */
  1597. (fForce || /* Forcing rebuild, or */
  1598. g_tmLastHIDRebuild == 0 || /* Never built before, or */
  1599. dwTick - g_tmLastHIDRebuild > MSREBUILDRATE /* Haven't built for a while */
  1600. #ifdef WINNT
  1601. || dwTick - Excl_GetConfigChangedTime() < MSREBUILDRATE /* joyConfig just Changed */
  1602. #endif
  1603. ))
  1604. {
  1605. GUID guidHid;
  1606. HDEVINFO hdev;
  1607. HidD_GetHidGuid(&guidHid);
  1608. hdev = SetupDiGetClassDevs(&guidHid, 0, 0,
  1609. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  1610. if(hdev != INVALID_HANDLE_VALUE)
  1611. {
  1612. DIHid_CheckHidList();
  1613. /*
  1614. * There is no way to query the number of devices.
  1615. * You just have to keep incrementing until you run out.
  1616. *
  1617. * If we already have a g_phdl, then re-use it. Else, create
  1618. * a new one. But always realloc up to the minimum starting
  1619. * point. (This upward realloc is important in case there
  1620. * were no HID devices the last time we checked.)
  1621. */
  1622. if( !g_phdl )
  1623. {
  1624. hres = AllocCbPpv(cbHdlChdi(chdiInit), &g_phdl);
  1625. if(SUCCEEDED(hres))
  1626. {
  1627. g_phdl->chdi = 0;
  1628. g_phdl->chdiAlloc = chdiInit;
  1629. } else
  1630. {
  1631. /* Skip erroneous items */
  1632. SquirtSqflPtszV(sqfl | sqflError,
  1633. TEXT("DIHid_BuildHidListEntry ")
  1634. TEXT("Realloc g_phdl fails."));
  1635. }
  1636. } else
  1637. {
  1638. hres = S_OK;
  1639. }
  1640. if(SUCCEEDED(hres))
  1641. {
  1642. int idev;
  1643. /*
  1644. * To avoid infinite looping on
  1645. * internal *boo-boo's*, break on any
  1646. * error once we have tried more than
  1647. * chdiMax devices, since that's the most
  1648. * HID will ever give us.
  1649. */
  1650. for(idev = 0; idev < chdiMax; idev++)
  1651. {
  1652. SP_DEVICE_INTERFACE_DATA did;
  1653. AssertF(g_phdl->chdi <= g_phdl->chdiAlloc);
  1654. /*
  1655. * SetupDI requires that the caller initialize cbSize.
  1656. */
  1657. did.cbSize = cbX(did);
  1658. if(SetupDiEnumDeviceInterfaces(hdev, 0, &guidHid,
  1659. idev, &did))
  1660. {
  1661. if(!DIHid_BuildHidListEntry(hdev, &did))
  1662. {
  1663. /* Skip erroneous items */
  1664. SquirtSqflPtszV(sqfl | sqflError,
  1665. TEXT("DIHid_BuildHidListEntry ")
  1666. TEXT("failed?"));
  1667. }
  1668. }
  1669. else if(GetLastError() == ERROR_NO_MORE_ITEMS)
  1670. {
  1671. break;
  1672. }
  1673. else
  1674. {
  1675. /* Skip erroneous items */
  1676. SquirtSqflPtszV(sqfl | sqflError,
  1677. TEXT("SetupDiEnumDeviceInterface ")
  1678. TEXT("failed? le=%d"), GetLastError());
  1679. }
  1680. }
  1681. }
  1682. SetupDiDestroyDeviceInfoList(hdev);
  1683. }
  1684. else
  1685. {
  1686. SquirtSqflPtszV(sqfl | sqflError,
  1687. TEXT("SetupDiGetClassDevs failed le=%d"), GetLastError());
  1688. }
  1689. #ifdef WINNT
  1690. if( g_phdl && g_phdl->chdi )
  1691. {
  1692. DIWdm_InitJoyId();
  1693. }
  1694. #endif
  1695. g_tmLastHIDRebuild = GetTickCount();
  1696. }
  1697. DllLeaveCrit();
  1698. ExitProc();
  1699. }
  1700. DWORD DIHid_DetectHideAndRevealFlags( PCHID this )
  1701. {
  1702. // Get hold of the Devices Parent
  1703. // If the Parent a HID device that we know about ?
  1704. // If the parent is a gaming device ( joystick / gamepad, etc )
  1705. // Mark the device as being "fictional"
  1706. DWORD dwFlags2 = 0x0;
  1707. HDEVINFO hdev;
  1708. // We only detect and hide mice and keyboard,
  1709. // For now, there is no reason to hide other HID devices.
  1710. // Futhermore the scheme to detect which devices to hide is based
  1711. // on MSHs filter driver implementation where they eject PDOs for
  1712. // "fictional" devices. These fictional devices show up as childern of
  1713. // gaming devices. FredBh (HID/PM) informs us that most multi-function devices he
  1714. // has seen (mice and kbd) have had multiple top level collections.
  1715. AssertF( ( GET_DIDEVICE_TYPE( this->dwDevType ) == DI8DEVTYPE_MOUSE )
  1716. || ( GET_DIDEVICE_TYPE( this->dwDevType ) == DI8DEVTYPE_KEYBOARD ) );
  1717. hdev = SetupDiCreateDeviceInfoList(NULL, NULL);
  1718. if (hdev != INVALID_HANDLE_VALUE)
  1719. {
  1720. SP_DEVINFO_DATA dinf;
  1721. dinf.cbSize = cbX(SP_DEVINFO_DATA);
  1722. if (SetupDiOpenDeviceInfo(hdev, this->ptszId, NULL, 0, &dinf))
  1723. {
  1724. DEVINST DevInst;
  1725. if ( (CM_Get_Parent(&DevInst, dinf.DevInst, 0x0)) == CR_SUCCESS )
  1726. {
  1727. TCHAR tszId[MAX_PATH];
  1728. if ( CR_SUCCESS == CM_Get_Device_ID(DevInst, tszId, MAX_PATH, 0x0 ))
  1729. {
  1730. PHIDDEVICEINFO phdi;
  1731. DllEnterCrit();
  1732. phdi = phdiFindHIDDeviceId(tszId);
  1733. if ( phdi )
  1734. {
  1735. DWORD dwDevType = phdi->osd.dwDevType;
  1736. // If the device is a HID gaming device (in the broadest definition)
  1737. if ( ( GET_DIDEVICE_TYPE(dwDevType) >= DI8DEVTYPE_GAMEMIN )
  1738. && ( dwDevType & DIDEVTYPE_HID ) )
  1739. {
  1740. dwFlags2 = JOYTYPE_HIDEACTIVE;
  1741. switch (GET_DIDEVICE_TYPE( this->dwDevType ))
  1742. {
  1743. case DI8DEVTYPE_MOUSE:
  1744. dwFlags2 |= JOYTYPE_MOUSEHIDE;
  1745. break;
  1746. case DI8DEVTYPE_KEYBOARD:
  1747. dwFlags2 |= JOYTYPE_KEYBHIDE;
  1748. break;
  1749. default:
  1750. AssertF(0);
  1751. }
  1752. }
  1753. }
  1754. DllLeaveCrit();
  1755. }
  1756. }
  1757. }
  1758. SetupDiDestroyDeviceInfoList(hdev);
  1759. }
  1760. return dwFlags2;
  1761. }