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.

980 lines
29 KiB

  1. /*****************************************************************************
  2. *
  3. * PidInit.c
  4. * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  5. * Abstract:
  6. *
  7. * Initialization code .
  8. *
  9. *****************************************************************************/
  10. #include "pidpr.h"
  11. #define sqfl ( sqflInit )
  12. #define NudgeWorkerThread(thid) \
  13. PostThreadMessage(thid, WM_NULL, 0x0, (LPARAM)NULL)
  14. #pragma BEGIN_CONST_DATA
  15. static PIDUSAGE c_rgUsgPool[] =
  16. {
  17. MAKE_PIDUSAGE(SIMULTANEOUS_EFFECTS_MAX, FIELD_OFFSET(REPORTPOOL,uSimulEfMax)),
  18. MAKE_PIDUSAGE(RAM_POOL_SIZE, FIELD_OFFSET(REPORTPOOL,uRamPoolSz)),
  19. MAKE_PIDUSAGE(ROM_POOL_SIZE, FIELD_OFFSET(REPORTPOOL,uRomPoolSz)),
  20. MAKE_PIDUSAGE(ROM_EFFECT_BLOCK_COUNT, FIELD_OFFSET(REPORTPOOL,uRomETCount)),
  21. MAKE_PIDUSAGE(POOL_ALIGNMENT, FIELD_OFFSET(REPORTPOOL,uPoolAlign)),
  22. };
  23. static PIDUSAGE c_rgUsgPoolSz[] =
  24. {
  25. MAKE_PIDUSAGE(SET_CONSTANT_FORCE_REPORT, FIELD_OFFSET(SZPOOL, uSzConstant)),
  26. MAKE_PIDUSAGE(SET_ENVELOPE_REPORT, FIELD_OFFSET(SZPOOL, uSzEnvelope)),
  27. MAKE_PIDUSAGE(SET_CONDITION_REPORT, FIELD_OFFSET(SZPOOL, uSzCondition)),
  28. MAKE_PIDUSAGE(SET_CUSTOM_FORCE_REPORT, FIELD_OFFSET(SZPOOL, uSzCustom)),
  29. MAKE_PIDUSAGE(SET_PERIODIC_REPORT, FIELD_OFFSET(SZPOOL, uSzPeriodic)),
  30. MAKE_PIDUSAGE(SET_RAMP_FORCE_REPORT, FIELD_OFFSET(SZPOOL, uSzRamp)),
  31. MAKE_PIDUSAGE(SET_EFFECT_REPORT, FIELD_OFFSET(SZPOOL, uSzEffect)),
  32. MAKE_PIDUSAGE(CUSTOM_FORCE_DATA_REPORT, FIELD_OFFSET(SZPOOL, uSzCustomData)),
  33. };
  34. static PIDREPORT PoolSz =
  35. {
  36. HidP_Feature,
  37. HID_USAGE_PAGE_PID,
  38. HID_USAGE_PID_PARAMETER_BLOCK_SIZE,
  39. cbX(SZPOOL),
  40. cA(c_rgUsgPoolSz),
  41. c_rgUsgPoolSz
  42. };
  43. PIDREPORT g_PoolReport =
  44. {
  45. HidP_Feature,
  46. HID_USAGE_PAGE_PID,
  47. HID_USAGE_PID_POOL_REPORT,
  48. cbX(REPORTPOOL),
  49. cA(c_rgUsgPool),
  50. c_rgUsgPool
  51. };
  52. static PIDSUPPORT g_PoolSupport[] =
  53. {
  54. {PID_DEVICEMANAGED, PIDMAKEUSAGEDWORD(DEVICE_MANAGED_POOL), HID_BUTTON, HidP_Feature},
  55. {PID_SHAREDPARAM, PIDMAKEUSAGEDWORD(SHARED_PARAMETER_BLOCKS), HID_BUTTON, HidP_Feature},
  56. };
  57. #pragma END_CONST_DATA
  58. /*****************************************************************************
  59. *
  60. * PID_InitSharedMem
  61. *
  62. * Inits our Shared Memory
  63. *
  64. *****************************************************************************/
  65. HRESULT INTERNAL
  66. PID_InitSharedMem
  67. (
  68. IDirectInputEffectDriver *ped
  69. )
  70. {
  71. HRESULT hres = S_OK;
  72. CPidDrv *this = (CPidDrv *)ped;
  73. EnterProcI( PID_InitSharedMem, (_"x", ped));
  74. // Get hold of global memory to keep the EffectState
  75. if( SUCCEEDED(hres) )
  76. {
  77. UINT unitID;
  78. hres = DIERR_PID_NOTINITIALIZED;
  79. WaitForSingleObject(g_hmtxShared, INFINITE);
  80. for(unitID = 0; unitID < MAX_UNITS; unitID++)
  81. {
  82. GUID* pGuid = &g_pshmem->rgus[unitID].GuidInstance;
  83. #ifdef DEBUG
  84. TCHAR lpName[MAX_PATH];
  85. NameFromGUID(lpName, pGuid);
  86. SquirtSqflPtszV(sqfl | sqflVerbose,
  87. TEXT("%s:UnitId(%d): GUID %s"),
  88. s_tszProc, unitID, lpName );
  89. #endif
  90. if( IsEqualGUID(pGuid, &this->GuidInstance) )
  91. {
  92. this->iUnitStateOffset = (&g_pshmem->rgus[unitID] - (PUNITSTATE)g_pshmem);
  93. hres = S_OK;
  94. } else if( IsEqualGUID(pGuid, &GUID_NULL ) )
  95. {
  96. PUNITSTATE pUnitState;
  97. this->iUnitStateOffset = (&g_pshmem->rgus[unitID] - (PUNITSTATE)g_pshmem);
  98. pUnitState = (PUNITSTATE)(g_pshmem + this->iUnitStateOffset);
  99. pUnitState->GuidInstance = this->GuidInstance;
  100. pUnitState->nAlloc = 0x0;
  101. ZeroBuf(pUnitState->State,GLOBAL_EFFECT_MEMSZ );
  102. hres = S_OK;
  103. }
  104. if( SUCCEEDED(hres) )
  105. {
  106. break;
  107. }
  108. }
  109. if(SUCCEEDED(hres) )
  110. {
  111. PUNITSTATE pUnitState = (PUNITSTATE)(g_pshmem + this->iUnitStateOffset);
  112. PPIDMEM pGuard = pUnitState->Guard;
  113. INT_PTR iGuard1 = (PUCHAR)&pUnitState->Guard[0] - (PUCHAR)pUnitState, iGuard2 = (PUCHAR)&pUnitState->Guard[1] - (PUCHAR)pUnitState;
  114. pGuard->uOfSz = PIDMEM_OFSZ(0x0, 0x0 );
  115. pGuard->iNext = iGuard2;
  116. pGuard++;
  117. pGuard->uOfSz = PIDMEM_OFSZ(this->ReportPool.uRamPoolSz, 0x0);
  118. pGuard->iNext = iGuard1;
  119. pUnitState->nAlloc = 0x2;
  120. pUnitState->cEfDownloaded = (USHORT)this->ReportPool.uRomETCount;
  121. }
  122. ReleaseMutex(g_hmtxShared);
  123. if( FAILED(hres) )
  124. {
  125. SquirtSqflPtszV(sqfl | sqflError,
  126. TEXT("%s:FAIL Could not find free unitID"),
  127. s_tszProc );
  128. }
  129. }
  130. ExitOleProc();
  131. return hres;
  132. }
  133. /*****************************************************************************
  134. *
  135. * PID_InitScaling
  136. *
  137. * Inits Scaling Coefficients
  138. *
  139. *****************************************************************************/
  140. PID_InitScaling
  141. (
  142. IDirectInputEffectDriver *ped
  143. )
  144. {
  145. HRESULT hres = S_OK;
  146. CPidDrv *this = (CPidDrv *)ped;
  147. USHORT LinkCollection;
  148. UINT indx;
  149. EnterProc( PID_InitScaling, (_"x", ped));
  150. // Scaling Exponents and Offsets
  151. this->DiSEffectScale.dwSize = this->DiSEffectOffset.dwSize = sizeof(DIEFFECT); /* sizeof(DIEFFECT) */
  152. //this->DiSEffect.dwFlags /* DiEffect* */
  153. this->DiSEffectScale.dwDuration = DI_SECONDS ;/* Microseconds */
  154. this->DiSEffectScale.dwSamplePeriod = DI_SECONDS ;/* Microseconds */
  155. this->DiSEffectScale.dwGain = DI_FFNOMINALMAX;
  156. this->DiSEffectScale.dwTriggerButton = 0x0; /* or DIEB_NOTRIGGER */
  157. this->DiSEffectScale.dwTriggerRepeatInterval = DI_SECONDS; /* Microseconds */
  158. //this->DiSEffect.cAxes; /* Number of axes */
  159. //this->DiSEffect.rgdwAxes; /* Array of axes */
  160. //this->DiSEffect.rglDirection; /* Array of directions */
  161. //this->DiSEffect.lpEnvelope; /* Optional */
  162. //this->DiSEffect.cbTypeSpecificParams; /* Size of params */
  163. //this->DiSEffect.lpvTypeSpecificParams; /* Pointer to params */
  164. #if DIRECTINPUT_VERSION >= 0x600
  165. this->DiSEffectScale.dwStartDelay = DI_SECONDS; // Start delay
  166. #endif
  167. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Effect.UsagePage, g_Effect.Collection, 0x0, &LinkCollection )))
  168. {
  169. PID_ComputeScalingFactors(ped, &g_Effect, LinkCollection, &this->DiSEffectScale, this->DiSEffectScale.dwSize, &this->DiSEffectOffset, this->DiSEffectOffset.dwSize);
  170. }
  171. this->DiSEnvScale.dwSize = this->DiSEnvOffset.dwSize = sizeof(DIENVELOPE); /* sizeof(DIENVELOPE) */
  172. this->DiSEnvScale.dwAttackLevel = DI_FFNOMINALMAX;
  173. this->DiSEnvScale.dwAttackTime = DI_SECONDS; /* Microseconds */
  174. this->DiSEnvScale.dwFadeLevel = DI_FFNOMINALMAX;
  175. this->DiSEnvScale.dwFadeTime = DI_SECONDS; /* Microseconds */
  176. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Envelope.UsagePage, g_Envelope.Collection, 0x0, &LinkCollection)))
  177. {
  178. PID_ComputeScalingFactors(ped, &g_Envelope, LinkCollection, &this->DiSEnvScale, this->DiSEnvScale.dwSize, &this->DiSEnvOffset, this->DiSEnvOffset.dwSize);
  179. }
  180. this->DiSPeriodicScale.dwMagnitude = DI_FFNOMINALMAX;
  181. this->DiSPeriodicScale.lOffset = DI_FFNOMINALMAX;
  182. this->DiSPeriodicScale.dwPhase = 360 * DI_DEGREES;
  183. this->DiSPeriodicScale.dwPeriod = DI_SECONDS;
  184. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Periodic.UsagePage, g_Periodic.Collection, 0x0, &LinkCollection)))
  185. {
  186. PID_ComputeScalingFactors(ped, &g_Periodic, LinkCollection, &this->DiSPeriodicScale, cbX(this->DiSPeriodicScale), &this->DiSPeriodicOffset, cbX(this->DiSPeriodicOffset));
  187. }
  188. this->DiSRampScale.lStart =
  189. this->DiSRampScale.lEnd = DI_FFNOMINALMAX;
  190. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Ramp.UsagePage, g_Ramp.Collection, 0x0, &LinkCollection)))
  191. {
  192. PID_ComputeScalingFactors(ped, &g_Ramp, LinkCollection, &this->DiSRampScale, cbX(this->DiSRampScale), &this->DiSRampOffset, cbX(this->DiSRampOffset));
  193. }
  194. this->DiSCondScale.lOffset =
  195. this->DiSCondScale.lPositiveCoefficient =
  196. this->DiSCondScale.lNegativeCoefficient =
  197. this->DiSCondScale.dwPositiveSaturation =
  198. this->DiSCondScale.dwNegativeSaturation =
  199. this->DiSCondScale.lDeadBand = DI_FFNOMINALMAX;
  200. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Condition.UsagePage,g_Condition.Collection,0x0, &LinkCollection)))
  201. {
  202. PID_ComputeScalingFactors(ped, &g_Condition, LinkCollection, &this->DiSCondScale, cbX(this->DiSCondScale), &this->DiSCondOffset, cbX(this->DiSCondOffset));
  203. }
  204. this->DiSConstScale.lMagnitude = DI_FFNOMINALMAX;
  205. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Constant.UsagePage, g_Constant.Collection, 0x0, &LinkCollection)))
  206. {
  207. PID_ComputeScalingFactors(ped, &g_Constant, LinkCollection, &this->DiSConstScale,cbX(this->DiSConstScale), &this->DiSConstOffset,cbX(this->DiSConstOffset));
  208. }
  209. this->DiSCustomScale.dwSamplePeriod = DI_SECONDS;
  210. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Custom.UsagePage, g_Custom.Collection, 0x0, &LinkCollection)))
  211. {
  212. PID_ComputeScalingFactors(ped, &g_Custom, LinkCollection, &this->DiSCustomScale, cbX(this->DiSCustomScale), &this->DiSCustomOffset, cbX(this->DiSCustomOffset));
  213. }
  214. // Direction could be ordinals
  215. g_Direction.cbXData = cA(c_rgUsgOrdinals)*cbX(DWORD);
  216. g_Direction.cAPidUsage = cA(c_rgUsgOrdinals);
  217. g_Direction.rgPidUsage = c_rgUsgOrdinals;
  218. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_Direction.UsagePage, g_Direction.Collection, 0x0, &LinkCollection)))
  219. {
  220. HRESULT hres1;
  221. for(indx = 0x0; indx < MAX_ORDINALS; indx++)
  222. {
  223. this->DiSEffectAngleScale[indx] = 360 * DI_DEGREES;
  224. }
  225. hres1 = PID_ComputeScalingFactors(ped, &g_Direction, LinkCollection, &this->DiSEffectAngleScale[0], cbX(this->DiSEffectAngleScale), &this->DiSEffectAngleOffset[0], cbX(this->DiSEffectAngleOffset));
  226. // Direction could be angles
  227. if(hres1 == E_NOTIMPL )
  228. {
  229. g_Direction.cbXData = cA(c_rgUsgDirection)*cbX(DWORD);
  230. g_Direction.cAPidUsage = cA(c_rgUsgDirection);
  231. g_Direction.rgPidUsage = c_rgUsgDirection;
  232. // Reset the nominal values
  233. for(indx = 0x0; indx < MAX_ORDINALS; indx++)
  234. {
  235. this->DiSEffectAngleScale[indx] = 360 * DI_DEGREES;
  236. }
  237. hres1 = PID_ComputeScalingFactors(ped, &g_Direction, LinkCollection, &this->DiSEffectAngleScale[0], cbX(this->DiSEffectAngleScale), &this->DiSEffectAngleOffset[0], cbX(this->DiSEffectAngleOffset));
  238. if( hres1 == E_NOTIMPL )
  239. {
  240. // Could be direction Vectors
  241. // Not sure how vectors are implemented in PID
  242. SquirtSqflPtszV(sqfl | sqflError,
  243. TEXT("%s:FAIL Cannot understand the direction collection\n")
  244. TEXT("\t\t Supported usages are {Rx, Ry, Rz} or {Ordinals} \n"),
  245. s_tszProc );
  246. }
  247. }
  248. }
  249. for(indx = 0x0; indx < MAX_ORDINALS; indx++)
  250. {
  251. this->DiSCustomSample[indx] = DI_FFNOMINALMAX;
  252. }
  253. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_CustomSample.UsagePage, g_CustomSample.Collection, 0x0, &LinkCollection)) )
  254. {
  255. //get the custom data for each axis
  256. USHORT cAValCaps = 0x1;
  257. USAGE UsagePage;
  258. USAGE Usage[3] = {HID_USAGE_GENERIC_X, HID_USAGE_GENERIC_Y, HID_USAGE_GENERIC_Z};
  259. NTSTATUS ntSt[3];
  260. int nAxis = 0;
  261. UsagePage = HID_USAGE_PAGE_GENERIC;
  262. for (nAxis = 0; nAxis < 3; nAxis ++)
  263. {
  264. cAValCaps = 0x1;
  265. ntSt[nAxis] = HidP_GetSpecificValueCaps
  266. (
  267. g_CustomSample.HidP_Type,
  268. UsagePage,
  269. LinkCollection,
  270. Usage[nAxis],
  271. &this->customCaps[nAxis],
  272. &cAValCaps,
  273. this->ppd
  274. );
  275. if (FAILED(ntSt[nAxis]))
  276. {
  277. this->customCaps[nAxis].BitSize = 0;
  278. this->customCaps[nAxis].LogicalMin = this->customCaps[nAxis].LogicalMax = 0;
  279. }
  280. }
  281. if ((FAILED(ntSt[0])) && (FAILED(ntSt[1])) && (FAILED(ntSt[2])))
  282. {
  283. SquirtSqflPtszV(sqfl | sqflError,
  284. TEXT("%s:FAIL Cannot understand the download force sample collection\n")
  285. TEXT("\t\t Supported usages are {X, Y, Z} \n"),
  286. s_tszProc );
  287. }
  288. //get how many bytes of custom data can send at a time
  289. if (SUCCEEDED(PID_GetLinkCollectionIndex(ped, g_CustomData.UsagePage, g_CustomData.Collection, 0x0, &LinkCollection )))
  290. {
  291. USAGE UsageData = HID_USAGE_PID_CUSTOM_FORCE_DATA;
  292. NTSTATUS ntst;
  293. cAValCaps = 0x1;
  294. UsagePage = HID_USAGE_PAGE_PID;
  295. ntst = HidP_GetSpecificValueCaps
  296. (
  297. g_CustomData.HidP_Type,
  298. UsagePage,
  299. LinkCollection,
  300. UsageData,
  301. &this->customDataCaps,
  302. &cAValCaps,
  303. this->ppd
  304. );
  305. if (FAILED(ntst))
  306. {
  307. this->customDataCaps.BitSize = 0;
  308. }
  309. }
  310. }
  311. ExitOleProc();
  312. return hres;
  313. }
  314. /*****************************************************************************
  315. *
  316. * DIEnumProc
  317. *
  318. * Enum and cache FF device objects
  319. *
  320. *****************************************************************************/
  321. BOOL CALLBACK
  322. DIEnumProc(LPCDIDEVICEOBJECTINSTANCE pinst, LPVOID pv)
  323. {
  324. BOOL frc = DIENUM_CONTINUE;
  325. HRESULT hres = S_OK;
  326. CPidDrv* this = (CPidDrv*) pv;
  327. EnterProc( DIEnumProc, (_"xx", pinst, pv ));
  328. if( (pinst->dwFlags & DIDOI_FFACTUATOR )
  329. ||(pinst->dwFlags & DIDOI_FFEFFECTTRIGGER ))
  330. {
  331. AssertF(this->cFFObj <= this->cFFObjMax);
  332. if( this->cFFObj == this->cFFObjMax )
  333. {
  334. /* Grow by doubling */
  335. this->cFFObjMax = max(PIDALLOC_INIT, 2*this->cFFObjMax);
  336. hres = ReallocCbPpv(this->cFFObjMax * cbX(DIUSAGEANDINST), &this->rgFFUsageInst);
  337. }
  338. if( SUCCEEDED(hres) )
  339. {
  340. PDIUSAGEANDINST pdiUI = this->rgFFUsageInst + this->cFFObj;
  341. pdiUI->dwUsage = DIMAKEUSAGEDWORD(pinst->wUsagePage, pinst->wUsage);
  342. pdiUI->dwType = pinst->dwType ;
  343. }
  344. this->cFFObj++;
  345. }
  346. if( FAILED(hres) )
  347. {
  348. frc = DIENUM_STOP;
  349. }
  350. ExitProcF(frc);
  351. return frc;
  352. }
  353. STDMETHODIMP
  354. PID_InitFFAttributes
  355. (
  356. IDirectInputEffectDriver *ped
  357. )
  358. {
  359. HRESULT hres = S_OK;
  360. CPidDrv *this = (CPidDrv *)ped;
  361. EnterProcI( PID_Init, (_"x", ped));
  362. // We cannot call this function at init, because DInput call us before the device
  363. // has been completely initialized.
  364. if( this->cFFObj )
  365. {
  366. hres = S_FALSE; // Already initialized
  367. } else
  368. {
  369. // We need to get the Usage & UsagePage
  370. // for device objects marked as
  371. // FF Triggers and FF Actuators
  372. //If we are called with DInput version not larger than 7, load dinput.dll w/ IID_DirectInput7
  373. //else load dinput8.dll.
  374. if (this->dwDirectInputVersion <= 0x0700)
  375. {
  376. HINSTANCE hinst = LoadLibrary(TEXT("dinput.dll"));
  377. if (hinst)
  378. {
  379. typedef HRESULT ( WINAPI * DIRECTINPUTCREATEEX) ( HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter);
  380. DIRECTINPUTCREATEEX _DirectInputCreateEx;
  381. LPDIRECTINPUT lpDI;
  382. _DirectInputCreateEx = (DIRECTINPUTCREATEEX)GetProcAddress(hinst, "DirectInputCreateEx");
  383. if (_DirectInputCreateEx)
  384. {
  385. hres = _DirectInputCreateEx(g_hinst, this->dwDirectInputVersion, &IID_IDirectInput7, &lpDI, NULL );
  386. if( SUCCEEDED(hres) )
  387. {
  388. LPDIRECTINPUTDEVICE pdid;
  389. hres = IDirectInput_CreateDevice(lpDI, &this->GuidInstance, &pdid, NULL);
  390. /* Create the device object */
  391. if( SUCCEEDED(hres) )
  392. {
  393. hres = IDirectInputDevice2_EnumObjects
  394. (
  395. pdid,
  396. DIEnumProc,
  397. ped,
  398. DIDFT_ALL //DIDFT_FFEFFECTTRIGGER | DIDFT_FFACTUATOR
  399. );
  400. IDirectInput_Release(pdid);
  401. }
  402. IDirectInput_Release(lpDI);
  403. }
  404. }
  405. else //!DirectInputCreateEx
  406. {
  407. //Something is horribly wrong here if we can't find the Create fn!
  408. //Return the same error code that CDIDev_CreateEffectDriver() returns if there was an error loading FF driver
  409. hres = DIERR_UNSUPPORTED;
  410. }
  411. FreeLibrary(hinst);
  412. }
  413. else // !hinst
  414. {
  415. //Something is horribly wrong here if we came through Dinput but can't load it!
  416. //Return the same error code that CDIDev_CreateEffectDriver() returns if there was an error loading FF driver
  417. hres = DIERR_UNSUPPORTED;
  418. }
  419. }
  420. else
  421. {
  422. HINSTANCE hinst = LoadLibrary(TEXT("dinput8.dll"));
  423. if (hinst)
  424. {
  425. typedef HRESULT ( WINAPI * DIRECTINPUT8CREATE) ( HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter);
  426. DIRECTINPUT8CREATE _DirectInput8Create;
  427. LPDIRECTINPUT8 lpDI;
  428. _DirectInput8Create = (DIRECTINPUT8CREATE)GetProcAddress(hinst, "DirectInput8Create");
  429. if (_DirectInput8Create)
  430. {
  431. hres = _DirectInput8Create(g_hinst, this->dwDirectInputVersion, &IID_IDirectInput8, &lpDI, NULL );
  432. if( SUCCEEDED(hres) )
  433. {
  434. LPDIRECTINPUTDEVICE8 pdid;
  435. hres = IDirectInput8_CreateDevice(lpDI, &this->GuidInstance, &pdid, NULL);
  436. /* Create the device object */
  437. if( SUCCEEDED(hres) )
  438. {
  439. hres = IDirectInputDevice8_EnumObjects
  440. (
  441. pdid,
  442. DIEnumProc,
  443. ped,
  444. DIDFT_ALL //DIDFT_FFEFFECTTRIGGER | DIDFT_FFACTUATOR
  445. );
  446. IDirectInput_Release(pdid);
  447. }
  448. IDirectInput_Release(lpDI);
  449. }
  450. }
  451. else //!DirectInput8Create
  452. {
  453. //Something is horribly wrong here if we can't find the Create fn!
  454. //Return the same error code that CDIDev_CreateEffectDriver() returns if there was an error loading FF driver
  455. hres = DIERR_UNSUPPORTED;
  456. }
  457. FreeLibrary(hinst);
  458. }
  459. else // !hinst
  460. {
  461. //Something is horribly wrong here if we came through Dinput but can't load it!
  462. //Return the same error code that CDIDev_CreateEffectDriver() returns if there was an error loading FF driver
  463. hres = DIERR_UNSUPPORTED;
  464. }
  465. }
  466. }
  467. ExitOleProc();
  468. return hres;
  469. }
  470. /*****************************************************************************
  471. *
  472. * PID_Init
  473. *
  474. * Inits PID device
  475. *
  476. *****************************************************************************/
  477. STDMETHODIMP
  478. PID_Init
  479. (
  480. IDirectInputEffectDriver *ped
  481. )
  482. {
  483. HRESULT hres = S_OK;
  484. CPidDrv *this = (CPidDrv *)ped;
  485. USHORT LinkCollection;
  486. EnterProcI( PID_Init, (_"x", ped));
  487. PID_CreateUsgTxt();
  488. AssertF( this->hdev == INVALID_HANDLE_VALUE );
  489. if( SUCCEEDED(hres) )
  490. {
  491. this->hdev = CreateFile(this->tszDeviceInterface,
  492. GENERIC_READ | GENERIC_WRITE,
  493. FILE_SHARE_READ | FILE_SHARE_WRITE,
  494. 0, /* no SECURITY_ATTRIBUTES */
  495. OPEN_EXISTING,
  496. 0x0, /* attributes */
  497. 0); /* template */
  498. if( this->hdev == INVALID_HANDLE_VALUE )
  499. {
  500. hres = E_HANDLE;
  501. SquirtSqflPtszV(sqfl | sqflError,
  502. TEXT("%s:FAIL CreateFile"),
  503. s_tszProc );
  504. }
  505. }
  506. if( SUCCEEDED(hres) )
  507. {
  508. // Get all the HID goo
  509. if( HidD_GetAttributes(this->hdev, &this->attr) &&
  510. HidD_GetPreparsedData(this->hdev, &this->ppd) &&
  511. SUCCEEDED(HidP_GetCaps(this->ppd, &this->caps)) )
  512. {
  513. // Success
  514. } else
  515. {
  516. SquirtSqflPtszV(sqfl | sqflError,
  517. TEXT("%s: FAIL HID init "),
  518. s_tszProc );
  519. hres = DIERR_PID_NOTINITIALIZED;
  520. }
  521. }
  522. if( SUCCEEDED(hres) )
  523. {
  524. // Get collection info
  525. hres = AllocCbPpv(cbX(*this->pLinkCollection) * this->caps.NumberLinkCollectionNodes,
  526. &this->pLinkCollection);
  527. if( SUCCEEDED(hres) && (this->pLinkCollection != NULL) )
  528. {
  529. ULONG cALinkCollection=this->caps.NumberLinkCollectionNodes;
  530. hres = HidP_GetLinkCollectionNodes
  531. (
  532. this->pLinkCollection,
  533. &cALinkCollection,
  534. this->ppd
  535. );
  536. }
  537. }
  538. if(SUCCEEDED(hres) )
  539. {
  540. UINT indx;
  541. this->cbReport[HidP_Input] = this->caps.InputReportByteLength;
  542. this->cbReport[HidP_Output] = this->caps.OutputReportByteLength;
  543. this->cbReport[HidP_Feature] = this->caps.FeatureReportByteLength;
  544. //write reports are output reports
  545. for( indx = 0x0; indx < MAX_BLOCKS; indx++ )
  546. {
  547. this->cbWriteReport[indx] = this->caps.OutputReportByteLength;
  548. }
  549. for( indx = 0x0; indx < HidP_Max; indx++ )
  550. {
  551. hres = AllocCbPpv(this->cbReport[indx], &this->pReport[indx]);
  552. if( FAILED(hres) )
  553. {
  554. break;
  555. }
  556. }
  557. for( indx = 0x0; indx < MAX_BLOCKS; indx++ )
  558. {
  559. hres = AllocCbPpv(this->cbWriteReport[indx], &this->pWriteReport[indx]);
  560. if( FAILED(hres) )
  561. {
  562. break;
  563. }
  564. }
  565. }
  566. if( SUCCEEDED(hres) )
  567. {
  568. hres = PID_InitRegistry(ped);
  569. }
  570. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped,g_PoolReport.UsagePage,g_PoolReport.Collection,0x0,&LinkCollection)))
  571. {
  572. PUCHAR pReport = this->pReport[g_PoolReport.HidP_Type];
  573. UINT cbReport = this->cbReport[g_PoolReport.HidP_Type];
  574. PID_GetReport
  575. (ped,
  576. &g_PoolReport,
  577. LinkCollection,
  578. pReport,
  579. cbReport
  580. );
  581. PID_ParseReport
  582. (
  583. ped,
  584. &g_PoolReport,
  585. LinkCollection,
  586. &this->ReportPool,
  587. cbX(this->ReportPool),
  588. pReport,
  589. cbReport
  590. );
  591. }
  592. SquirtSqflPtszV(sqfl | sqflVerbose,
  593. TEXT("%s:RamPoolSz:0x%x"),
  594. s_tszProc, this->ReportPool.uRamPoolSz );
  595. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped,PoolSz.UsagePage,PoolSz.Collection,0x0,&LinkCollection)) )
  596. {
  597. PUCHAR pReport = this->pReport[PoolSz.HidP_Type];
  598. UINT cbReport = this->cbReport[PoolSz.HidP_Type];
  599. PID_GetReport
  600. (ped,
  601. &PoolSz,
  602. LinkCollection,
  603. pReport,
  604. cbReport
  605. );
  606. PID_ParseReport
  607. (
  608. ped,
  609. &PoolSz,
  610. LinkCollection,
  611. &this->SzPool,
  612. cbX(this->SzPool),
  613. pReport,
  614. cbReport
  615. );
  616. }
  617. PID_Support(ped, cA(g_PoolSupport), g_PoolSupport, &this->uDeviceManaged);
  618. // Determine max number of parameter blocks per effect ?
  619. if( SUCCEEDED(hres) )
  620. {
  621. USHORT LinkCollection;
  622. hres = PID_GetLinkCollectionIndex(ped, HID_USAGE_PAGE_PID, HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_OFFSET, 0x0, &LinkCollection );
  623. if( SUCCEEDED(hres) )
  624. {
  625. USHORT cAValCaps;
  626. cAValCaps = 0x0;
  627. HidP_GetSpecificValueCaps
  628. (
  629. HidP_Output,
  630. HID_USAGE_PAGE_ORDINALS,
  631. LinkCollection,
  632. 0x0,
  633. NULL,
  634. &cAValCaps,
  635. this->ppd
  636. );
  637. this->cMaxParameters = cAValCaps;
  638. } else
  639. {
  640. this->cMaxParameters = 0x2;
  641. hres = S_OK;
  642. }
  643. }
  644. if( SUCCEEDED(hres))
  645. {
  646. hres = PID_InitSharedMem(ped);
  647. }
  648. if( SUCCEEDED(hres ) )
  649. {
  650. hres = PID_InitScaling(ped);
  651. }
  652. if( SUCCEEDED(hres) )
  653. {
  654. // Determine Max effects that can be downloaded to the device
  655. HIDP_VALUE_CAPS ValCaps;
  656. USHORT cAValCaps = 0x1;
  657. USAGE UsagePage = DIGETUSAGEPAGE(g_BlockIndex.rgPidUsage[0].dwUsage);
  658. USAGE Usage = DIGETUSAGE(g_BlockIndex.rgPidUsage[0].dwUsage);
  659. hres = HidP_GetSpecificValueCaps
  660. (
  661. g_BlockIndex.HidP_Type,
  662. UsagePage,
  663. 0x0,
  664. Usage,
  665. &ValCaps,
  666. &cAValCaps,
  667. this->ppd
  668. );
  669. if( SUCCEEDED(hres) || ( hres == HIDP_STATUS_BUFFER_TOO_SMALL ) )
  670. {
  671. hres = S_OK;
  672. this->cMaxEffects = (USHORT) ( ValCaps.PhysicalMax - ValCaps.PhysicalMin );
  673. } else
  674. {
  675. SquirtSqflPtszV(sqfl | sqflError,
  676. TEXT("%s: FAIL HidP_GetValCaps for (%x %x:%s) "),
  677. s_tszProc , UsagePage, Usage, PIDUSAGETXT(UsagePage,Usage) );
  678. }
  679. }
  680. this->cMaxEffects = (USHORT)min(this->cMaxEffects,
  681. GLOBAL_EFFECT_MEMSZ / ((FIELD_OFFSET(EFFECTSTATE,PidMem)) + this->cMaxParameters*cbX(PIDMEM)) );
  682. if( this->ReportPool.uSimulEfMax == 0x0 )
  683. {
  684. this->ReportPool.uSimulEfMax = 0xff;
  685. SquirtSqflPtszV(sqfl | sqflError,
  686. TEXT("%s: FAIL HID dwSimulEfMax == 0x0 defaults to %d "),
  687. s_tszProc, this->cMaxEffects );
  688. }
  689. if( SUCCEEDED(hres) )
  690. {
  691. TCHAR tsz[MAX_PATH];
  692. AssertF(this->hThread == 0x0 );
  693. AssertF(this->hWrite == 0x0);
  694. AssertF(this->hWriteComplete == 0x0);
  695. if( GetModuleFileName(g_hinst, tsz, cA(tsz))
  696. &&LoadLibrary(tsz) == g_hinst)
  697. {
  698. InterlockedIncrement(&this->cThreadRef);
  699. AssertF(this->cThreadRef == 0x1 );
  700. AssertF(this->hThread == 0x0 );
  701. this->hWrite = CreateEvent(NULL, FALSE, FALSE, NULL);
  702. if (this->hWrite == 0x0)
  703. {
  704. goto event_thread_error;
  705. }
  706. this->hWriteComplete = CreateEvent(NULL, TRUE, TRUE, NULL);
  707. if (this->hWriteComplete == 0x0)
  708. {
  709. goto event_thread_error;
  710. }
  711. this->hThread= CreateThread(0, 0, (LPTHREAD_START_ROUTINE)PID_ThreadProc, this,
  712. 0, &this->idThread);
  713. if (this->hThread == 0x0)
  714. {
  715. event_thread_error:;
  716. //close the event handles
  717. if (this->hWrite != 0x0)
  718. {
  719. CloseHandle(this->hWrite);
  720. this->hWrite = 0x0;
  721. }
  722. if (this->hWriteComplete != 0x0)
  723. {
  724. CloseHandle(this->hWriteComplete);
  725. this->hWriteComplete = 0x0;
  726. }
  727. hres = DIERR_PID_NOTINITIALIZED;
  728. FreeLibrary(g_hinst);
  729. InterlockedDecrement(&this->cThreadRef);
  730. }
  731. }
  732. }
  733. ExitOleProc();
  734. return hres;
  735. }
  736. /*****************************************************************************
  737. *
  738. * PID_Finalize
  739. *
  740. * Destroys PID device specific memory
  741. *
  742. *****************************************************************************/
  743. STDMETHODIMP
  744. PID_Finalize
  745. (
  746. IDirectInputEffectDriver *ped
  747. )
  748. {
  749. HRESULT hres = S_OK;
  750. CPidDrv *this = (CPidDrv *)ped;
  751. HANDLE hdev;
  752. UINT indx;
  753. EnterProc( PID_Finalize, (_"x", ped));
  754. DllEnterCrit();
  755. // Assasinate the thread
  756. InterlockedDecrement(&this->cThreadRef);
  757. AssertF(this->cThreadRef == 0x0 );
  758. // Wait for the thread to die before we go about releasing
  759. // memory
  760. do
  761. {
  762. DWORD dwWait;
  763. NudgeWorkerThread(this->idThread);
  764. Sleep(0);
  765. dwWait = WaitForSingleObject(this->hThread, 500 ) ;
  766. if( WAIT_TIMEOUT == dwWait)
  767. {
  768. SquirtSqflPtszV(sqfl | sqflError,
  769. TEXT("%s: Waiting for worker Thread %d to die"),
  770. s_tszProc,this->idThread );
  771. }
  772. //if didn't timeout, and thread didn't die, then we can get into an infinite loop.
  773. //so close the handle.
  774. if ((WAIT_ABANDONED == dwWait) || (WAIT_FAILED == dwWait))
  775. {
  776. if( this->hdevOvrlp != INVALID_HANDLE_VALUE )
  777. {
  778. HANDLE hdevOvr;
  779. hdevOvr = this->hdevOvrlp;
  780. this->hdevOvrlp = INVALID_HANDLE_VALUE;
  781. CancelIo_(hdevOvr);
  782. Sleep(0);
  783. CloseHandle(hdevOvr);
  784. }
  785. AssertF(this->hdevOvrlp == INVALID_HANDLE_VALUE);
  786. }
  787. }while( this->hdevOvrlp != INVALID_HANDLE_VALUE );
  788. // Close the handle
  789. if( this->hdev != INVALID_HANDLE_VALUE)
  790. {
  791. hdev = this->hdev;
  792. this->hdev = INVALID_HANDLE_VALUE;
  793. CloseHandle(hdev);
  794. }
  795. // Free PreParseData
  796. if( this->ppd )
  797. {
  798. HidD_FreePreparsedData(this->ppd);
  799. this->ppd = NULL;
  800. }
  801. // Free HIDP_VALUE_CAPS data
  802. FreePpv(&this->rgFFUsageInst);
  803. FreePpv(&this->pLinkCollection);
  804. for(indx = 0x0; indx < HidP_Max; indx++ )
  805. {
  806. FreePpv(&this->pReport[indx]);
  807. }
  808. for(indx = 0x0; indx < MAX_BLOCKS; indx++ )
  809. {
  810. FreePpv(&this->pWriteReport[indx]);
  811. }
  812. DllLeaveCrit();
  813. ExitOleProc();
  814. return hres;
  815. }