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.

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