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.

1911 lines
56 KiB

  1. /*****************************************************************************
  2. *
  3. * DIPort.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Support functions for Gameport/Serialport enumeration.
  10. *
  11. * Contents:
  12. *
  13. *
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. /*
  18. * We can reuse some code from diHidEnm.c
  19. */
  20. #define DIPort_GetDevicePath(hdev, pdid, didd, dinf) \
  21. DIHid_GetDevicePath(hdev, pdid, didd, dinf)
  22. #define DIPort_GetDeviceInstanceId(hdev, pdinf, tszId) \
  23. DIHid_GetDeviceInstanceId(hdev, pdinf, tszId)
  24. #define DIPort_GetInstanceGUID(hk, lpguid) \
  25. DIHid_GetInstanceGUID(hk, lpguid)
  26. #define DIPort_GetRegistryProperty(ptszId, dwProperty, pdiph) \
  27. DIHid_GetRegistryProperty(ptszId, dwProperty, pdiph)
  28. /*****************************************************************************
  29. *
  30. * The sqiffle for this file.
  31. *
  32. *****************************************************************************/
  33. #undef sqfl
  34. #define sqfl sqflPort
  35. /*****************************************************************************
  36. *
  37. * @doc INTERNAL
  38. *
  39. * @global PBUSDEVICE | g_pBusDevice |
  40. *
  41. * List of known GamePort/SerialPort devices.
  42. *
  43. *****************************************************************************/
  44. static BUSDEVICE g_pBusDevice[] =
  45. {
  46. {
  47. D(TEXT("GamePort Bus") comma)
  48. NULL,
  49. &GUID_GAMEENUM_BUS_ENUMERATOR,
  50. 0x0,
  51. IOCTL_GAMEENUM_EXPOSE_HARDWARE,
  52. IOCTL_GAMEENUM_REMOVE_HARDWARE,
  53. IOCTL_GAMEENUM_PORT_DESC,
  54. IOCTL_GAMEENUM_PORT_PARAMETERS,
  55. IOCTL_GAMEENUM_EXPOSE_SIBLING,
  56. IOCTL_GAMEENUM_REMOVE_SELF,
  57. IDS_STDGAMEPORT,
  58. JOY_HWS_ISGAMEPORTBUS
  59. },
  60. /***************
  61. No defination for serial port devices yet !
  62. {
  63. D(TEXT("SerialPort Bus") comma )
  64. NULL,
  65. &GUID_SERENUM_BUS_ENUMERATOR,
  66. 0x0,
  67. IOCTL_SERIALENUM_EXPOSE_HARDWARE,
  68. IOCTL_SERIALENUM_REMOVE_HARDWARE,
  69. IOCTL_SERIALENUM_PORT_DESC,
  70. IOCTL_SERIALENUM_PORT_PARAMETERS,
  71. IOCTL_SERIALENUM_EXPOSE_SIBLING,
  72. IOCTL_SERIALENUM_REMOVE_SELF,
  73. IDS_STDSERIALPORT,
  74. JOY_HWS_ISSERIALPORTBUS
  75. },
  76. ****************/
  77. };
  78. #pragma BEGIN_CONST_DATA
  79. /*****************************************************************************
  80. *
  81. * @doc INTERNAL
  82. *
  83. * @func BOOL INTERNAL | SearchDevTree |
  84. *
  85. * Helper routine that searches the device tree for
  86. * a desired device device.
  87. *
  88. * @parm IN DEVINST | dnStart |
  89. * Starting point for the search.
  90. *
  91. * @parm IN DEVINST | dnSeek |
  92. * The device instance we are looking for.
  93. *
  94. * @parm IN PULONG | pRecurse |
  95. * To limit the number of recursions.
  96. *
  97. * @returns BOOL
  98. * True on success.
  99. *
  100. *****************************************************************************/
  101. CONFIGRET INTERNAL
  102. SearchDevTree
  103. (
  104. DEVINST dnStart,
  105. DEVINST dnSeek,
  106. PUINT pRecurse
  107. )
  108. {
  109. #define MAX_RECURSION ( 4 )
  110. CONFIGRET cr;
  111. EnterProcI(SearchDevTree, (_"xxx", dnStart, dnSeek, pRecurse));
  112. cr = CR_SUCCESS;
  113. for( *pRecurse = 0x0; *pRecurse < MAX_RECURSION && cr == CR_SUCCESS; (*pRecurse)++)
  114. {
  115. cr = CM_Get_Parent(&dnSeek, dnSeek, 0 );
  116. if( dnStart == dnSeek )
  117. {
  118. break;
  119. }
  120. }
  121. if( dnStart != dnSeek )
  122. {
  123. cr = CR_NO_SUCH_DEVNODE;
  124. }
  125. #undef MAX_RECURSION
  126. #if 0 // Using Recursion
  127. if( *pRecurse > MAX_RECURSION )
  128. {
  129. return CR_NO_SUCH_DEVNODE;
  130. }
  131. if( dnSeek == dnStart )
  132. {
  133. return CR_SUCCESS;
  134. }
  135. do
  136. {
  137. DEVINST dnNode;
  138. cr = CM_Get_Child(&dnNode, dnStart, 0 );
  139. if( cr == CR_SUCCESS )
  140. {
  141. CAssertF(CR_SUCCESS == 0x0 );
  142. if( CR_SUCCESS == SearchDevTree(dnNode, dnSeek, pRecurse) )
  143. {
  144. return cr;
  145. }
  146. }
  147. cr = CM_Get_Sibling(&dnStart, dnStart, 0);
  148. }while( cr == CR_SUCCESS );
  149. #endif // No recursion
  150. return cr;
  151. }
  152. /*****************************************************************************
  153. *
  154. * @doc INTERNAL
  155. *
  156. * @func PBUSDEVICEINFO | pbdiFromphdi |
  157. *
  158. * Locates Gameport/Serialport information given a device instance of
  159. * one of its children.
  160. * Returns NULL if the device instance is not a child of
  161. * any known gameports/serialports
  162. *
  163. * Internal Routine, parameters already validated.
  164. *
  165. * The DLL critical must be held across the call; once the
  166. * critical section is released, the returned pointer becomes
  167. * invalid.
  168. *
  169. * @parm IN PHIDDEVICEINFO | phdi |
  170. *
  171. * Address of a HIDDEVICEINFO structure
  172. *
  173. * @returns
  174. *
  175. * Pointer to the <t BUSDEVICEINFO> that describes
  176. * the parent bus.
  177. *
  178. *****************************************************************************/
  179. PBUSDEVICEINFO INTERNAL
  180. pbdiFromphdi
  181. (
  182. IN PHIDDEVICEINFO phdi
  183. )
  184. {
  185. PBUSDEVICEINFO pbdi_Found;
  186. PBUSDEVICE pBusDevice;
  187. int iBusType;
  188. EnterProcI(pbdiFromphdi, (_"x", phdi));
  189. AssertF(InCrit());
  190. AssertF(phdi != NULL );
  191. pbdi_Found = NULL;
  192. for( iBusType = 0x0, pBusDevice = g_pBusDevice;
  193. iBusType < cA(g_pBusDevice) && pbdi_Found == NULL;
  194. iBusType++, pBusDevice++ )
  195. {
  196. HDEVINFO hdev;
  197. /*
  198. * Now talk to SetupApi to get info about the device.
  199. */
  200. hdev = SetupDiCreateDeviceInfoList(NULL, NULL);
  201. if(hdev != INVALID_HANDLE_VALUE )
  202. {
  203. SP_DEVINFO_DATA dinf_hid;
  204. ZeroX(dinf_hid);
  205. dinf_hid.cbSize = cbX(SP_DEVINFO_DATA);
  206. /* Get SP_DEVINFO_DATA for the HID device */
  207. if( pBusDevice->pbdl != NULL &&
  208. phdi!= NULL &&
  209. SetupDiOpenDeviceInfo(hdev, phdi->ptszId, NULL, 0, &dinf_hid))
  210. {
  211. int igdi;
  212. PBUSDEVICEINFO pbdi;
  213. SP_DEVINFO_DATA dinf_bus;
  214. ZeroX(dinf_bus);
  215. dinf_bus.cbSize = cbX(SP_DEVINFO_DATA);
  216. /*
  217. * Loop through all known gameports/serialports and look for a gameport/serialport
  218. * that is a parent of the HID device
  219. */
  220. for(igdi = 0, pbdi = pBusDevice->pbdl->rgbdi;
  221. igdi < pBusDevice->pbdl->cgbi && pbdi_Found == NULL ;
  222. igdi++, pbdi++)
  223. {
  224. if(SetupDiOpenDeviceInfo(hdev, pbdi->ptszId, NULL, 0, &dinf_bus))
  225. {
  226. ULONG Recurse = 0x0;
  227. if( CR_SUCCESS == SearchDevTree(dinf_bus.DevInst, dinf_hid.DevInst, &Recurse) )
  228. {
  229. pbdi_Found = pbdi;
  230. break;
  231. }
  232. }
  233. }
  234. }
  235. SetupDiDestroyDeviceInfoList(hdev);
  236. }
  237. }
  238. ExitProcX((UINT_PTR)pbdi_Found);
  239. return pbdi_Found;
  240. }
  241. /*****************************************************************************
  242. *
  243. * @doc INTERNAL
  244. *
  245. * @func PBUSDEVICEINFO | pbdiFromGUID |
  246. *
  247. * Locates Gameport/Serialport information given a device instance of
  248. * one of its children.
  249. * Returns NULL if the device instance is not a child of
  250. * any known gameports/serialports
  251. *
  252. * Internal Routine, parameters already validated.
  253. *
  254. * The DLL critical must be held across the call; once the
  255. * critical section is released, the returned pointer becomes
  256. * invalid.
  257. *
  258. * @parm IN PCGUID | pguid |
  259. *
  260. * The instance GUID to be located.
  261. *
  262. * @returns
  263. *
  264. * Pointer to the <t BUSDEVICEINFO> that describes
  265. * the parent bus.
  266. *
  267. *****************************************************************************/
  268. PBUSDEVICEINFO EXTERNAL
  269. pbdiFromGUID
  270. (
  271. IN PCGUID pguid
  272. )
  273. {
  274. PBUSDEVICEINFO pbdi_Found;
  275. PBUSDEVICE pBusDevice;
  276. int iBusType;
  277. EnterProcI(pbdiFromGUID, (_"G", &pguid));
  278. AssertF(InCrit());
  279. pbdi_Found = NULL;
  280. for( iBusType = 0x0, pBusDevice = g_pBusDevice;
  281. iBusType < cA(g_pBusDevice) && pbdi_Found == NULL;
  282. iBusType++, pBusDevice++ )
  283. {
  284. /*
  285. * Loop through all known gameports/serialports and look for a gameport/serialport
  286. * that is a parent of the HID device
  287. */
  288. PBUSDEVICEINFO pbdi;
  289. int igdi;
  290. for(igdi = 0, pbdi = pBusDevice->pbdl->rgbdi;
  291. igdi < pBusDevice->pbdl->cgbi && pbdi_Found == NULL ;
  292. igdi++, pbdi++)
  293. {
  294. if( IsEqualGUID(pguid, &pbdi->guid) )
  295. {
  296. pbdi_Found = pbdi;
  297. }
  298. }
  299. }
  300. ExitProcX((UINT_PTR)pbdi_Found);
  301. return pbdi_Found;
  302. }
  303. /*****************************************************************************
  304. *
  305. * @doc INTERNAL
  306. *
  307. * @func PHIDDEVICEINFO | phdiFrompbdi |
  308. *
  309. * Locates a HID device attached to a given Gameport/Serialport
  310. * Returns NULL if no devices are currently attached to a known port.
  311. *
  312. * Internal Routine, parameters already validated.
  313. *
  314. * The DLL critical must be held across the call; once the
  315. * critical section is released, the returned pointer becomes
  316. * invalid.
  317. *
  318. * @parm IN PBUSDEVICEINFO | pbdi |
  319. *
  320. * Address of the <t BUSDEVICEINFO> structure that
  321. * describes the gameport/serialport.
  322. *
  323. * @returns
  324. *
  325. * Pointer to one of the <t HIDDEVICEINFO> that describes
  326. * the device. ( Gamport may have multiple devices attached ).
  327. *
  328. *****************************************************************************/
  329. PHIDDEVICEINFO INTERNAL
  330. phdiFrompbdi
  331. (
  332. IN PBUSDEVICEINFO pbdi
  333. )
  334. {
  335. PHIDDEVICEINFO phdi_Found;
  336. HDEVINFO hdev;
  337. EnterProcI(phdiFrompbdi, (_"x", pbdi));
  338. AssertF(InCrit());
  339. AssertF(pbdi != NULL );
  340. /* Enumurate the HID devices */
  341. DIHid_BuildHidList(TRUE);
  342. phdi_Found = NULL;
  343. /*
  344. * Now talk to SetupApi to get info about the device.
  345. */
  346. hdev = SetupDiCreateDeviceInfoList(NULL, NULL);
  347. if(hdev != INVALID_HANDLE_VALUE)
  348. {
  349. SP_DEVINFO_DATA dinf_bus;
  350. dinf_bus.cbSize = cbX(SP_DEVINFO_DATA);
  351. if( pbdi != NULL && SetupDiOpenDeviceInfo(hdev, pbdi->ptszId, NULL, 0, &dinf_bus))
  352. {
  353. int ihdi;
  354. PHIDDEVICEINFO phdi;
  355. SP_DEVINFO_DATA dinf_hid;
  356. dinf_hid.cbSize = cbX(SP_DEVINFO_DATA);
  357. if( g_phdl )
  358. {
  359. for(ihdi = 0, phdi = g_phdl->rghdi ;
  360. ihdi < g_phdl->chdi && phdi_Found == NULL ;
  361. ihdi++, phdi++)
  362. {
  363. if(SetupDiOpenDeviceInfo(hdev, phdi->ptszId, NULL, 0, &dinf_hid))
  364. {
  365. ULONG Recurse = 0x0;
  366. if(CR_SUCCESS == SearchDevTree(dinf_bus.DevInst, dinf_hid.DevInst, &Recurse) )
  367. {
  368. phdi_Found = phdi;
  369. }
  370. }
  371. }
  372. }
  373. }
  374. SetupDiDestroyDeviceInfoList(hdev);
  375. }
  376. ExitProcX((UINT_PTR)phdi_Found);
  377. return phdi_Found;
  378. }
  379. /*****************************************************************************
  380. *
  381. * @doc EXTERNAL
  382. *
  383. * @func PPORTDEVICEINFO | pbdiFromJoyId |
  384. *
  385. * Locates Gameport/Serialport information given a device id of
  386. * a joystick .
  387. *
  388. * Returns NULL if the device instance is not a child of
  389. * any known gameports/serialports
  390. *
  391. * Internal Routine, parameters already validated.
  392. *
  393. * The DLL critical must be held across the call; once the
  394. * critical section is released, the returned pointer becomes
  395. * invalid.
  396. *
  397. * @parm IN int | idJoy |
  398. *
  399. * The Joystick ID of the child device that will be associated
  400. * to a known gameport/serialport.
  401. *
  402. * @returns
  403. *
  404. * Pointer to the <t BUSDEVICEINFO> that describes
  405. * the device.
  406. *
  407. *****************************************************************************/
  408. PBUSDEVICEINFO EXTERNAL
  409. pbdiFromJoyId
  410. (
  411. IN int idJoy
  412. )
  413. {
  414. GUID guid;
  415. HRESULT hres;
  416. PBUSDEVICEINFO pbdi;
  417. EnterProcI(pbdiFromJoyId, (_"x", idJoy));
  418. AssertF(InCrit());
  419. pbdi = NULL;
  420. /* Find the GUID that corresponds to the Joystick ID */
  421. hres = hResIdJoypInstanceGUID_WDM(idJoy, &guid);
  422. #ifndef WINNT
  423. if( FAILED(hres) ) {
  424. hres = hResIdJoypInstanceGUID_95(idJoy, &guid);
  425. }
  426. #endif
  427. if( SUCCEEDED(hres) )
  428. {
  429. PHIDDEVICEINFO phdi;
  430. phdi = phdiFindHIDInstanceGUID(&guid);
  431. if( phdi != NULL )
  432. {
  433. pbdi = pbdiFromphdi(phdi);
  434. }
  435. }
  436. ExitProcX((UINT_PTR)pbdi);
  437. return pbdi;
  438. }
  439. /*****************************************************************************
  440. *
  441. * @doc INTERNAL
  442. *
  443. * @func BOOL | DIBusDevice_Expose |
  444. *
  445. * Attaches a gameport/serialport device to the Gameport/SerialPort Bus
  446. *
  447. * @parm IN PBUSDEVICEINFO | pbdi |
  448. * Address of a BUSDEVICEINFO structure.
  449. *
  450. * @parm IN OUT PBUS_REGDATA | pRegData |
  451. * Gameport/Serialport specific data. The Handle to the opened device
  452. * is returned in this structure
  453. *
  454. *
  455. * @returns
  456. * BOOL. True indicates success.
  457. *
  458. *****************************************************************************/
  459. HRESULT EXTERNAL
  460. DIBusDevice_Expose
  461. (
  462. IN PBUSDEVICEINFO pbdi,
  463. IN OUT PBUS_REGDATA pRegData
  464. )
  465. {
  466. HRESULT hres;
  467. BOOL frc;
  468. PHIDDEVICEINFO phdi;
  469. EnterProcI(DIBusDevice_Expose, (_ "pp", pbdi, pRegData));
  470. AssertF(DllInCrit() );
  471. AssertF(pbdi!= NULL );
  472. phdi = phdiFrompbdi(pbdi);
  473. if( pRegData && pRegData->dwSize != cbX(*pRegData) )
  474. {
  475. hres = E_INVALIDARG;
  476. } else if( phdi != NULL )
  477. {
  478. hres = E_ACCESSDENIED;
  479. } else
  480. {
  481. HANDLE hf;
  482. BUS_REGDATA RegDataTest;
  483. /* There is a weird condition where the HID device does not appear on a previous
  484. * Add, (drivers not loaded, user cancelled loading of some files, etc
  485. * In such cases we need to tell GameEnum to remove the device before proceeding
  486. * any further
  487. */
  488. if( pbdi->fAttached || pRegData->hHardware != NULL )
  489. {
  490. DIBusDevice_Remove(pbdi);
  491. }
  492. AssertF(pbdi->fAttached == FALSE);
  493. // Change for Windows bug 575181 -- make sure we can write to the registry
  494. // before we expose the device; otherwise we might not be able to remove it!
  495. ZeroMemory(&RegDataTest, cbX(RegDataTest));
  496. RegDataTest.dwSize = cbX(RegDataTest);
  497. if (FAILED(DIBusDevice_SetRegData(pbdi->hk, &RegDataTest)))
  498. {
  499. // We couldn't write to the registy; return E_ACCESSDENIED
  500. hres = E_ACCESSDENIED;
  501. }
  502. else
  503. {
  504. // Open a File handle to the gameport/serialport device so we can send it IOCTLS
  505. hf = CreateFile(pbdi->pdidd->DevicePath,
  506. GENERIC_READ | GENERIC_WRITE,
  507. FILE_SHARE_READ | FILE_SHARE_WRITE,
  508. 0, /* no SECURITY_ATTRIBUTES */
  509. OPEN_EXISTING,
  510. 0, /* attributes */
  511. 0); /* template */
  512. if( hf != INVALID_HANDLE_VALUE )
  513. {
  514. DWORD cbRc;
  515. GAMEENUM_PORT_DESC Desc;
  516. Desc.Size = cbX(Desc) ;
  517. Sleep(50); //need sleep a while to wait for the device is ready to accept commands.
  518. /* Get the gameport bus properties */
  519. frc = DeviceIoControl (hf,
  520. pbdi->pBusDevice->ioctl_DESC,
  521. &Desc, cbX(Desc),
  522. &Desc, cbX(Desc),
  523. &cbRc, NULL);
  524. if( frc && cbRc == cbX(Desc) )
  525. {
  526. PGAMEENUM_EXPOSE_HARDWARE pExpose;
  527. DWORD cbExpose;
  528. cbExpose = cbX(*pExpose) + cbX(pRegData->wszHardwareId);
  529. hres = AllocCbPpv( cbExpose, & pExpose);
  530. if( SUCCEEDED(hres ) )
  531. {
  532. typedef struct _OEMDATA
  533. {
  534. ULONG uVID_uPID;
  535. ULONG joy_hws_dwFlags;
  536. ULONG dwFlags1;
  537. ULONG Reserved;
  538. } OEMDATA, *POEMDATA;
  539. POEMDATA pOemData = (POEMDATA)(&pExpose->OemData);
  540. CAssertF(2*sizeof(*pOemData) == sizeof(pExpose->OemData))
  541. pOemData->uVID_uPID = MAKELONG(pRegData->uVID, pRegData->uPID);
  542. pOemData->joy_hws_dwFlags = pRegData->hws.dwFlags;
  543. pOemData->dwFlags1 = pRegData->dwFlags1;
  544. /*
  545. * Make sure only known analog devices cause the
  546. * compatible hardware ID to be exposed.
  547. * This is done so that no in-box drivers will match for
  548. * an unsupported digital joystick so users will be
  549. * prompted to use an unsigned IHV driver rather than
  550. * silently loading the generic analog joystick driver.
  551. */
  552. if( ( pRegData->dwFlags1 & JOYTYPE_ANALOGCOMPAT )
  553. || ( ( pRegData->uVID == MSFT_SYSTEM_VID )
  554. && ( ( pRegData->uPID & 0xff00 ) == MSFT_SYSTEM_PID ) ) )
  555. {
  556. pExpose->Flags = GAMEENUM_FLAG_COMPATIDCTRL;
  557. }
  558. else
  559. {
  560. pExpose->Flags = GAMEENUM_FLAG_COMPATIDCTRL | GAMEENUM_FLAG_NOCOMPATID ;
  561. }
  562. pExpose->Size = cbX(*pExpose) ;
  563. pExpose->PortHandle = Desc.PortHandle;
  564. pExpose->NumberJoysticks = pRegData->nJoysticks;
  565. pRegData->nAxes = 2;
  566. if( pExpose->NumberJoysticks != 2 )
  567. {
  568. AssertF( pExpose->NumberJoysticks == 1);
  569. if( pRegData->hws.dwFlags & JOY_HWS_HASZ )
  570. {
  571. pRegData->nAxes++;
  572. }
  573. if( pRegData->hws.dwFlags & JOY_HWS_HASR )
  574. {
  575. pRegData->nAxes++;
  576. }
  577. pExpose->NumberButtons = (USHORT)pRegData->hws.dwNumButtons;
  578. }
  579. else
  580. {
  581. pOemData++;
  582. pOemData->uVID_uPID = MAKELONG(pRegData->uVID, pRegData->uPID);
  583. pOemData->joy_hws_dwFlags = JOY_HWS_XISJ2X | JOY_HWS_YISJ2Y;
  584. pExpose->NumberButtons = 2;
  585. }
  586. pExpose->NumberAxis = pRegData->nAxes;
  587. /*
  588. * The SideWinder driver uses the OEMData field in a
  589. * sibling expose to pass internal data (this ptrs) from
  590. * one instance to another. Since these fields are
  591. * supposed to be for the OEMData we have a Flags1 field
  592. * to allow the data to be zeroed for a DInput expose for
  593. * drivers that don't want the normal data.
  594. */
  595. if ( pRegData->dwFlags1 & JOYTYPE_ZEROGAMEENUMOEMDATA )
  596. {
  597. ZeroBuf(pExpose->OemData, sizeof(pExpose->OemData) );
  598. }
  599. CopyMemory(pExpose->HardwareIDs, pRegData->wszHardwareId, cbX(pRegData->wszHardwareId) );
  600. Sleep(50);
  601. if( frc = DeviceIoControl (hf,
  602. pbdi->pBusDevice->ioctl_EXPOSE,
  603. pExpose, cbExpose,
  604. pExpose, cbExpose,
  605. &cbRc, NULL )
  606. && cbRc == cbExpose )
  607. {
  608. PVOID hHardwareOld = pRegData->hHardware;
  609. pbdi->fAttached = TRUE;
  610. pRegData->hHardware = pExpose->HardwareHandle;
  611. DIBusDevice_SetRegData(pbdi->hk, pRegData);
  612. /*
  613. * If we have dealt with this device before then the hHardwareOld
  614. * will be non null, and we have sufficient reason to believe that the
  615. * expose will succeed.
  616. *
  617. * This test needs to be removed to fix manbug: 39554.
  618. * For new created device, we need wait for a while to let phdi be ready.
  619. *
  620. */
  621. //if(hHardwareOld)
  622. {
  623. int i;
  624. for(i = 0; (i < 20) && (phdiFrompbdi(pbdi) == NULL); i++ )
  625. {
  626. Sleep(50);
  627. }
  628. }
  629. } else // DeviceIOControl (EXPOSE) Failed
  630. {
  631. hres = E_FAIL;
  632. SquirtSqflPtszV(sqfl | sqflError,
  633. TEXT("%S: IOCTL_PORTENUM_EXPOSE_HARDWARE failed ")
  634. TEXT("Error = %d"),
  635. s_szProc, GetLastError());
  636. }
  637. FreePpv(&pExpose);
  638. } else // Alloc failed
  639. {
  640. SquirtSqflPtszV(sqfl | sqflError,
  641. TEXT("%S: AllocCbPpv failed "),
  642. s_szProc);
  643. }
  644. } else // IOCTL FAILED
  645. {
  646. hres = E_FAIL;
  647. SquirtSqflPtszV(sqfl | sqflError,
  648. TEXT("%S: IOCTL_PORTENUM_PORT_DESC failed ")
  649. TEXT("Error = %d"),
  650. s_szProc, GetLastError());
  651. }
  652. CloseHandle(hf);
  653. } else
  654. {
  655. hres = E_FAIL;
  656. SquirtSqflPtszV(sqfl | sqflError,
  657. TEXT("%S: CreateFile(%s) failed ")
  658. TEXT("Error = %d"),
  659. s_szProc, pbdi->pdidd->DevicePath, GetLastError());
  660. }
  661. }
  662. }
  663. ExitBenignProcX(hres);
  664. return hres;
  665. }
  666. /*****************************************************************************
  667. *
  668. * @doc INTERNAL
  669. *
  670. * @func BOOL | DIBusDevice_Remove |
  671. *
  672. * Removes the FDO for a gameport/serialport device.
  673. *
  674. * @parm IN HANDLE | hf |
  675. * Handle to the GamePort/SerialPort Bus device file object
  676. *
  677. * @parm IN PPORT_REGDATA | pRegData |
  678. * Structure that contains registry data. What we need from here is the
  679. * handle to the hardware.
  680. *
  681. * @returns
  682. * BOOL. True for success.
  683. *
  684. *****************************************************************************/
  685. HRESULT INTERNAL
  686. DIBusDevice_Remove
  687. (
  688. IN PBUSDEVICEINFO pbdi
  689. )
  690. {
  691. HRESULT hres;
  692. BUS_REGDATA RegData;
  693. EnterProcI(DIBus_Remove, (_ "p", pbdi));
  694. hres = DIBusDevice_GetRegData(pbdi->hk, &RegData);
  695. //
  696. // Delete our registry goo, so this device
  697. // will not show up on subsequent reboots
  698. //
  699. DIBusDevice_SetRegData(pbdi->hk, NULL);
  700. if( SUCCEEDED(hres) )
  701. {
  702. HANDLE hf;
  703. BOOL frc;
  704. // Open a File handle to the gameport/serialport device so we can send it IOCTLS
  705. hf = CreateFile(pbdi->pdidd->DevicePath,
  706. GENERIC_READ | GENERIC_WRITE,
  707. FILE_SHARE_READ | FILE_SHARE_WRITE,
  708. 0, /* no SECURITY_ATTRIBUTES */
  709. OPEN_EXISTING,
  710. 0, /* attributes */
  711. 0); /* template */
  712. if( hf != INVALID_HANDLE_VALUE )
  713. {
  714. DWORD cbRc;
  715. GAMEENUM_REMOVE_HARDWARE Remove;
  716. Remove.Size = cbX(Remove);
  717. Remove.HardwareHandle = RegData.hHardware;
  718. frc = DeviceIoControl (hf,
  719. pbdi->pBusDevice->ioctl_REMOVE,
  720. &Remove, cbX(Remove),
  721. &Remove, cbX(Remove),
  722. &cbRc, NULL) ;
  723. if( frc && cbRc == cbX(Remove) )
  724. {
  725. pbdi->fAttached = FALSE;
  726. } else // DeviceIoControl ( REMOVE_HARDWARE ) Failed
  727. {
  728. hres = E_FAIL;
  729. SquirtSqflPtszV(sqfl | sqflError,
  730. TEXT("%S: DeviceIOControl(REMOVE_HARDWARE) failed ")
  731. TEXT("Error = %d"),
  732. s_szProc, GetLastError());
  733. }
  734. CloseHandle(hf);
  735. }
  736. }
  737. ExitBenignOleProc();
  738. return hres;
  739. }
  740. /*****************************************************************************
  741. *
  742. * @doc INTERNAL
  743. *
  744. * @func HRESULT | DIPort_SetRegData |
  745. *
  746. * Sets up registry data under the $hk$/Config subkey for the gameport
  747. * device.
  748. *
  749. * @parm IN HKEY | hk |
  750. * A handle to the parent key where the registry data will be written.
  751. *
  752. * @parm IN PGAMEPORT_REGDATA | pRegData |
  753. * Pointer to a structure containing data to be written to the registry.
  754. *
  755. * @returns
  756. * BOOL. True for success
  757. *
  758. *****************************************************************************/
  759. HRESULT INTERNAL
  760. DIBusDevice_SetRegData
  761. (
  762. IN HKEY hk,
  763. IN PBUS_REGDATA pRegData
  764. )
  765. {
  766. LONG lrc;
  767. HRESULT hres = S_OK;
  768. EnterProcI(DIPort_SetRegData, (_ "xpx", hk, pRegData ));
  769. if( pRegData != NULL )
  770. {
  771. if( ( lrc = RegSetValueEx(hk, TEXT("Config"), 0, REG_BINARY,
  772. (PV) (pRegData), cbX(*pRegData)) ) == ERROR_SUCCESS )
  773. {
  774. hres = S_OK;
  775. } else // RegSetValueEx FAILED
  776. {
  777. hres = E_FAIL;
  778. SquirtSqflPtszV(sqfl | sqflError,
  779. TEXT("%S: RegSetValueEx() failed ")
  780. TEXT("Error = %d"),
  781. s_szProc, lrc);
  782. }
  783. } else
  784. {
  785. lrc = RegDeleteValue(hk, TEXT("Config"));
  786. }
  787. ExitOleProc();
  788. return (hres);
  789. }
  790. /*****************************************************************************
  791. *
  792. * @doc INTERNAL
  793. *
  794. * @func HRESULT | DIPort_GetRegData |
  795. *
  796. * Gets registry data from the $hk$/Config subkey for the gameport
  797. * device.
  798. *
  799. * @parm IN HKEY | hk |
  800. * A handle to the parent key where the registry.
  801. *
  802. * @parm IN PGAMEPORT_REGDATA | pRegData |
  803. * Address of a pointer to the structure where the registry data
  804. * will be read into.
  805. *
  806. * @returns
  807. * HRESULT
  808. *****************************************************************************/
  809. HRESULT INTERNAL
  810. DIBusDevice_GetRegData
  811. (
  812. IN HKEY hk,
  813. OUT PBUS_REGDATA pRegData
  814. )
  815. {
  816. LONG lRc;
  817. DWORD cb;
  818. HRESULT hres;
  819. EnterProcI(DIPort_GetRegData, (_ "xpx", hk, pRegData ));
  820. cb = cbX(*pRegData);
  821. lRc = RegQueryValueEx( hk, TEXT("Config"), 0, 0 , (PV)(pRegData), &cb );
  822. if( lRc == ERROR_SUCCESS && pRegData->dwSize == cbX(*pRegData ) )
  823. {
  824. hres = S_OK;
  825. } else
  826. {
  827. DIBusDevice_SetRegData(hk, NULL );
  828. ZeroX(*pRegData);
  829. hres = E_FAIL;
  830. SquirtSqflPtszV(sqfl | sqflBenign,
  831. TEXT("%S: RegQueryValueEx(Config) failed ")
  832. TEXT("Error = %d, ( pRegData->cbSize(%d) == cbX(*pRegData)(%d)) "),
  833. s_szProc, lRc, pRegData->dwSize, cbX(*pRegData) );
  834. }
  835. ExitBenignOleProc();
  836. return ( hres ) ;
  837. }
  838. /*****************************************************************************
  839. *
  840. * @doc INTERNAL
  841. *
  842. * @func void | DIBus_BuildListEntry |
  843. *
  844. * Builds a single entry in the list of GAMEPORT/SERIALPORT devices.
  845. *
  846. * @parm HDEVINFO | hdev |
  847. *
  848. * Device list being enumerated.
  849. *
  850. * @parm PSP_DEVICE_INTERFACE_DATA | pdid |
  851. *
  852. * Describes the device that was enumerated.
  853. *
  854. * @returns
  855. *
  856. * Nonzero on success.
  857. *
  858. *****************************************************************************/
  859. BOOL INTERNAL
  860. DIBusDevice_BuildListEntry
  861. (
  862. HDEVINFO hdev,
  863. PSP_DEVICE_INTERFACE_DATA pdid,
  864. PBUSDEVICE pBusDevice
  865. )
  866. {
  867. BOOL fRc = TRUE;
  868. //HKEY hkDev;
  869. HKEY hkDin;
  870. PBUSDEVICEINFO pbdi;
  871. PBUSDEVICELIST pbdl;
  872. PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd;
  873. BOOL fAlreadyExist;
  874. HRESULT hres;
  875. EnterProcI(DIBus_BuildListEntry, (_ "xp", hdev, pdid));
  876. pbdl = pBusDevice->pbdl;
  877. fAlreadyExist = FALSE;
  878. /* GetDevicePath is expecting a NULL */
  879. pdidd = NULL;
  880. if( DIPort_GetDevicePath(hdev, pdid, &pdidd, NULL) )
  881. {
  882. int ibdi;
  883. //Check whether the device has been in the list
  884. for( ibdi = 0; ibdi < pbdl->cgbi; ibdi++)
  885. {
  886. if( pbdl->rgbdi[ibdi].pdidd )
  887. {
  888. if( lstrcmp( pdidd->DevicePath, pbdl->rgbdi[ibdi].pdidd->DevicePath ) == 0 )
  889. {
  890. //already in the list
  891. fAlreadyExist = TRUE;
  892. break;
  893. }
  894. }
  895. }
  896. FreePpv(&pdidd);
  897. }
  898. if( fAlreadyExist == TRUE )
  899. {
  900. fRc = TRUE;
  901. } else
  902. {
  903. /*
  904. * Make sure there is room for this device in the list.
  905. * Grow by doubling.
  906. */
  907. if( pbdl->cgbi >= pbdl->cgbiAlloc)
  908. {
  909. /*
  910. * Assert that we never ask for zero bytes here
  911. */
  912. AssertF( cbGdlCbdi( pbdl->cgbiAlloc * 2) );
  913. hres = ReallocCbPpv( cbGdlCbdi( pbdl->cgbiAlloc * 2), &pBusDevice->pbdl );
  914. if( FAILED(hres) )
  915. {
  916. SquirtSqflPtszV(sqfl | sqflError,
  917. TEXT("%S: Realloc failed"), s_szProc);
  918. fRc = FALSE;
  919. goto done;
  920. }
  921. /*
  922. * Prefix warns (Win:170673) that pBusDevice->pbdl could be zero
  923. * if we asked for zero bytes above but the size requested cannot
  924. * be zero so this has been asserted. Note the fix for (W:45084)
  925. * was incorrect so it has been removed.
  926. */
  927. pbdl = pBusDevice->pbdl;
  928. pbdl->cgbiAlloc *= 2;
  929. }
  930. AssertF( pbdl->cgbi < pbdl->cgbiAlloc);
  931. pbdi = &pbdl->rgbdi[pbdl->cgbi];
  932. pbdi->pBusDevice = pBusDevice;
  933. pbdi->hk = 0;
  934. pbdi->idJoy = JOY_BOGUSID;
  935. /*
  936. * Open the registry key for the device so we can obtain
  937. * auxiliary information.
  938. */
  939. {
  940. //Open our own reg key under MediaProperties/DirectInput,
  941. //creating it if necessary.
  942. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  943. REGSTR_PATH_DITYPEPROP,
  944. DI_KEY_ALL_ACCESS,
  945. REG_OPTION_NON_VOLATILE,
  946. &hkDin);
  947. if (SUCCEEDED(hres))
  948. {
  949. //Create the Gameports reg key
  950. HKEY hkGameports;
  951. hres = hresMumbleKeyEx(hkDin,
  952. TEXT("Gameports"),
  953. DI_KEY_ALL_ACCESS,
  954. REG_OPTION_NON_VOLATILE,
  955. &hkGameports);
  956. if (SUCCEEDED(hres))
  957. {
  958. //Create a reg key corresponding to the instance number.
  959. //Since we do this for every gameport enumerated, the number in the list
  960. //indicates the instance number.
  961. TCHAR tszInst[3];
  962. wsprintf(tszInst, TEXT("%u"), pbdl->cgbi);
  963. hres = hresMumbleKeyEx(hkGameports,
  964. tszInst,
  965. DI_KEY_ALL_ACCESS,
  966. REG_OPTION_NON_VOLATILE,
  967. &pbdi->hk);
  968. if(SUCCEEDED(hres))
  969. {
  970. SP_DEVINFO_DATA dinf;
  971. dinf.cbSize = cbX(SP_DEVINFO_DATA);
  972. /*
  973. * Get the instance GUID and the path to
  974. * the GAMEPORT/SERIALPORT device so we can talk to it.
  975. */
  976. if(DIPort_GetDevicePath(hdev, pdid, &pbdi->pdidd, &dinf) &&
  977. DIPort_GetDeviceInstanceId(hdev, &dinf, &pbdi->ptszId) &&
  978. DIPort_GetInstanceGUID(pbdi->hk, &pbdi->guid) )
  979. {
  980. HANDLE hf;
  981. hf = CreateFile(pbdi->pdidd->DevicePath,
  982. GENERIC_READ | GENERIC_WRITE,
  983. FILE_SHARE_READ | FILE_SHARE_WRITE,
  984. 0, /* no SECURITY_ATTRIBUTES */
  985. OPEN_EXISTING,
  986. 0, /* attributes */
  987. 0); /* template */
  988. if( hf != INVALID_HANDLE_VALUE )
  989. {
  990. BUS_REGDATA RegData;
  991. ZeroX(RegData);
  992. CloseHandle(hf);
  993. // Bump up the counter
  994. fRc = TRUE;
  995. pbdl->cgbi++;
  996. hres = DIBus_InitId(pBusDevice->pbdl);
  997. if( SUCCEEDED(hres) )
  998. {
  999. hres = DIBusDevice_GetRegData(pbdi->hk, &RegData);
  1000. }
  1001. if( SUCCEEDED(hres) )
  1002. {
  1003. /* There is a pathological case which can cause endless bluescreen's
  1004. * If the HID driver causes a bluescreen, and we keep reattaching
  1005. * it, we are sunk !!
  1006. * To guard against this possiblity we reattach a device on reboot
  1007. * only if we are sure that it succeeded the first time around
  1008. */
  1009. if( RegData.fAttachOnReboot == FALSE )
  1010. {
  1011. DIBusDevice_Remove(pbdi);
  1012. SquirtSqflPtszV(sqfl | sqflError,
  1013. TEXT("%S: DIPortDevice_Expose FAILED, ")
  1014. TEXT("Driver did not load property the first time around "),
  1015. s_szProc);
  1016. } else if( pbdi->fAttached == FALSE )
  1017. {
  1018. hres = DIBusDevice_Expose( pbdi, &RegData );
  1019. if( SUCCEEDED( hres ) || hres == E_ACCESSDENIED )
  1020. {
  1021. pbdi->fAttached = TRUE;
  1022. } else
  1023. {
  1024. SquirtSqflPtszV(sqfl | sqflError,
  1025. TEXT("%S: DIPortDevice_Expose FAILED ")
  1026. TEXT("hres = %d"),
  1027. s_szProc, hres);
  1028. }
  1029. }
  1030. }
  1031. } else
  1032. {
  1033. fRc = FALSE;
  1034. SquirtSqflPtszV(sqfl | sqflError,
  1035. TEXT("%S: CreateFile(%s) failed ")
  1036. TEXT("Error = %d"),
  1037. s_szProc, pbdi->pdidd->DevicePath, GetLastError());
  1038. }
  1039. } else
  1040. {
  1041. SquirtSqflPtszV(sqfl | sqflError,
  1042. TEXT("%S: Unable to get device path"),
  1043. s_szProc);
  1044. pbdi->hk = 0x0;
  1045. fRc = FALSE;
  1046. }
  1047. /*
  1048. * If we failed, then free the goo we already got.
  1049. */
  1050. if(!fRc)
  1051. {
  1052. if( pbdi->hk )
  1053. RegCloseKey(pbdi->hk);
  1054. pbdi->hk = 0;
  1055. FreePpv(&pbdi->pdidd);
  1056. FreePpv(&pbdi->ptszId);
  1057. fRc = FALSE;
  1058. }
  1059. } else
  1060. {
  1061. SquirtSqflPtszV(sqfl | sqflError,
  1062. TEXT("%S: RegCreateKeyEx failed on Instance, error "),
  1063. s_szProc);
  1064. fRc = FALSE;
  1065. }
  1066. RegCloseKey(hkGameports);
  1067. } else // RegCreateKeyEx FAILED
  1068. {
  1069. SquirtSqflPtszV(sqfl | sqflError,
  1070. TEXT("%S: RegCreateKeyEx failed on Gameports, error "),
  1071. s_szProc);
  1072. fRc = FALSE;
  1073. }
  1074. RegCloseKey(hkDin);
  1075. }
  1076. else
  1077. {
  1078. SquirtSqflPtszV(sqfl | sqflError,
  1079. TEXT("%S: RegOpenKeyEx failed on DirectInput"),
  1080. s_szProc);
  1081. fRc = FALSE;
  1082. }
  1083. }
  1084. }
  1085. done:;
  1086. ExitProcF(fRc);
  1087. return fRc;
  1088. }
  1089. /*****************************************************************************
  1090. *
  1091. * @doc EXTERNAL
  1092. *
  1093. * @func void | DIPort_EmptyList |
  1094. *
  1095. * Empty the list of GAMEPORT/SERIALPORT devices.
  1096. *
  1097. * This function must be called under the DLL critical section.
  1098. *
  1099. *****************************************************************************/
  1100. void INTERNAL
  1101. DIBus_EmptyList
  1102. (
  1103. PBUSDEVICELIST *ppbdl
  1104. )
  1105. {
  1106. PBUSDEVICELIST pbdl = *ppbdl;
  1107. AssertF(InCrit());
  1108. if( pbdl )
  1109. {
  1110. int igdi;
  1111. for(igdi = 0; igdi < pbdl->cgbi; igdi++)
  1112. {
  1113. FreePpv(&pbdl->rgbdi[igdi].pdidd);
  1114. FreePpv(&pbdl->rgbdi[igdi].ptszId);
  1115. if( pbdl->rgbdi[igdi].hk)
  1116. {
  1117. RegCloseKey( pbdl->rgbdi[igdi].hk);
  1118. }
  1119. }
  1120. /*
  1121. * We invalidated all the pointers, so make sure
  1122. * nobody looks at them.
  1123. */
  1124. pbdl->cgbi = 0;
  1125. FreePpv(&pbdl);
  1126. *ppbdl = NULL;
  1127. }
  1128. }
  1129. void EXTERNAL
  1130. DIBus_FreeMemory()
  1131. {
  1132. int iBusType;
  1133. PBUSDEVICE pBusDevice;
  1134. for( iBusType = 0x0, pBusDevice = g_pBusDevice;
  1135. iBusType < cA(g_pBusDevice);
  1136. iBusType++, pBusDevice++ )
  1137. {
  1138. DIBus_EmptyList(&pBusDevice->pbdl);
  1139. }
  1140. }
  1141. /*****************************************************************************
  1142. *
  1143. * @doc EXTERNAL
  1144. *
  1145. * @func void | DIPort_InitId |
  1146. *
  1147. * Initializes Joystick IDs for JoyConfig and legacy APIs
  1148. * Store the joystick IDs the registry under the %%DirectX/JOYID key.
  1149. *
  1150. *****************************************************************************/
  1151. #undef PORTID_BOGUS
  1152. #define PORTID_BOGUS ( 0xffffffff )
  1153. HRESULT EXTERNAL
  1154. DIBus_InitId(PBUSDEVICELIST pbdl)
  1155. {
  1156. HRESULT hres = FALSE;
  1157. LONG lRc;
  1158. DWORD cb;
  1159. int igdi;
  1160. BOOL fNeedId;
  1161. BOOL rfPortId[cgbiMax]; /* Bool Array for to determine which IDs are in use */
  1162. PBUSDEVICEINFO pbdi;
  1163. EnterProcI(DIBus_InitId, (_ ""));
  1164. fNeedId = FALSE;
  1165. AssertF(DllInCrit());
  1166. ZeroX(rfPortId );
  1167. if( pbdl != NULL )
  1168. {
  1169. /* Iterate over to find used IDs */
  1170. for( igdi = 0, pbdi = pbdl->rgbdi ;
  1171. igdi < pbdl->cgbi ;
  1172. igdi++, pbdi++ )
  1173. {
  1174. pbdi->idPort = PORTID_BOGUS; // Default
  1175. cb = cbX(pbdi->idPort);
  1176. if( ( lRc = RegQueryValueEx(pbdi->hk, TEXT("ID"),
  1177. 0, 0, (PV)&pbdi->idPort, &cb) == ERROR_SUCCESS ) )
  1178. {
  1179. if( rfPortId[pbdi->idPort] // Collision in GameId
  1180. || pbdi->idPort > cgbiMax ) // Wrror
  1181. {
  1182. pbdi->idPort = PORTID_BOGUS;
  1183. fNeedId = TRUE;
  1184. } else // Valid idPort
  1185. {
  1186. rfPortId[pbdi->idPort] = TRUE;
  1187. }
  1188. } else // RegQueryValue("ID") does not exist
  1189. {
  1190. fNeedId = TRUE;
  1191. }
  1192. }
  1193. if( fNeedId )
  1194. {
  1195. /*
  1196. * We have Examined all GamePort/SerialPort Ids found used IDs
  1197. * and determined some device needs an Id
  1198. */
  1199. /* Iterate to assign unused Id's */
  1200. for( igdi = 0, pbdi = pbdl->rgbdi;
  1201. igdi < pbdl->cgbi ;
  1202. igdi++, pbdi++ )
  1203. {
  1204. if( pbdi->idPort == PORTID_BOGUS )
  1205. {
  1206. /* Get an Unused ID */
  1207. for( pbdi->idPort = 0x0;
  1208. pbdi->idPort < cgbiMax;
  1209. pbdi->idPort++ )
  1210. {
  1211. if( rfPortId[pbdi->idPort] == FALSE )
  1212. break;
  1213. }
  1214. rfPortId[pbdi->idPort] = TRUE;
  1215. if( lRc = RegSetValueEx(pbdi->hk, TEXT("ID"), 0, REG_BINARY,
  1216. (PV)&pbdi->idPort, cbX(pbdi->idPort)) == ERROR_SUCCESS )
  1217. {
  1218. } else
  1219. {
  1220. SquirtSqflPtszV(sqfl | sqflError,
  1221. TEXT("%S: RegSetValueEx(JOYID) FAILED ")
  1222. TEXT("Error = %d"),
  1223. s_szProc, lRc);
  1224. hres = FALSE;
  1225. }
  1226. }
  1227. }
  1228. }
  1229. }
  1230. ExitOleProc();
  1231. return hres;
  1232. }
  1233. /*****************************************************************************
  1234. *
  1235. * @doc INTERNAL
  1236. *
  1237. * @func void | DIBus_CheckList |
  1238. *
  1239. * Check the list of HID devices and free any that cannot be opened
  1240. *
  1241. * This function must be called under the DLL critical section.
  1242. *
  1243. *****************************************************************************/
  1244. void INTERNAL
  1245. DIBus_CheckList(PBUSDEVICELIST pbdl)
  1246. {
  1247. HANDLE hf;
  1248. AssertF(InCrit());
  1249. /*
  1250. * Free all the information of the device that cannot be opened
  1251. */
  1252. if(pbdl)
  1253. {
  1254. int ibdi;
  1255. PBUSDEVICEINFO pbdi;
  1256. for(ibdi = 0, pbdl->cgbi = 0; ibdi < pbdl->cgbiAlloc; ibdi++)
  1257. {
  1258. pbdi = &pbdl->rgbdi[ibdi];
  1259. if( pbdi && pbdi->pdidd )
  1260. {
  1261. /*
  1262. * Open the device
  1263. */
  1264. hf = CreateFile(pbdi->pdidd->DevicePath,
  1265. GENERIC_READ | GENERIC_WRITE,
  1266. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1267. 0, /* no SECURITY_ATTRIBUTES */
  1268. OPEN_EXISTING,
  1269. 0, /* attributes */
  1270. 0); /* template */
  1271. if(hf == INVALID_HANDLE_VALUE)
  1272. {
  1273. FreePpv(&pbdi->pdidd);
  1274. FreePpv(&pbdi->ptszId);
  1275. if(pbdi->hk)
  1276. {
  1277. RegCloseKey(pbdi->hk);
  1278. }
  1279. ZeroX( pbdi );
  1280. } else
  1281. {
  1282. pbdl->cgbi++;
  1283. CloseHandle(hf);
  1284. }
  1285. }
  1286. }
  1287. //re-order the existing devices, put them at the front of the hid list.
  1288. for(ibdi = 0; ibdi < pbdl->cgbi; ibdi++)
  1289. {
  1290. if( !pbdl->rgbdi[ibdi].pdidd )
  1291. {
  1292. int ibdi2;
  1293. //find the existing device from the biggest index in the hid list.
  1294. for( ibdi2 = pbdl->cgbiAlloc; ibdi2 >= ibdi+1; ibdi2-- )
  1295. {
  1296. if( pbdl->rgbdi[ibdi2].pdidd )
  1297. {
  1298. memcpy( &pbdl->rgbdi[ibdi], &pbdl->rgbdi[ibdi2], sizeof(BUSDEVICEINFO) );
  1299. ZeroX( pbdl->rgbdi[ibdi2] );
  1300. }
  1301. }
  1302. }
  1303. }
  1304. }
  1305. return;
  1306. }
  1307. /*****************************************************************************
  1308. *
  1309. * @doc EXTERNAL
  1310. *
  1311. * @func void | DIBus_BuildList |
  1312. *
  1313. * Builds the list of GAMEPORT/SERIALPORT devices.
  1314. *
  1315. * @parm BOOL | fForce |
  1316. *
  1317. * If nonzero, we force a rebuild of the GAMEPORT/SERIALPORT list.
  1318. * Otherwise, we rebuild only if the list hasn't
  1319. * been rebuilt recently.
  1320. *
  1321. *****************************************************************************/
  1322. #define MSREBUILDRATE 20000 /* Twenty seconds */
  1323. ULONG EXTERNAL
  1324. DIBus_BuildList( IN BOOL fForce )
  1325. {
  1326. HRESULT hres;
  1327. PBUSDEVICE pBusDevice;
  1328. ULONG cDevices;
  1329. int iBusType;
  1330. DWORD dwTickCount;
  1331. EnterProcI(DIBus_BuildList, (_ "u", fForce));
  1332. DllEnterCrit();
  1333. /*
  1334. * Decide whether or not to rebuild once (don't want to half rebuild)
  1335. */
  1336. dwTickCount = GetTickCount();
  1337. // Force implies a complete rebuild of the list.
  1338. if(fForce)
  1339. {
  1340. DIBus_FreeMemory();
  1341. }
  1342. DIHid_BuildHidList(fForce);
  1343. hres = S_OK;
  1344. for( cDevices = iBusType = 0x0, pBusDevice = g_pBusDevice;
  1345. iBusType < cA(g_pBusDevice);
  1346. iBusType++, pBusDevice++ )
  1347. {
  1348. PBUSDEVICELIST pbdl;
  1349. pbdl = pBusDevice->pbdl;
  1350. if( HidD_GetHidGuid && /* HID support */
  1351. ( fForce || /* Forcing rebuild, or */
  1352. pBusDevice->tmLastRebuild == 0 || /* Never built before, or */
  1353. dwTickCount - pBusDevice->tmLastRebuild > MSREBUILDRATE )
  1354. )
  1355. {
  1356. HDEVINFO hdev;
  1357. /* delete devices that disappeared since we last looked */
  1358. DIBus_CheckList(pbdl);
  1359. hdev = SetupDiGetClassDevs((LPGUID)pBusDevice->pcGuid, 0, 0,
  1360. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  1361. if(hdev != INVALID_HANDLE_VALUE)
  1362. {
  1363. /*
  1364. * There is no way to query the number of devices.
  1365. * You just have to keep incrementing until you run out.
  1366. *
  1367. * If we already have a pbdl, then re-use it. Else, create
  1368. * a new one. Alloc up to the minimum starting point.
  1369. */
  1370. if( pBusDevice->pbdl == NULL )
  1371. {
  1372. /*
  1373. * Prefix warns that we leak this memory (mb:34688) but
  1374. * we keep a reference in our global list so we can free
  1375. * the memory when we're done with it.
  1376. */
  1377. hres = AllocCbPpv(cbGdlCbdi(cgbiInit), &pBusDevice->pbdl );
  1378. if(SUCCEEDED(hres))
  1379. {
  1380. pbdl = pBusDevice->pbdl;
  1381. pbdl->cgbi = 0;
  1382. pbdl->cgbiAlloc = cgbiInit;
  1383. }
  1384. }
  1385. if( SUCCEEDED(hres) )
  1386. {
  1387. int idev;
  1388. /*
  1389. * To avoid infinite looping on
  1390. * internal *boo-boo's*, break on any
  1391. * error once we have tried more than
  1392. * cgbiMax devices, since that's the most
  1393. * GAMEPORT/SERIALPORT will ever give us.
  1394. */
  1395. for(idev = 0; idev < cgbiMax; idev++)
  1396. {
  1397. SP_DEVICE_INTERFACE_DATA did;
  1398. AssertF( pbdl->cgbi <= pbdl->cgbiAlloc);
  1399. /*
  1400. * Note, pnp.c doesn't initialize this so we have to
  1401. */
  1402. did.cbSize = cbX(did);
  1403. if(SetupDiEnumDeviceInterfaces(hdev, 0, (LPGUID)pBusDevice->pcGuid,
  1404. idev, &did))
  1405. {
  1406. if(DIBusDevice_BuildListEntry(hdev, &did, &g_pBusDevice[iBusType] ))
  1407. {
  1408. //pbdl->cgbi++;
  1409. } else
  1410. {
  1411. /* Skip erroneous items */
  1412. SquirtSqflPtszV(sqfl | sqflError,
  1413. TEXT("DIBus_BuildListEntry ")
  1414. TEXT("failed?"));
  1415. }
  1416. } else
  1417. if(GetLastError() == ERROR_NO_MORE_ITEMS)
  1418. {
  1419. break;
  1420. } else
  1421. {
  1422. /* Skip erroneous items */
  1423. SquirtSqflPtszV(sqfl | sqflError,
  1424. TEXT("SetupDiEnumDeviceInterface ")
  1425. TEXT("failed? le=%d"), GetLastError());
  1426. }
  1427. }
  1428. }
  1429. SetupDiDestroyDeviceInfoList(hdev);
  1430. pBusDevice->tmLastRebuild = GetTickCount();
  1431. }
  1432. }
  1433. if(pbdl) { cDevices += pbdl->cgbi; }
  1434. }
  1435. /* New gameport devices may be exposed. Pick them up too */
  1436. DIHid_BuildHidList(FALSE);
  1437. DllLeaveCrit();
  1438. ExitProc();
  1439. return (cDevices);
  1440. }
  1441. PBUSDEVICELIST EXTERNAL
  1442. pbdlFromGUID
  1443. (
  1444. IN PCGUID pcGuid
  1445. )
  1446. {
  1447. PBUSDEVICELIST pbdl_Found = NULL;
  1448. PBUSDEVICE pBusDevice;
  1449. int iBusType;
  1450. for( iBusType = 0x0, pBusDevice = g_pBusDevice;
  1451. iBusType < cA(g_pBusDevice);
  1452. iBusType++, pBusDevice++ )
  1453. {
  1454. if( IsEqualGUID(pBusDevice->pcGuid, pcGuid) )
  1455. {
  1456. pbdl_Found = pBusDevice->pbdl;
  1457. break;
  1458. }
  1459. }
  1460. return pbdl_Found;
  1461. }
  1462. /*****************************************************************************
  1463. *
  1464. * @doc INTERNAL
  1465. *
  1466. * @func HRESULT | DIBusDevice_ExposeEx |
  1467. *
  1468. * Attache a HID device to all available ports.
  1469. *
  1470. * @parm IN HANDLE | hf |
  1471. * Handle the the Gameport/SerialPort File object
  1472. *
  1473. * @parm IN OUT PBUS_REGDATA | pRegData |
  1474. * Gameport/Serialport specific data. The Handle to the opened device
  1475. * is returned in this structure
  1476. *
  1477. *
  1478. * @returns
  1479. * BOOL. True indicates success.
  1480. *
  1481. *****************************************************************************/
  1482. HRESULT EXTERNAL
  1483. DIBusDevice_ExposeEx
  1484. (
  1485. IN PBUSDEVICELIST pbdl,
  1486. IN PBUS_REGDATA pRegData
  1487. )
  1488. {
  1489. HRESULT hres = DIERR_DEVICENOTREG;
  1490. EnterProcI(DIBusDevice_ExposeEx, (_ "xx", pbdl, pRegData));
  1491. /*
  1492. * The return code a little strange for this function
  1493. * If the Expose succeeds for any gameport then
  1494. * we will return that error code.
  1495. * If the expose fails for all gameports,
  1496. * then we will return the amalgam of
  1497. * all the error codes.
  1498. */
  1499. if( pbdl->cgbi != 0x0 )
  1500. {
  1501. HRESULT hres1 = DIERR_DEVICENOTREG;
  1502. int ibdi;
  1503. hres = S_OK;
  1504. for( ibdi = 0x0; ibdi < pbdl->cgbi; ibdi++)
  1505. {
  1506. HRESULT hres0;
  1507. PBUSDEVICEINFO pbdi;
  1508. hres0 = DIERR_DEVICENOTREG;
  1509. pbdi = &(pbdl->rgbdi[ibdi]);
  1510. if( pbdi->fAttached == FALSE )
  1511. {
  1512. pbdi->fDeleteIfNotConnected = TRUE;
  1513. hres0 = DIBusDevice_Expose(pbdi, pRegData);
  1514. if( FAILED(hres0) )
  1515. {
  1516. hres |= hres0;
  1517. } else
  1518. {
  1519. hres1 = hres0;
  1520. }
  1521. } else {
  1522. hres = DIERR_DEVICEFULL;
  1523. }
  1524. }
  1525. if(SUCCEEDED(hres1))
  1526. {
  1527. hres = hres1;
  1528. }
  1529. }
  1530. ExitOleProc();
  1531. return hres;
  1532. }
  1533. /*****************************************************************************
  1534. *
  1535. * @doc INTERNAL
  1536. *
  1537. * @func HRESULT | DIBusDevice_GetTypeInfo |
  1538. *
  1539. * Gets typeinfo for bus device.
  1540. *
  1541. * @parm IN PCGUID | pcguid |
  1542. * GUID that identifies the gameport
  1543. *
  1544. * @parm OUT LPDIJOTYPEINFO | pjti |
  1545. * Typeinfo stuct filled in by this function
  1546. *
  1547. * @parm IN DWORD | fl |
  1548. * Flags that specify what fields to fill out.
  1549. *
  1550. * @returns
  1551. * HRESULT.
  1552. *
  1553. *****************************************************************************/
  1554. HRESULT EXTERNAL
  1555. DIBusDevice_GetTypeInfo
  1556. (
  1557. PCGUID pcguid,
  1558. LPDIJOYTYPEINFO pjti,
  1559. DWORD fl
  1560. )
  1561. {
  1562. HRESULT hres;
  1563. PBUSDEVICEINFO pbdi;
  1564. EnterProcI(DIBusDevice_GetTypeInfo, (_ "Gp", pcguid, pjti));
  1565. hres = E_FAIL;
  1566. DllEnterCrit();
  1567. if( NULL != ( pbdi = pbdiFromGUID(pcguid) ) )
  1568. {
  1569. DIPROPSTRING dips;
  1570. if(fl & DITC_REGHWSETTINGS)
  1571. {
  1572. pjti->hws.dwFlags = pbdi->pBusDevice->dwJOY_HWS_ISPORTBUS | JOY_HWS_AUTOLOAD ;
  1573. pjti->hws.dwNumButtons = MAKELONG( pbdi->idPort, 0x0 );
  1574. }
  1575. if( fl & DITC_CLSIDCONFIG )
  1576. {
  1577. pjti->clsidConfig = pbdi->guid;
  1578. }
  1579. if(fl & DITC_DISPLAYNAME)
  1580. {
  1581. if(FAILED( hres = DIPort_GetRegistryProperty(pbdi->ptszId, SPDRP_FRIENDLYNAME, &dips.diph) ) )
  1582. {
  1583. if( FAILED( hres = DIPort_GetRegistryProperty(pbdi->ptszId, SPDRP_DEVICEDESC, &dips.diph) ) )
  1584. {
  1585. SquirtSqflPtszV(sqfl | sqflError,
  1586. TEXT("%S: No device name | friendly name for gameport %d "),
  1587. s_szProc, pbdi->idPort);
  1588. }
  1589. }
  1590. if( SUCCEEDED(hres) )
  1591. {
  1592. /*
  1593. * Prefix warns (Wi:228282) that dips.wsz could be
  1594. * uninitialized however one of the above GetRegistryProperty
  1595. * functions has succeeded leaving a worst case of a NULL
  1596. * terminator having been copied there.
  1597. */
  1598. lstrcpyW(pjti->wszDisplayName, dips.wsz);
  1599. }
  1600. }
  1601. #ifndef WINNT
  1602. if(fl & DITC_CALLOUT)
  1603. {
  1604. ZeroX(pjti->wszCallout);
  1605. }
  1606. #endif
  1607. if(fl & DITC_HARDWAREID)
  1608. {
  1609. ZeroX(pjti->wszHardwareId);
  1610. }
  1611. if( fl & DITC_FLAGS1 )
  1612. {
  1613. pjti->dwFlags1 = 0x0;
  1614. }
  1615. hres = S_OK;
  1616. } else
  1617. {
  1618. hres = E_FAIL;
  1619. SquirtSqflPtszV(sqfl | sqflError,
  1620. TEXT("%S: GUID not a port GUID "),
  1621. s_szProc);
  1622. }
  1623. DllLeaveCrit();
  1624. ExitProcX(hres);
  1625. return hres;
  1626. }
  1627. HRESULT EXTERNAL DIPort_SnapTypes(LPWSTR *ppwszz)
  1628. {
  1629. LONG cDevices;
  1630. HRESULT hres = E_FAIL;
  1631. cDevices = DIBus_BuildList(FALSE);
  1632. if( cDevices)
  1633. {
  1634. DllEnterCrit();
  1635. hres = AllocCbPpv(cbCwch( cDevices * MAX_JOYSTRING) , ppwszz);
  1636. if( SUCCEEDED(hres) )
  1637. {
  1638. int iBusType, igdi;
  1639. PBUSDEVICE pBusDevice;
  1640. LPWSTR pwsz = *ppwszz;
  1641. for(iBusType = 0x0, pBusDevice = g_pBusDevice;
  1642. iBusType < 1;
  1643. iBusType++, pBusDevice++ )
  1644. {
  1645. PBUSDEVICEINFO pbdi;
  1646. for(igdi = 0, pbdi = pBusDevice->pbdl->rgbdi;
  1647. igdi < pBusDevice->pbdl->cgbi;
  1648. igdi++, pbdi++)
  1649. {
  1650. TCHAR tszGuid[MAX_JOYSTRING];
  1651. NameFromGUID(tszGuid, &pbdi->guid);
  1652. #ifdef UNICODE
  1653. lstrcpyW(pwsz, &tszGuid[ctchNamePrefix]);
  1654. pwsz += lstrlenW(pwsz) + 1;
  1655. #else
  1656. TToU(pwsz, cA(pwsz), &tszGuid[ctchNamePrefix]);
  1657. pwsz += lstrlenW(pwsz) + 1;
  1658. #endif
  1659. }
  1660. }
  1661. *pwsz = L'\0'; /* Make it ZZ */
  1662. }
  1663. DllLeaveCrit();
  1664. }
  1665. return hres;
  1666. }