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.

1111 lines
33 KiB

  1. /*****************************************************************************
  2. *
  3. * DIWdm.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * WINNT specific functions.
  10. *
  11. * Contents:
  12. *
  13. * hResIdJoyInstanceGUID
  14. * DIWdm_SetLegacyConfig
  15. * DIWdm_InitJoyId
  16. *
  17. *****************************************************************************/
  18. #include "dinputpr.h"
  19. /*****************************************************************************
  20. *
  21. * The sqiffle for this file.
  22. *
  23. *****************************************************************************/
  24. #define sqfl sqflWDM
  25. /*****************************************************************************
  26. *
  27. * @doc INTERNAL
  28. *
  29. * @func HRESULT | DIWdm_SetJoyId |
  30. * Given a guid for a HID device and a Joystick ID.
  31. * This function will swap the old joystick ID for the device
  32. * specified by the guid ( pcguid ) for the new ID specified in
  33. * idJoy
  34. *
  35. * @parm IN UINT | idJoy |
  36. *
  37. * The Joyid the the HID device specified by pcguid should have.
  38. *
  39. * @parm OUT LPGUID | pcguid |
  40. *
  41. * GUID that specifies a HID device.
  42. *
  43. * @returns
  44. * HRESULT
  45. *
  46. *****************************************************************************/
  47. HRESULT EXTERNAL
  48. DIWdm_SetJoyId
  49. (
  50. IN PCGUID pcguid,
  51. IN int idJoy
  52. )
  53. {
  54. PHIDDEVICEINFO phdi;
  55. HRESULT hres;
  56. BOOL fConfigChanged = FALSE;
  57. EnterProcI(DIWdm_SetJoyId, (_"Gu", pcguid, idJoy));
  58. //PostDx7 patch:
  59. // No point setting the joystick entries in the registry
  60. // if the ID of the joystick is -1.
  61. if( idJoy == -1 )
  62. {
  63. return E_FAIL;
  64. }
  65. DllEnterCrit();
  66. hres = S_OK;
  67. /* Get pointer to HIDDEVICEINFO from the GUID */
  68. phdi = phdiFindHIDInstanceGUID(pcguid);
  69. if(phdi != NULL )
  70. {
  71. PHIDDEVICEINFO phdiSwap = NULL;
  72. GUID guidInstanceOld;
  73. LONG lRc;
  74. int idJoySwap;
  75. /* Swap the ID's */
  76. idJoySwap = phdi->idJoy;
  77. phdi->idJoy = idJoy;
  78. phdiSwap = NULL;
  79. /* Get the GUID for the old ID */
  80. if( SUCCEEDED( hres = hResIdJoypInstanceGUID_WDM(idJoySwap, &guidInstanceOld)) )
  81. {
  82. /* Get pointer to HIDDEVICEINFO for old ID */
  83. phdiSwap = phdiFindHIDInstanceGUID(&guidInstanceOld);
  84. if( phdiSwap )
  85. {
  86. phdiSwap->idJoy = idJoySwap;
  87. } else
  88. {
  89. // Old device disappeared !
  90. }
  91. } else
  92. {
  93. DIJOYCONFIG c_djcReset = {
  94. cbX(c_djcReset), /* dwSize */
  95. { 0}, /* guidInstance */
  96. { 0}, /* hwc */
  97. DI_FFNOMINALMAX, /* dwGain */
  98. { 0}, /* wszType */
  99. { 0}, /* wszCallout */
  100. };
  101. hres = JoyReg_SetConfig(idJoySwap, &c_djcReset.hwc,&c_djcReset, DIJC_SETVALID) ;
  102. if( FAILED(hres) )
  103. {
  104. SquirtSqflPtszV(sqfl | sqflError,
  105. TEXT("%S: JoyReg_SetConfig to NULL FAILED "),
  106. s_szProc );
  107. }
  108. }
  109. /* Set the new ID and LegacyConfig */
  110. if( phdi )
  111. {
  112. if( lRc = RegSetValueEx(phdi->hk, TEXT("Joystick Id"), 0, REG_BINARY,
  113. (PV)&idJoy, cbX(idJoy)) == ERROR_SUCCESS )
  114. {
  115. /*
  116. * This extra RegSetValueEx on "Joystick Id" is to keep the
  117. * compatibility with Win2k Gold.
  118. * See Windows bug 395416 for detail.
  119. */
  120. RegSetValueEx(phdi->hkOld, TEXT("Joystick Id"), 0, REG_BINARY,
  121. (PV)&idJoy, cbX(idJoy));
  122. if( SUCCEEDED( hres = DIWdm_SetLegacyConfig(idJoy)) )
  123. {
  124. fConfigChanged = TRUE;
  125. }
  126. }
  127. }
  128. /* Set old ID and legacy Config */
  129. if( (phdiSwap != NULL) && (phdiSwap != phdi) )
  130. {
  131. if( lRc = RegSetValueEx(phdiSwap->hk, TEXT("Joystick Id"), 0, REG_BINARY,
  132. (PV)&idJoySwap, cbX(idJoySwap)) == ERROR_SUCCESS )
  133. {
  134. /*
  135. * This extra RegSetValueEx on "Joystick Id" is to keep the
  136. * compatibility with Win2k Gold.
  137. * See Windows bug 395416 for detail.
  138. */
  139. RegSetValueEx(phdiSwap->hkOld, TEXT("Joystick Id"), 0, REG_BINARY,
  140. (PV)&idJoySwap, cbX(idJoySwap));
  141. if( SUCCEEDED( hres = DIWdm_SetLegacyConfig(idJoySwap) ) )
  142. {
  143. fConfigChanged = TRUE;
  144. }
  145. }
  146. } else if( phdiSwap == NULL )
  147. {
  148. // Old Device disappeared !
  149. if( SUCCEEDED( hres = DIWdm_SetLegacyConfig(idJoySwap) ) )
  150. {
  151. fConfigChanged = TRUE;
  152. }
  153. }
  154. } else
  155. {
  156. hres = E_FAIL;
  157. RPF("ERROR %s: invalid guid.", s_szProc);
  158. }
  159. #ifndef WINNT
  160. if( SUCCEEDED(hres) )
  161. {
  162. /*
  163. * Make sure the new Ids do not cause any collisions
  164. */
  165. DIWdm_InitJoyId();
  166. }
  167. #endif
  168. if( fConfigChanged ) {
  169. #ifdef WINNT
  170. Excl_SetConfigChangedTime( GetTickCount() );
  171. PostMessage(HWND_BROADCAST, g_wmJoyChanged, 0, 0L);
  172. #else
  173. joyConfigChanged(0);
  174. #endif
  175. }
  176. DllLeaveCrit();
  177. ExitOleProc();
  178. return hres;
  179. }
  180. /*****************************************************************************
  181. *
  182. * @doc EXTERNAL
  183. *
  184. * @func HRESULT | hResIdJoyInstanceGUID_WDM |
  185. *
  186. * Maps a HID JoyStick ID to a DeviceInstance GUID
  187. *
  188. * The parameters have already been validated.
  189. *
  190. *
  191. * @parm IN UINT | idJoy |
  192. *
  193. * The Joyid of the HID device to be located.
  194. *
  195. * @parm OUT LPGUID | lpguid |
  196. *
  197. * The Device Instance GUID corresponding to the JoystickID
  198. * If a mapping is not found GUID_NULL is passed back in lpguid
  199. *
  200. * @returns
  201. * HRESULT
  202. *
  203. *****************************************************************************/
  204. HRESULT EXTERNAL hResIdJoypInstanceGUID_WDM
  205. (
  206. IN UINT idJoy,
  207. OUT LPGUID lpguid
  208. )
  209. {
  210. HRESULT hres = DIERR_NOTFOUND;
  211. EnterProc( hResIdJoypInstanceGUID_WDM, ( _ "ux", idJoy, lpguid) );
  212. /* Zap the guid for failure case */
  213. ZeroBuf(lpguid, cbX(*lpguid) );
  214. if( idJoy > cJoyMax )
  215. {
  216. hres = DIERR_NOMOREITEMS;
  217. } else
  218. {
  219. DllEnterCrit();
  220. /* Build the HID list if it is too old */
  221. DIHid_BuildHidList(FALSE);
  222. /* Make sure there is some HID device */
  223. if(g_phdl)
  224. {
  225. int ihdi;
  226. PHIDDEVICEINFO phdi;
  227. /* Search over all HID devices */
  228. for(ihdi = 0, phdi = g_phdl->rghdi;
  229. ihdi < g_phdl->chdi;
  230. ihdi++, phdi++)
  231. {
  232. /* Check for matching ID */
  233. if(idJoy == (UINT)phdi->idJoy)
  234. {
  235. hres = S_OK;
  236. /* Copy the GUID */
  237. *lpguid = phdi->guid;
  238. break;
  239. }
  240. }
  241. }
  242. DllLeaveCrit();
  243. }
  244. ExitBenignOleProc();
  245. return hres;
  246. }
  247. /*****************************************************************************
  248. *
  249. * @doc INTERNAL
  250. *
  251. * @func PHIDDEVICEINFO | phdiFindJoyId |
  252. *
  253. * Locates information given a joystick ID for a HID device.
  254. *
  255. * The parameters have already been validated.
  256. *
  257. * The DLL critical must be held across the call; once the
  258. * critical section is released, the returned pointer becomes
  259. * invalid.
  260. *
  261. * @parm IN int | idJoy |
  262. *
  263. * The Id of the joystick to be located.
  264. *
  265. * @returns
  266. *
  267. * Pointer to the <t HIDDEVICEINFO> that describes
  268. * the device.
  269. *
  270. *****************************************************************************/
  271. PHIDDEVICEINFO EXTERNAL
  272. phdiFindJoyId(int idJoy )
  273. {
  274. PHIDDEVICEINFO phdi;
  275. EnterProcI(phdiFindJoyId, (_"u", idJoy));
  276. /* We should have atleast one HID device */
  277. if(g_phdl)
  278. {
  279. int ihdi;
  280. /* Loop over all HID devices */
  281. for(ihdi = 0, phdi = g_phdl->rghdi; ihdi < g_phdl->chdi;
  282. ihdi++, phdi++)
  283. {
  284. /* Match */
  285. if(idJoy == phdi->idJoy)
  286. {
  287. goto done;
  288. }
  289. }
  290. }
  291. phdi = 0;
  292. done:;
  293. ExitProcX((UINT_PTR)phdi);
  294. return phdi;
  295. }
  296. /*****************************************************************************
  297. *
  298. * @doc INTERNAL
  299. *
  300. * @func HRESULT | DIWdm_SetLegacyConfig |
  301. *
  302. * Sets up the registry keys so that a joystick HID device
  303. * can be "seen" by legacy APIs and the Control Panel.
  304. * Primarily, this routine sets up the structs that are passed
  305. * to JoyReg_SetConfig routine.
  306. *
  307. * @parm IN int | idJoy |
  308. *
  309. * Joystick ID.
  310. *
  311. * @returns HRESULT
  312. *
  313. *****************************************************************************/
  314. //ISSUE-2001/03/29-timgill Fix unicode madness
  315. HRESULT INTERNAL DIWdm_SetLegacyConfig
  316. (
  317. IN int idJoy
  318. )
  319. {
  320. HRESULT hres;
  321. DIJOYCONFIG cfg;
  322. BOOL fNeedType;
  323. BOOL fNeedConfig;
  324. BOOL fNeedNone;
  325. HKEY hk;
  326. DIJOYTYPEINFO dijti;
  327. PHIDDEVICEINFO phdi;
  328. WCHAR wszType[cA(VID_PID_TEMPLATE)];
  329. #ifndef UNICODE
  330. char szType[cbX(VID_PID_TEMPLATE)];
  331. #endif
  332. EnterProcI(DIWdm_SetLegacyConfig, (_ "u", idJoy));
  333. if( idJoy == -1 )
  334. {
  335. // Dx7Gold Patch:
  336. // ID == -1 implies this device is not joystick.
  337. // Do not write any entries to the registry
  338. return E_FAIL;
  339. }
  340. ZeroX(dijti);
  341. dijti.dwSize = cbX(dijti);
  342. fNeedType = fNeedConfig = TRUE;
  343. fNeedNone = FALSE;
  344. /*
  345. * 1. Find out what the WinMM registry data is saying now
  346. */
  347. CAssertF( JOY_HW_NONE == 0 );
  348. hres = JoyReg_OpenConfigKey(idJoy, KEY_QUERY_VALUE, 0x0, &hk);
  349. if( SUCCEEDED(hres) )
  350. {
  351. /* Get the type name from the registry */
  352. JoyReg_GetConfigValue(
  353. hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ,
  354. &cfg.wszType, cbX(cfg.wszType) );
  355. hres = JoyReg_GetConfigValue(
  356. hk, REGSTR_VAL_JOYNCONFIG, idJoy, REG_BINARY,
  357. &cfg.hwc, cbX(cfg.hwc) );
  358. RegCloseKey(hk);
  359. } else
  360. {
  361. cfg.wszType[0] = '\0';
  362. }
  363. if( FAILED( hres ) )
  364. {
  365. cfg.hwc.dwType = JOY_HW_NONE;
  366. }
  367. /*
  368. * 2. If the config info is in sync with WDM then don't rewrite
  369. */
  370. phdi = phdiFindJoyId(idJoy);
  371. if( phdi )
  372. {
  373. /*
  374. * The type key for HID devices is "VID_xxxx&PID_yyyy",
  375. * mirroring the format used by plug and play.
  376. */
  377. if( ( LOWORD(phdi->guidProduct.Data1) == MSFT_SYSTEM_VID )
  378. &&( ( HIWORD(phdi->guidProduct.Data1) >= MSFT_SYSTEM_PID + JOY_HW_PREDEFMIN )
  379. &&( HIWORD(phdi->guidProduct.Data1) < MSFT_SYSTEM_PID + JOY_HW_PREDEFMAX ) ) )
  380. {
  381. /* Predefined type definitions don't go into the registry */
  382. fNeedType = FALSE;
  383. /*
  384. * Predefined types are determined by the dwType value so fix
  385. * only it if that is wrong.
  386. */
  387. if( cfg.hwc.dwType + MSFT_SYSTEM_PID == HIWORD(phdi->guidProduct.Data1) )
  388. {
  389. fNeedConfig = FALSE;
  390. } else
  391. {
  392. /*
  393. * Get type info so that JOY_HWS_* flags start with correct values.
  394. */
  395. wszType[0] = L'#';
  396. wszType[1] = L'0' + HIWORD(phdi->guidProduct.Data1) - MSFT_SYSTEM_PID;
  397. wszType[2] = L'\0';
  398. JoyReg_GetPredefTypeInfo(wszType, &dijti, DITC_INREGISTRY | DITC_DISPLAYNAME);
  399. }
  400. } else
  401. {
  402. /*
  403. * This should work, but it doesn't in Win98.
  404. *
  405. * ctch = wsprintfW(wszType, L"VID_%04X&PID_%04X",
  406. * LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
  407. */
  408. #ifdef UNICODE
  409. wsprintfW(wszType, VID_PID_TEMPLATE,
  410. LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
  411. CharUpperW(wszType);
  412. #else
  413. wsprintf(szType, VID_PID_TEMPLATE,
  414. LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
  415. CharUpper( szType );
  416. AToU( wszType, cA(wszType), szType );
  417. #endif
  418. }
  419. } else
  420. {
  421. /*
  422. * There is no WDM device so flag for deletion if the WinMM data is wrong
  423. */
  424. if( ( cfg.hwc.dwType != JOY_HW_NONE ) || ( cfg.wszType[0] != L'\0' ) )
  425. {
  426. fNeedNone = TRUE;
  427. fNeedType = fNeedConfig = FALSE;
  428. }
  429. }
  430. if( fNeedType ) /* Not already decided against (predefined type) */
  431. {
  432. /* Does the registry have the correct device ? */
  433. /*
  434. * lstrcmpW doesn't work in Win9x, bad. We have to use our own DiChauUpperW,
  435. * then memcmp. Also, the wsprintf template has to use 'X' not 'x'.
  436. */
  437. DiCharUpperW(cfg.wszType);
  438. if( (memcmp(cfg.wszType, wszType, cbX(wszType)) == 0x0)
  439. && (cfg.hwc.dwType >= JOY_HW_PREDEFMAX) )
  440. {
  441. fNeedConfig = FALSE;
  442. }
  443. /* Check the type key */
  444. hres = JoyReg_GetTypeInfo(wszType, &dijti, DITC_INREGISTRY);
  445. if( SUCCEEDED(hres) )
  446. {
  447. fNeedType = FALSE;
  448. }
  449. }
  450. /*
  451. * No failures up to this point should be returned
  452. */
  453. hres = S_OK;
  454. /*
  455. * 3. If something is missing, find the data from WDM and set it straight
  456. */
  457. if( fNeedType || fNeedConfig )
  458. {
  459. if( fNeedConfig ) {
  460. ZeroX(cfg);
  461. cfg.dwSize = cbX(cfg);
  462. hres = DIWdm_JoyHidMapping(idJoy, NULL, &cfg, &dijti );
  463. } else {
  464. hres = DIWdm_JoyHidMapping(idJoy, NULL, NULL, &dijti );
  465. }
  466. if( SUCCEEDED(hres) )
  467. {
  468. if( fNeedType == TRUE)
  469. {
  470. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  471. REGSTR_PATH_JOYOEM,
  472. DI_KEY_ALL_ACCESS,
  473. REG_OPTION_NON_VOLATILE,
  474. &hk);
  475. if( SUCCEEDED(hres) )
  476. {
  477. hres = JoyReg_SetTypeInfo(hk,
  478. cfg.wszType,
  479. &dijti,
  480. DITC_REGHWSETTINGS | DITC_DISPLAYNAME | DITC_HARDWAREID );
  481. if( SUCCEEDED(hres ) )
  482. {
  483. } else // SetTypeinfo FAILED
  484. SquirtSqflPtszV(sqfl | sqflError,
  485. TEXT("%S: JoyReg_SetTypeInfo FAILED "),
  486. s_szProc );
  487. RegCloseKey(hk);
  488. } else // SetTypeinfo FAILED
  489. SquirtSqflPtszV(sqfl | sqflError,
  490. TEXT("%S: JoyReg_OpenTypeKey FAILED "),
  491. s_szProc );
  492. }
  493. if( fNeedConfig )
  494. {
  495. hres = JoyReg_SetConfig(idJoy,
  496. &cfg.hwc,
  497. &cfg,
  498. DIJC_INREGISTRY);
  499. if( SUCCEEDED(hres) )
  500. {
  501. #ifdef WINNT
  502. Excl_SetConfigChangedTime( GetTickCount() );
  503. PostMessage (HWND_BROADCAST, g_wmJoyChanged, idJoy+1, 0L);
  504. #else
  505. joyConfigChanged(0);
  506. #endif
  507. } else
  508. {
  509. SquirtSqflPtszV(sqfl | sqflError,
  510. TEXT(",JoyReg_SetConfig FAILED hres=%d"),
  511. hres);
  512. }
  513. }
  514. } else // DIWdm_GetJoyHidMapping FAILED
  515. {
  516. fNeedNone = TRUE;
  517. }
  518. }
  519. /*
  520. * 4. If WinMM has data for a device that WDM does not, delete it
  521. */
  522. if( fNeedNone )
  523. {
  524. ZeroX( cfg );
  525. cfg.dwSize = cbX( cfg );
  526. cfg.dwGain = DI_FFNOMINALMAX;
  527. if(SUCCEEDED(hres = JoyReg_SetConfig(idJoy, &cfg.hwc,
  528. &cfg, DIJC_SETVALID)) &&
  529. SUCCEEDED(hres = JoyReg_OpenConfigKey(idJoy, MAXIMUM_ALLOWED,
  530. REG_OPTION_VOLATILE, &hk)))
  531. {
  532. TCHAR tsz[MAX_JOYSTRING];
  533. wsprintf(tsz, TEXT("%u"), idJoy + 1);
  534. #ifdef WINNT
  535. DIWinnt_RegDeleteKey(hk, tsz);
  536. #else
  537. RegDeleteKey(hk, tsz);
  538. #endif
  539. RegCloseKey(hk);
  540. hres = S_OK;
  541. }
  542. }
  543. ExitProcX(hres);
  544. return hres;
  545. }
  546. /*****************************************************************************
  547. *
  548. * @doc INTERNAL
  549. *
  550. * @func void | DIWdm_InitJoyId |
  551. *
  552. * Initializes Joystick IDs for JoyConfig and legacy APIs
  553. * Store the joystick IDs the registry under the %%DirectX/JOYID key.
  554. *
  555. *****************************************************************************/
  556. BOOL EXTERNAL
  557. DIWdm_InitJoyId( void )
  558. {
  559. BOOL fRc;
  560. LONG lRc;
  561. int ihdi;
  562. int idJoy;
  563. BOOL fNeedId;
  564. BOOL rfJoyId[cJoyMax]; /* Bool Array for to determine which IDs are in use */
  565. PHIDDEVICEINFO phdi;
  566. HRESULT hres = E_FAIL;
  567. EnterProcI(DIWdm_InitJoyId, (_ ""));
  568. DllEnterCrit();
  569. fRc = TRUE;
  570. ZeroX(rfJoyId );
  571. fNeedId = FALSE;
  572. /* Iterate over all HID devices to find used IDs */
  573. for( ihdi = 0, phdi = g_phdl->rghdi ;
  574. (g_phdl != NULL) && (phdi != NULL) && (phdi->fAttached) && (ihdi < g_phdl->chdi) ;
  575. ihdi++, phdi++ )
  576. {
  577. /* We need joyIDs only for HID game controller devices */
  578. if( ( GET_DIDEVICE_TYPE( phdi->osd.dwDevType ) >= DI8DEVTYPE_GAMEMIN )
  579. && ( phdi->osd.dwDevType & DIDEVTYPE_HID ) )
  580. {
  581. idJoy = phdi->idJoy ;
  582. /* Validate the ID. */
  583. if( idJoy < cJoyMax && rfJoyId[idJoy] != TRUE )
  584. {
  585. rfJoyId[idJoy] = TRUE;
  586. hres = DIWdm_SetLegacyConfig(idJoy);
  587. if( FAILED ( hres ) )
  588. {
  589. fRc = FALSE;
  590. SquirtSqflPtszV(sqfl | sqflError,
  591. TEXT("%S: DIWdm_SetLegacyConfig() FAILED ")
  592. TEXT("idJoy=%d FAILED hres = %d"),
  593. s_szProc, idJoy, hres );
  594. }
  595. } else
  596. {
  597. /* ID either over the limit OR is already used */
  598. phdi->idJoy = JOY_BOGUSID;
  599. fNeedId = TRUE;
  600. }
  601. }
  602. }
  603. /* Are there devices that need an ID */
  604. if( fNeedId )
  605. {
  606. /*
  607. * We have Examined all Joystick Ids found used IDs
  608. * and determined some device needs an Id
  609. */
  610. /* Iterate to assign unused Id's */
  611. for( ihdi = 0, phdi = g_phdl->rghdi;
  612. ihdi < g_phdl->chdi ;
  613. ihdi++, phdi++ )
  614. {
  615. /* We need joyIDs only for HID game controller devices */
  616. if( ( GET_DIDEVICE_TYPE( phdi->osd.dwDevType ) >= DI8DEVTYPE_GAMEMIN )
  617. && ( phdi->osd.dwDevType & DIDEVTYPE_HID ) )
  618. {
  619. idJoy = phdi->idJoy;
  620. if( idJoy == JOY_BOGUSID )
  621. {
  622. /* Get an Unused ID */
  623. for(idJoy = 0x0;
  624. idJoy < cJoyMax;
  625. idJoy++ )
  626. {
  627. if( rfJoyId[idJoy] == FALSE )
  628. break;
  629. }
  630. if( idJoy < cJoyMax )
  631. {
  632. rfJoyId[idJoy] = TRUE;
  633. phdi->idJoy = idJoy;
  634. if( lRc = RegSetValueEx(phdi->hk, TEXT("Joystick Id"), 0, REG_BINARY,
  635. (PV)&idJoy, cbX(idJoy)) == ERROR_SUCCESS )
  636. {
  637. /*
  638. * This extra RegSetValueEx on "Joystick Id" is to keep the
  639. * compatibility with Win2k Gold.
  640. * See Windows bug 395416 for detail.
  641. */
  642. RegSetValueEx(phdi->hkOld, TEXT("Joystick Id"), 0, REG_BINARY,
  643. (PV)&idJoy, cbX(idJoy));
  644. /* Setup Registry data for legacy API's */
  645. hres = DIWdm_SetLegacyConfig(idJoy);
  646. if( FAILED ( hres ) )
  647. {
  648. fRc = FALSE;
  649. SquirtSqflPtszV(sqfl | sqflError,
  650. TEXT("%S: DIWdm_SetLegacyConfig() FAILED")
  651. TEXT(" idJoy=%d hres = %d"),
  652. s_szProc, idJoy, hres );
  653. }
  654. } else
  655. {
  656. SquirtSqflPtszV(sqfl | sqflError,
  657. TEXT("%S: RegSetValueEx(JOYID) FAILED ")
  658. TEXT("Error = %d"),
  659. s_szProc, lRc);
  660. fRc = FALSE;
  661. }
  662. }
  663. }
  664. }
  665. }
  666. }
  667. DllLeaveCrit();
  668. ExitBenignProcF(fRc);
  669. return fRc;
  670. }
  671. /*****************************************************************************
  672. *
  673. * @doc EXTERNAL
  674. *
  675. * @func HRESULT | DIWdm_SetConfig |
  676. *
  677. * Sets config for analog joysticks. This function is an
  678. * extention of the JoyCfg_SetConfig function for NT.
  679. * It associates a gameport/serialport bus with a legacy (HID) device and
  680. * sends an IOCTL to the gameport/serialport bus to attach the device.
  681. * The IOCLT takes the hardware ID[] which is got from
  682. * the Joystick OEM types entry
  683. * (HKLM\CurrentControlSet\Control\Media\PrivateProperties\Joystick\OEM)
  684. * Some time later PnP realizes that a new device has been added, and hunts for
  685. * an inf file that matches the HardwareId.
  686. *
  687. * When the new HID device finally shows up, we look for the gameport/serialport that
  688. * the HID device is associated with and try to give it the requested idJoy.
  689. *
  690. *
  691. * @parm IN UINT | idJoy |
  692. *
  693. * ID of Joystick
  694. *
  695. * @parm IN LPJOYREGHWCONFIG | pjwc |
  696. *
  697. * Address of JOYREGHWCONFIG structure that contains config info for the joystick
  698. *
  699. * @parm IN LPCDIJOYCONFIG | pcfg |
  700. *
  701. * Address of DIJOYCONFIG structure that contains config info for the joystick
  702. *
  703. * @parm IN DWORD | fl |
  704. *
  705. * Flags
  706. *
  707. * @returns
  708. *
  709. * DIERR_INVALIDPARAM This function needs DX6.1a functionality.
  710. * DIERR_UNSUPPORTED Autoload devices cannot be added through this API.
  711. * DIERR_NOTFOUND TypeInfo not found in the registry.
  712. * E_ACCESSDENIED Gameport is configured to use another device.
  713. * E_FAIL CreateFile on Gameport device failed.
  714. * Could not send IOCTL to gameport device.
  715. *
  716. *****************************************************************************/
  717. HRESULT EXTERNAL
  718. DIWdm_SetConfig
  719. (
  720. IN UINT idJoy,
  721. IN LPJOYREGHWCONFIG pjwc,
  722. IN LPCDIJOYCONFIG pcfg,
  723. IN DWORD fl
  724. )
  725. {
  726. HRESULT hres;
  727. EnterProc(DIWdm_SetConfig, (_"uppu", idJoy, pjwc, pcfg, fl));
  728. DllEnterCrit();
  729. hres = E_FAIL;
  730. if( pcfg->dwSize < cbX(DIJOYCONFIG_DX6 ))
  731. {
  732. /* This function needs DX5B2 functionality */
  733. hres = DIERR_INVALIDPARAM;
  734. } else if( pjwc->hws.dwFlags & JOY_HWS_AUTOLOAD )
  735. {
  736. /* Device cannot be autoload */
  737. hres = DIERR_UNSUPPORTED;
  738. } else
  739. {
  740. DIJOYTYPEINFO dijti;
  741. BUS_REGDATA RegData;
  742. ZeroX(dijti);
  743. dijti.dwSize = cbX(dijti);
  744. ZeroX(RegData);
  745. RegData.dwSize = cbX(RegData);
  746. RegData.nJoysticks = 1;
  747. /* Is this a predefined joystick type ? */
  748. if(pcfg->wszType[0] == TEXT('#'))
  749. {
  750. #define JoyCfg_TypeFromChar(tch) ((tch) - L'0')
  751. hres = JoyReg_GetPredefTypeInfo(pcfg->wszType,
  752. &dijti, DITC_INREGISTRY | DITC_HARDWAREID);
  753. RegData.uVID = MSFT_SYSTEM_VID;
  754. RegData.uPID = MSFT_SYSTEM_PID + JoyCfg_TypeFromChar(pcfg->wszType[1]);
  755. if(JoyCfg_TypeFromChar(pcfg->wszType[1]) == JOY_HW_TWO_2A_2B_WITH_Y )
  756. {
  757. RegData.nJoysticks = 2;
  758. pjwc->hws.dwFlags = 0x0;
  759. }
  760. #undef JoyCfg_TypeFromChar
  761. } else
  762. {
  763. hres = JoyReg_GetTypeInfo(pcfg->wszType,
  764. &dijti, DITC_INREGISTRY | DITC_HARDWAREID | DITC_DISPLAYNAME );
  765. if( SUCCEEDED(hres) )
  766. {
  767. USHORT uVID, uPID;
  768. PWCHAR pCurrChar;
  769. PWCHAR pLastSlash = NULL;
  770. /* Find the last slash in the hardwareId, any VID/PID should follow directly */
  771. for( pCurrChar = dijti.wszHardwareId; *pCurrChar != L'\0'; pCurrChar++ )
  772. {
  773. if( *pCurrChar == L'\\' )
  774. {
  775. pLastSlash = pCurrChar;
  776. }
  777. }
  778. /*
  779. * If the hardware ID has no separator, treat the device as
  780. * though JOY_HWS_AUTOLOAD were set because we cannot expose
  781. * a non-PnP device without a hardware ID.
  782. */
  783. if( pLastSlash++ )
  784. {
  785. /*
  786. * If the hardwareId does contain a VIDPID, try the type
  787. * name. Some auto-detect types require this.
  788. *
  789. * Prefix gets messed up in ParseVIDPID (mb:34573) and warns
  790. * that uVID is uninitialized when ParseVIDPID returns TRUE.
  791. */
  792. if( ParseVIDPID( &uVID, &uPID, pLastSlash )
  793. || ParseVIDPID( &uVID, &uPID, pcfg->wszType ) )
  794. {
  795. RegData.uVID = uVID;
  796. RegData.uPID = uPID;
  797. }
  798. else
  799. {
  800. SquirtSqflPtszV(sqfl | sqflBenign,
  801. TEXT("%hs: cannot find VID and PID for non-PnP type %ls"),
  802. s_szProc, pcfg->wszType);
  803. }
  804. }
  805. else
  806. {
  807. SquirtSqflPtszV(sqfl | sqflError,
  808. TEXT("%hs: invalid hardware ID for non-PnP type %ls"),
  809. s_szProc, pcfg->wszType);
  810. hres = DIERR_UNSUPPORTED;
  811. }
  812. }
  813. }
  814. if( SUCCEEDED(hres) )
  815. {
  816. PBUSDEVICEINFO pbdi;
  817. PBUSDEVICELIST pbdl;
  818. /* Copy over the hardwareID */
  819. lstrcpyW(RegData.wszHardwareId, dijti.wszHardwareId);
  820. RegData.hws = pjwc->hws;
  821. RegData.dwFlags1 = dijti.dwFlags1;
  822. pbdi = pbdiFromGUID(&pcfg->guidGameport);
  823. // Attach device to the gameport
  824. if( pbdi )
  825. {
  826. // Set the Joystick ID for the gameport/serialport
  827. pbdi->idJoy = idJoy;
  828. // We know which instance of the gameport.
  829. hres = DIBusDevice_Expose(pbdi, &RegData);
  830. } else if( NULL != ( pbdl = pbdlFromGUID(&pcfg->guidGameport ) ) )
  831. {
  832. // We don't kwow which instance of the gameport
  833. // only which bus.
  834. // We will expose the device on all instances of the
  835. // gameport and later delete devices when we find they
  836. // are not connected.
  837. hres = DIBusDevice_ExposeEx(pbdl, &RegData);
  838. } else
  839. {
  840. hres = DIERR_DEVICENOTREG;
  841. }
  842. if( SUCCEEDED(hres) )
  843. {
  844. /* Device is not present */
  845. pjwc->dwUsageSettings &= ~JOY_US_PRESENT;
  846. /* Definately volatile */
  847. pjwc->dwUsageSettings |= JOY_US_VOLATILE;
  848. }
  849. }
  850. }
  851. ExitOleProc();
  852. DllLeaveCrit();
  853. return hres;
  854. } /* DIWdm_SetConfig */
  855. /*****************************************************************************
  856. *
  857. * @doc EXTERNAL
  858. *
  859. * @func HRESULT | DIWdm_DeleteConfig |
  860. *
  861. * WDM extension for JoyCfd::DeleteConfig. On WDM a legacy(HID) device will
  862. * keep reappearing as long as the gameport bus is aware of it. So when a
  863. * legacy(HID) device is deleted, we need to find out he associated gameport bus
  864. * and tell him to stop attaching the device.
  865. *
  866. * @parm IN UINT | idJoy |
  867. *
  868. * ID of Joystick
  869. *
  870. * @returns
  871. *
  872. * HRESULT code
  873. * DIERR_DEVICENOTREG: Device is not a WDM device
  874. * DIERR_UNSUPPORTED: Device is WDM but not gameport
  875. * S_OK: Device Persistance removed.
  876. *
  877. *****************************************************************************/
  878. HRESULT EXTERNAL
  879. DIWdm_DeleteConfig( int idJoy )
  880. {
  881. HRESULT hres = S_OK;
  882. PBUSDEVICEINFO pbdi = NULL;
  883. PHIDDEVICEINFO phdi = NULL;
  884. EnterProcI(DIWdm_DeleteConfig, (_"u", idJoy));
  885. DllEnterCrit();
  886. DIHid_BuildHidList(FALSE);
  887. /*
  888. * pbdi (BUSDEVICEINFO) must be obtained before we remove the device
  889. */
  890. phdi = phdiFindJoyId(idJoy);
  891. if(phdi != NULL )
  892. {
  893. pbdi = pbdiFromphdi(phdi);
  894. } else
  895. {
  896. hres = DIERR_DEVICENOTREG;
  897. goto _done;
  898. }
  899. if( SUCCEEDED(hres)
  900. && phdi != NULL
  901. && pbdi != NULL )
  902. {
  903. lstrcpy( g_tszIdLastRemoved, pbdi->ptszId );
  904. g_tmLastRemoved = GetTickCount();
  905. // If the device is a bus device ( Non USB )
  906. // it needs some help in removal.
  907. hres = DIBusDevice_Remove(pbdi);
  908. //If the device has been successfully removed,
  909. //then we need remember it in phdi list in case
  910. //the PnP doesn't function well.
  911. if( pbdi->fAttached == FALSE )
  912. {
  913. phdi->fAttached = FALSE;
  914. }
  915. } else
  916. {
  917. //HDEVINFO hdev;
  918. // Device is USB, we do not support removing
  919. // USB devices from the CPL. User is encouraged to
  920. // Yank out the device or go to the device manager to
  921. // remove it.
  922. // This is true in Win2K. But in Win9X, since VJOYD also works with USB,
  923. // when we swap id, we need delete it first.
  924. hres = DIERR_UNSUPPORTED;
  925. #if 0
  926. // In case we wanted to support removing USB devices from
  927. // the game cpl. Here is the code ...
  928. /*
  929. * Talk to SetupApi to delete the device.
  930. * This should not be necessary, but I have
  931. * to do this to work around a PnP bug whereby
  932. * the device is not removed after I send a remove
  933. * IOCTL to gameenum.
  934. */
  935. hdev = SetupDiCreateDeviceInfoList(NULL, NULL);
  936. if( phdi && hdev != INVALID_HANDLE_VALUE)
  937. {
  938. SP_DEVINFO_DATA dinf;
  939. dinf.cbSize = cbX(SP_DEVINFO_DATA);
  940. /* Get SP_DEVINFO_DATA for the HID device */
  941. if(SetupDiOpenDeviceInfo(hdev, phdi->ptszId, NULL, 0, &dinf))
  942. {
  943. /* Delete the device */
  944. if( SetupDiCallClassInstaller(DIF_REMOVE,
  945. hdev,
  946. &dinf) )
  947. {
  948. // SUCCESS
  949. } else
  950. {
  951. hres = E_FAIL;
  952. SquirtSqflPtszV(sqfl | sqflError,
  953. TEXT("%S: SetupDiClassInstalled(DIF_REMOVE) FAILED "),
  954. s_szProc );
  955. }
  956. }
  957. SetupDiDestroyDeviceInfoList(hdev);
  958. }
  959. #endif
  960. }
  961. _done:
  962. /*
  963. * Force a remake of the HID list
  964. * Some devices may have disappered
  965. * It helps to sleep for some time to give
  966. * PnP and its worker threads to spin.
  967. */
  968. Sleep(10);
  969. DIHid_BuildHidList(TRUE);
  970. DllLeaveCrit();
  971. ExitOleProc();
  972. return hres;
  973. }