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.

1294 lines
41 KiB

  1. /*****************************************************************************
  2. *
  3. * PidEff.c
  4. * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  5. *
  6. * Abstract:
  7. *
  8. * Download PID Effect Block.
  9. *
  10. *****************************************************************************/
  11. #include "pidpr.h"
  12. #define sqfl ( sqflEff )
  13. #pragma BEGIN_CONST_DATA
  14. /*
  15. * The structure c_rgUsgEffects, aids in translating elements in the DIEFFECT
  16. * structure to PID usages
  17. */
  18. static PIDUSAGE c_rgUsgEffect[] =
  19. {
  20. MAKE_PIDUSAGE(DURATION, FIELD_OFFSET(DIEFFECT,dwDuration) ),
  21. MAKE_PIDUSAGE(SAMPLE_PERIOD, FIELD_OFFSET(DIEFFECT,dwSamplePeriod) ),
  22. MAKE_PIDUSAGE(GAIN, FIELD_OFFSET(DIEFFECT,dwGain) ),
  23. MAKE_PIDUSAGE(TRIGGER_BUTTON, FIELD_OFFSET(DIEFFECT,dwTriggerButton) ),
  24. MAKE_PIDUSAGE(TRIGGER_REPEAT_INTERVAL,FIELD_OFFSET(DIEFFECT,dwTriggerRepeatInterval) ),
  25. #if DIRECTINPUT_VERSION >= 0x600
  26. MAKE_PIDUSAGE(START_DELAY ,FIELD_OFFSET(DIEFFECT,dwStartDelay)),
  27. #endif
  28. };
  29. /*
  30. * g_Effect provides context to the c_rgUsgEffect struct
  31. */
  32. PIDREPORT g_Effect =
  33. {
  34. HidP_Output, // Effect Blocks can only be output reports
  35. HID_USAGE_PAGE_PID, // Usage Page
  36. HID_USAGE_PID_SET_EFFECT_REPORT, // Collection
  37. cbX(DIEFFECT), // Size of incoming data
  38. cA(c_rgUsgEffect), // number of elements in c_rgUsgEffect
  39. c_rgUsgEffect // how elements of DIEFFECT are translated to PID
  40. };
  41. /*
  42. * Effect block index to PID usage
  43. */
  44. static PIDUSAGE c_rgUsgBlockIndex[] =
  45. {
  46. MAKE_PIDUSAGE(EFFECT_BLOCK_INDEX, 0x0 ),
  47. };
  48. /*
  49. * For some PID transactions block index is output report
  50. */
  51. PIDREPORT g_BlockIndex =
  52. {
  53. HidP_Output, // Report Type
  54. HID_USAGE_PAGE_PID, // Usage Page
  55. 0x0, // Any collection
  56. cbX(DWORD), // size of incoming data
  57. cA(c_rgUsgBlockIndex), // translation table for effect block index to PID usages
  58. c_rgUsgBlockIndex
  59. };
  60. /*
  61. * In the PID state report, block index is an input report
  62. */
  63. PIDREPORT g_BlockIndexIN =
  64. {
  65. HidP_Input,
  66. HID_USAGE_PAGE_PID,
  67. HID_USAGE_PID_STATE_REPORT,
  68. cbX(DWORD),
  69. cA(c_rgUsgBlockIndex),
  70. c_rgUsgBlockIndex
  71. };
  72. //CAssertF(MAX_ORDINALS == cA(c_rgUsgOrdinals));
  73. PIDREPORT g_TypeSpBlockOffset =
  74. {
  75. HidP_Output, // For PID ordinals output reports
  76. HID_USAGE_PAGE_PID, // Usage Page
  77. HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_OFFSET,
  78. cA(c_rgUsgOrdinals)*cbX(DWORD), // sizeof incoming data
  79. cA(c_rgUsgOrdinals), // number of elements
  80. c_rgUsgOrdinals // translation table
  81. };
  82. #pragma END_CONST_DATA
  83. PIDREPORT g_Direction =
  84. {
  85. HidP_Output, // For PID ordinals output reports
  86. HID_USAGE_PAGE_PID, // Usage Page
  87. HID_USAGE_PID_DIRECTION,
  88. 0x0,
  89. 0x0,
  90. NULL
  91. };
  92. /*****************************************************************************
  93. *
  94. * hresFinddwUsageFromdwFlags
  95. *
  96. * Given the flags for a DEVICEOBJECTINSTANCE, find the usage and usage page
  97. * On init we enum the device and cache the
  98. * DeviceObjects marked as actuators and Effect Triggers.
  99. *
  100. *****************************************************************************/
  101. HRESULT
  102. hresFinddwUsageFromdwFlags
  103. (
  104. IDirectInputEffectDriver *ped,
  105. DWORD dwFlags,
  106. DWORD *pdwUsage
  107. )
  108. {
  109. HRESULT hres = S_OK;
  110. CPidDrv *this = (CPidDrv *)ped;
  111. EnterProcI( PID_hresFinddwUsageFromdwFlags, (_"xxx", ped, dwFlags, pdwUsage ));
  112. // Init FF attributes
  113. hres = PID_InitFFAttributes(ped);
  114. if( SUCCEEDED(hres) )
  115. {
  116. /* Better be a FF object ( actuator / Trigger ) */
  117. if( dwFlags & DIDFT_FFACTUATOR
  118. || dwFlags & DIDFT_FFEFFECTTRIGGER )
  119. {
  120. hres = S_OK;
  121. } else
  122. {
  123. SquirtSqflPtszV(sqfl | sqflError,
  124. TEXT("%s:FAIL dwFlags(0x%x) not FFACTUATOR | FFEFFECTTRIGGER "),
  125. s_tszProc, dwFlags );
  126. hres = E_UNEXPECTED;
  127. }
  128. if( SUCCEEDED(hres) )
  129. {
  130. UINT cFFObj;
  131. hres = E_NOTIMPL;
  132. /* Loop through the all the objects we found during enum */
  133. for(cFFObj = 0x0;
  134. cFFObj < this->cFFObj;
  135. cFFObj++ )
  136. {
  137. PDIUSAGEANDINST pdiUI = this->rgFFUsageInst + cFFObj;
  138. if( pdiUI->dwType == dwFlags )
  139. {
  140. *pdwUsage = pdiUI->dwUsage;
  141. hres = S_OK;
  142. break;
  143. }
  144. }
  145. }
  146. }
  147. if( FAILED(hres) )
  148. {
  149. SquirtSqflPtszV(sqfl | sqflError,
  150. TEXT("%s:FAIL No mapping for dwFlags(0x%x) "),
  151. s_tszProc, dwFlags );
  152. }
  153. ExitOleProc();
  154. return hres;
  155. }
  156. /*****************************************************************************
  157. *
  158. * PID_NewEffectIndex
  159. *
  160. * Gets a new effect index.
  161. *
  162. * For host managed devices, we assign an unused effect ID.
  163. * For device managed, we get the effectID from the device
  164. *
  165. *****************************************************************************/
  166. STDMETHODIMP
  167. PID_NewEffectIndex
  168. (
  169. IDirectInputEffectDriver *ped,
  170. LPDIEFFECT peff,
  171. DWORD dwEffectId,
  172. PDWORD pdwEffect
  173. )
  174. {
  175. CPidDrv *this = (CPidDrv *)ped;
  176. HRESULT hres;
  177. USHORT dwEffect;
  178. EnterProcI(PID_NewEffectIndex, (_"xx", this, pdwEffect));
  179. AssertF(*pdwEffect == 0);
  180. // Default assumption is that the device is full.
  181. hres = DIERR_DEVICEFULL;
  182. if( this->uDeviceManaged & PID_DEVICEMANAGED )
  183. {
  184. PVOID pReport;
  185. UINT cbReport;
  186. USHORT LinkCollection = 0x0;
  187. USHORT TLinkCollection = 0x0;
  188. UINT nUsages = 0x1;
  189. USAGE Usage;
  190. USAGE Collection = HID_USAGE_PID_CREATE_NEW_EFFECT;
  191. USAGE UsagePage;
  192. HIDP_REPORT_TYPE HidP_Type = HidP_Feature;
  193. cbReport = this->cbReport[HidP_Type];
  194. pReport = this->pReport[HidP_Type];
  195. ZeroBuf(pReport, cbReport);
  196. // Usage and Usage page determine type of new effect
  197. Usage = DIGETUSAGE(dwEffectId);
  198. UsagePage = DIGETUSAGEPAGE(dwEffectId);
  199. hres = PID_GetLinkCollectionIndex(ped, UsagePage, Collection, 0x0, &LinkCollection );
  200. if( SUCCEEDED(hres) )
  201. {
  202. Collection = HID_USAGE_PID_EFFECT_TYPE;
  203. hres = PID_GetLinkCollectionIndex(ped, UsagePage, Collection, LinkCollection, &TLinkCollection );
  204. }
  205. if( SUCCEEDED(hres) )
  206. {
  207. hres = HidP_SetUsages
  208. (
  209. HidP_Type,
  210. UsagePage,
  211. TLinkCollection,
  212. &Usage,
  213. &nUsages,
  214. this->ppd,
  215. pReport,
  216. cbReport);
  217. }
  218. if( SUCCEEDED(hres) && PIDMAKEUSAGEDWORD(ET_CUSTOM) == dwEffectId )
  219. {
  220. DICUSTOMFORCE DiParam;
  221. LONG lValue;
  222. int nBytes;
  223. AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
  224. memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
  225. //how many bytes do we need per sample?
  226. nBytes = ( this->customCaps[ 0].BitSize + this->customCaps[ 1].BitSize + this->customCaps[ 2].BitSize)/8;
  227. lValue = DiParam.cSamples * nBytes;
  228. hres = HidP_SetScaledUsageValue
  229. (
  230. HidP_Type,
  231. HID_USAGE_PAGE_GENERIC,
  232. LinkCollection,
  233. HID_USAGE_GENERIC_BYTE_COUNT,
  234. lValue,
  235. this->ppd,
  236. pReport,
  237. cbReport
  238. );
  239. }
  240. // Send the report
  241. if( SUCCEEDED(hres) )
  242. {
  243. hres = PID_SendReport(ped, pReport, cbReport, HidP_Type, TRUE, 0, 1);
  244. }
  245. // Get back the effect ID
  246. if( SUCCEEDED(hres) )
  247. {
  248. PIDREPORT BlockIndex = g_BlockIndex;
  249. USHORT LinkCollection;
  250. BlockIndex.Collection = HID_USAGE_PID_BLOCK_LOAD_REPORT;
  251. BlockIndex.HidP_Type = HidP_Feature;
  252. hres = PID_GetLinkCollectionIndex
  253. (ped,
  254. BlockIndex.UsagePage,
  255. BlockIndex.Collection,
  256. 0x0,
  257. &LinkCollection);
  258. if( SUCCEEDED(hres) )
  259. {
  260. PUCHAR pReport = this->pReport[BlockIndex.HidP_Type];
  261. UINT cbReport = this->cbReport[BlockIndex.HidP_Type];
  262. PID_GetReport(ped, &BlockIndex, LinkCollection, pReport, cbReport );
  263. // Get the EffectIndex
  264. hres = PID_ParseReport
  265. (
  266. ped,
  267. &BlockIndex,
  268. LinkCollection,
  269. pdwEffect,
  270. cbX(*pdwEffect),
  271. pReport,
  272. cbReport
  273. );
  274. if( SUCCEEDED(hres ) )
  275. {
  276. NTSTATUS ntStat;
  277. USAGE rgUsageList[MAX_BUTTONS];
  278. UINT cUsageList = MAX_BUTTONS;
  279. PID_GetLinkCollectionIndex(ped, HID_USAGE_PAGE_PID, HID_USAGE_PID_BLOCK_LOAD_STATUS, LinkCollection, &LinkCollection );
  280. ntStat = HidP_GetUsages
  281. (
  282. BlockIndex.HidP_Type,
  283. HID_USAGE_PAGE_PID,
  284. LinkCollection,
  285. rgUsageList,
  286. &cUsageList,
  287. this->ppd,
  288. pReport,
  289. cbReport);
  290. if(SUCCEEDED(ntStat) )
  291. {
  292. if (cUsageList != 0)
  293. {
  294. if( rgUsageList[0] == HID_USAGE_PID_BLOCK_LOAD_FULL )
  295. {
  296. hres = DIERR_DEVICEFULL;
  297. } else if(rgUsageList[0] == HID_USAGE_PID_BLOCK_LOAD_ERROR )
  298. {
  299. hres = DIERR_PID_BLOCKLOADERROR;
  300. } else
  301. {
  302. AssertF(rgUsageList[0] == HID_USAGE_PID_BLOCK_LOAD_SUCCESS);
  303. }
  304. }
  305. else
  306. {
  307. //because of issues w/ some chipsets (see Whistler bugs 231235, 304863),
  308. //cUsageList can be 0.
  309. //so warn the user.
  310. RPF(TEXT("Unable to get the effect load status -- may be a USB chipset issue!"));
  311. RPF(TEXT("The effect may not play correctly!"));
  312. }
  313. }
  314. }
  315. if(SUCCEEDED(hres))
  316. {
  317. NTSTATUS ntStat;
  318. UsagePage = HID_USAGE_PAGE_PID;
  319. Usage = HID_USAGE_PID_RAMPOOL_AVAILABLE;
  320. ntStat = HidP_GetScaledUsageValue
  321. (
  322. HidP_Feature,
  323. UsagePage,
  324. LinkCollection,
  325. Usage,
  326. &this->dwUsedMem,
  327. this->ppd,
  328. pReport,
  329. cbReport
  330. );
  331. if(FAILED(ntStat) )
  332. {
  333. // Reset the amount of used memory
  334. this->dwUsedMem = 0x0 ;
  335. SquirtSqflPtszV(sqfl | sqflError,
  336. TEXT("%s: FAIL HidP_GetScaledUsageValue:0x%x for(%x, %x,%x:%s)"),
  337. s_tszProc, ntStat,
  338. LinkCollection, UsagePage, Usage,
  339. PIDUSAGETXT(UsagePage,Usage) );
  340. }
  341. }
  342. }
  343. }
  344. if( SUCCEEDED(hres) )
  345. {
  346. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,*pdwEffect);
  347. // Serialize access to for new effect
  348. WaitForSingleObject(g_hmtxShared, INFINITE);
  349. AssertF(! (pEffectState->lEfState & PID_EFFECT_BUSY ));
  350. pEffectState->lEfState |= PID_EFFECT_BUSY;
  351. hres = S_OK;
  352. ReleaseMutex(g_hmtxShared);
  353. }
  354. } else
  355. {
  356. // Serialize access to common memory block
  357. WaitForSingleObject(g_hmtxShared, INFINITE);
  358. for(dwEffect = 1;
  359. dwEffect <= this->cMaxEffects;
  360. dwEffect++)
  361. {
  362. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,dwEffect);
  363. if( ! ( pEffectState->lEfState & PID_EFFECT_BUSY ) )
  364. {
  365. pEffectState->lEfState |= PID_EFFECT_BUSY;
  366. *pdwEffect = dwEffect;
  367. ZeroBuf(pEffectState->PidMem, cbX(pEffectState->PidMem[0]) * this->cMaxParameters );
  368. hres = S_OK;
  369. break;
  370. }
  371. }
  372. ReleaseMutex(g_hmtxShared);
  373. }
  374. if( SUCCEEDED(hres) )
  375. {
  376. ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded++;
  377. } else
  378. {
  379. SquirtSqflPtszV(sqfl | sqflError,
  380. TEXT("%s:FAIL Could not create new effects, already have %d "),
  381. s_tszProc, ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded );
  382. }
  383. ExitOleProc();
  384. return hres;
  385. }
  386. /*****************************************************************************
  387. *
  388. * PID_ValidateEffectIndex
  389. *
  390. * Validates an effect index.
  391. *
  392. *****************************************************************************/
  393. STDMETHODIMP PID_ValidateEffectIndex
  394. (
  395. IDirectInputEffectDriver *ped,
  396. DWORD dwEffect
  397. )
  398. {
  399. CPidDrv *this = (CPidDrv *)ped;
  400. HRESULT hres;
  401. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this, dwEffect);
  402. EnterProc(PID_ValidateEffectIndex, (_"xx", this, dwEffect));
  403. if( pEffectState->lEfState & PID_EFFECT_BUSY )
  404. {
  405. hres = S_OK;
  406. } else
  407. {
  408. hres = E_HANDLE;
  409. }
  410. ExitOleProc();
  411. return hres;
  412. }
  413. /*****************************************************************************
  414. *
  415. * PID_DestroyEffect
  416. *
  417. * Remove an effect from the device.
  418. *
  419. * If the effect is playing, the driver should stop it
  420. * before unloading it.
  421. *
  422. * dwId
  423. *
  424. * The external joystick number being addressed.
  425. *
  426. * dwEffect
  427. *
  428. * The effect to be destroyed.
  429. *
  430. * Returns:
  431. *
  432. * S_OK on success.
  433. *
  434. * Any other DIERR_* error code may be returned.
  435. *
  436. * Private driver-specific error codes in the range
  437. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  438. * may be returned.
  439. *
  440. *
  441. * Makes an effect Index available for reuse. Deallocates parameter block
  442. * memory.
  443. *
  444. *****************************************************************************/
  445. STDMETHODIMP
  446. PID_DestroyEffect
  447. (
  448. IDirectInputEffectDriver *ped,
  449. DWORD dwId,
  450. DWORD dwEffect
  451. )
  452. {
  453. CPidDrv *this = (CPidDrv *)ped;
  454. HRESULT hres=S_OK;
  455. EnterProc(PID_DestroyEffectIndex, (_"xx", this, dwEffect));
  456. DllEnterCrit();
  457. // Stop the Effect
  458. hres = PID_EffectOperation
  459. (
  460. ped,
  461. dwId,
  462. dwEffect,
  463. PID_DIES_STOP,
  464. 0x0,
  465. TRUE,
  466. 0,
  467. 1
  468. );
  469. if(SUCCEEDED(hres) &&
  470. ( this->uDeviceManaged & PID_DEVICEMANAGED ) )
  471. {
  472. // Device Managed memory needs to be freed explicitly.
  473. USHORT cbReport;
  474. PUCHAR pReport;
  475. PIDREPORT BlockIndex = g_BlockIndex;
  476. USHORT LinkCollection;
  477. cbReport = this->cbReport[BlockIndex.HidP_Type];
  478. pReport = this->pReport[BlockIndex.HidP_Type];
  479. ZeroBuf(pReport, cbReport);
  480. BlockIndex.Collection = HID_USAGE_PID_BLOCK_FREE_REPORT;
  481. BlockIndex.HidP_Type = HidP_Output;
  482. PID_GetLinkCollectionIndex
  483. (ped,
  484. BlockIndex.UsagePage,
  485. BlockIndex.Collection,
  486. 0x0,
  487. &LinkCollection);
  488. hres = PID_PackValue
  489. (
  490. ped,
  491. &BlockIndex,
  492. LinkCollection,
  493. &dwEffect,
  494. cbX(dwEffect),
  495. pReport,
  496. cbReport
  497. );
  498. if(SUCCEEDED(hres) )
  499. {
  500. hres = PID_SendReport(ped, pReport, cbReport, BlockIndex.HidP_Type, TRUE, 0, 1);
  501. }
  502. }
  503. if( SUCCEEDED(hres) )
  504. {
  505. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,dwEffect);
  506. UINT nAlloc, uParam;
  507. WaitForSingleObject(g_hmtxShared, INFINITE);
  508. pEffectState->lEfState = PID_EFFECT_RESET;
  509. for( uParam = 0x0; uParam < this->cMaxParameters; uParam++ )
  510. {
  511. PPIDMEM pMem = &pEffectState->PidMem[uParam] ;
  512. if( PIDMEM_SIZE(pMem) )
  513. {
  514. PPIDMEM pTmp;
  515. PUNITSTATE pUnitState = (PUNITSTATE)(g_pshmem + this->iUnitStateOffset);
  516. for(nAlloc = 0x0, pTmp = &(pUnitState->Guard[0]);
  517. nAlloc < pUnitState->nAlloc;
  518. nAlloc++, pTmp = (PPIDMEM)((PUCHAR)pUnitState + pTmp->iNext))
  519. {
  520. if( (PPIDMEM)(pTmp->iNext) == (PPIDMEM)((PUCHAR)pMem - (PUCHAR)pUnitState ))
  521. {
  522. pTmp->iNext = pMem->iNext;
  523. pUnitState->nAlloc--;
  524. pUnitState->cbAlloc -= PIDMEM_SIZE(pMem);
  525. pMem->iNext = 0;
  526. pMem->uOfSz = 0x0;
  527. break;
  528. }
  529. }
  530. }
  531. }
  532. ReleaseMutex(g_hmtxShared);
  533. }
  534. if( SUCCEEDED(hres) )
  535. {
  536. ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cEfDownloaded--;
  537. }
  538. DllLeaveCrit();
  539. ExitOleProc();
  540. return hres;
  541. }
  542. /*****************************************************************************
  543. *
  544. * PID_SanitizeEffect
  545. *
  546. * Sanitize the parameters in the DIEFFECT structure.
  547. * Clip values of magnitude, time, etc ..
  548. * Convert the axes array to usage, usage page from the DINPUT obj instances.
  549. * Convert and scale angles.
  550. *
  551. *****************************************************************************/
  552. HRESULT PID_SanitizeEffect
  553. (
  554. IDirectInputEffectDriver *ped,
  555. LPDIEFFECT lpeff,
  556. DWORD dwFlags
  557. )
  558. {
  559. CPidDrv *this = (CPidDrv *)ped;
  560. HRESULT hres = S_OK;
  561. UINT nAxis;
  562. EnterProc( PID_SanitizeEffect, (_"xxx", ped, lpeff, dwFlags));
  563. if( ( dwFlags & DIEP_TRIGGERBUTTON )
  564. && lpeff->dwTriggerButton != -1 )
  565. {
  566. DWORD dwUsage;
  567. hres = hresFinddwUsageFromdwFlags(ped, lpeff->dwTriggerButton, &dwUsage);
  568. if( SUCCEEDED(hres) )
  569. {
  570. USAGE Usage = DIGETUSAGE(dwUsage);
  571. USAGE UsagePage = DIGETUSAGEPAGE(dwUsage);
  572. lpeff->dwTriggerButton = Usage;
  573. } else
  574. {
  575. lpeff->dwTriggerButton = 0x0;
  576. }
  577. } else
  578. {
  579. lpeff->dwTriggerButton = 0x0;
  580. }
  581. for(nAxis = 0x0;
  582. nAxis < lpeff->cAxes;
  583. nAxis++ )
  584. {
  585. DWORD dwUsage;
  586. hres = hresFinddwUsageFromdwFlags(ped, lpeff->rgdwAxes[nAxis], &dwUsage);
  587. if(SUCCEEDED(hres) )
  588. {
  589. lpeff->rgdwAxes[nAxis] = dwUsage;
  590. }
  591. //if we have only 1 axis and direction of 0 or 360, make sure the direction matches the axis!
  592. //if direction is not 0, we do not know what the app wants, so let it be.
  593. if ((lpeff->cAxes == 1) && (lpeff->rglDirection[nAxis] % 360*DI_DEGREES == 0))
  594. {
  595. #ifndef HID_USAGE_SIMULATION_STEERING
  596. #define HID_USAGE_SIMULATION_STEERING ((USAGE) 0xC8)
  597. #endif
  598. #ifndef HID_USAGE_SIMULATION_ACCELERATOR
  599. #define HID_USAGE_SIMULATION_ACCELERATOR ((USAGE) 0xC4)
  600. #endif
  601. #ifndef HID_USAGE_SIMULATION_BRAKE
  602. #define HID_USAGE_SIMULATION_BRAKE ((USAGE) 0xC5)
  603. #endif
  604. //if it is X-axis or steering on the wheel, set direction to 90 degrees
  605. if ((DIGETUSAGE(lpeff->rgdwAxes[nAxis]) == HID_USAGE_GENERIC_X) || (DIGETUSAGE(lpeff->rgdwAxes[nAxis]) == HID_USAGE_SIMULATION_STEERING))
  606. {
  607. lpeff->rglDirection[nAxis] = 90*DI_DEGREES;
  608. }
  609. //if it is Y-axis or accelerator or brake, set direction to 0
  610. else if ((DIGETUSAGE(lpeff->rgdwAxes[nAxis]) == HID_USAGE_GENERIC_Y) || (DIGETUSAGE(lpeff->rgdwAxes[nAxis]) == HID_USAGE_SIMULATION_ACCELERATOR) ||
  611. (DIGETUSAGE(lpeff->rgdwAxes[nAxis]) == HID_USAGE_SIMULATION_BRAKE))
  612. {
  613. lpeff->rglDirection[nAxis] = 0x0;
  614. }
  615. }
  616. else
  617. //we have more than 1 axes or direction is non-0 for 1-axis effect; leave the direction along
  618. {
  619. lpeff->rglDirection[nAxis] %= 360*DI_DEGREES;
  620. if(lpeff->rglDirection[nAxis] < 0)
  621. {
  622. lpeff->rglDirection[nAxis] += 360*DI_DEGREES;
  623. }
  624. }
  625. }
  626. // Clip the values to min / max
  627. lpeff->dwGain = Clip(lpeff->dwGain, DI_FFNOMINALMAX);
  628. // Scale to units that device expects
  629. PID_ApplyScalingFactors(ped, &g_Effect, &this->DiSEffectScale, this->DiSEffectScale.dwSize, &this->DiSEffectOffset, this->DiSEffectOffset.dwSize, lpeff, lpeff->dwSize );
  630. ExitOleProc();
  631. return hres;
  632. }
  633. /*****************************************************************************
  634. *
  635. * CPidDrv_DownloadEffect
  636. *
  637. * Send an effect to the device.
  638. *
  639. * dwId
  640. *
  641. * The external joystick number being addressed.
  642. *
  643. * dwEffectId
  644. *
  645. * Internal identifier for the effect, taken from
  646. * the DIEFFECTATTRIBUTES structure for the effect
  647. * as stored in the registry.
  648. *
  649. * pdwEffect
  650. *
  651. * On entry, contains the handle of the effect being
  652. * downloaded. If the value is zero, then a new effect
  653. * is downloaded. If the value is nonzero, then an
  654. * existing effect is modified.
  655. *
  656. * On exit, contains the new effect handle.
  657. *
  658. * On failure, set to zero if the effect is lost,
  659. * or left alone if the effect is still valid with
  660. * its old parameters.
  661. *
  662. * Note that zero is never a valid effect handle.
  663. *
  664. * peff
  665. *
  666. * The new parameters for the effect. The axis and button
  667. * values have been converted to object identifiers
  668. * as follows:
  669. *
  670. * - One type specifier:
  671. *
  672. * DIDFT_RELAXIS,
  673. * DIDFT_ABSAXIS,
  674. * DIDFT_PSHBUTTON,
  675. * DIDFT_TGLBUTTON,
  676. * DIDFT_POV.
  677. *
  678. * - One instance specifier:
  679. *
  680. * DIDFT_MAKEINSTANCE(n).
  681. *
  682. * Other bits are reserved and should be ignored.
  683. *
  684. * For example, the value 0x0200104 corresponds to
  685. * the type specifier DIDFT_PSHBUTTON and
  686. * the instance specifier DIDFT_MAKEINSTANCE(1),
  687. * which together indicate that the effect should
  688. * be associated with button 1. Axes, buttons, and POVs
  689. * are each numbered starting from zero.
  690. *
  691. * dwFlags
  692. *
  693. * Zero or more DIEP_* flags specifying which
  694. * portions of the effect information has changed from
  695. * the effect already on the device.
  696. *
  697. * This information is passed to drivers to allow for
  698. * optimization of effect modification. If an effect
  699. * is being modified, a driver may be able to update
  700. * the effect in situ and transmit to the device
  701. * only the information that has changed.
  702. *
  703. * Drivers are not, however, required to implement this
  704. * optimization. All fields in the DIEFFECT structure
  705. * pointed to by the peff parameter are valid, and
  706. * a driver may choose simply to update all parameters of
  707. * the effect at each download.
  708. *
  709. * Returns:
  710. *
  711. * S_OK on success.
  712. *
  713. * DI_TRUNCATED if the parameters of the effect were
  714. * successfully downloaded, but some of them were
  715. * beyond the capabilities of the device and were truncated.
  716. *
  717. * DI_EFFECTRESTARTED if the parameters of the effect
  718. * were successfully downloaded, but in order to change
  719. * the parameters, the effect needed to be restarted.
  720. *
  721. * DI_TRUNCATEDANDRESTARTED if both DI_TRUNCATED and
  722. * DI_EFFECTRESTARTED apply.
  723. *
  724. * Any other DIERR_* error code may be returned.
  725. *
  726. * Private driver-specific error codes in the range
  727. * DIERR_DRIVERFIRST through DIERR_DRIVERLAST
  728. * may be returned.
  729. *
  730. *****************************************************************************/
  731. STDMETHODIMP
  732. PID_DownloadEffect
  733. (
  734. IDirectInputEffectDriver *ped,
  735. DWORD dwId,
  736. DWORD dwEffectId,
  737. LPDWORD pdwEffect,
  738. LPCDIEFFECT peff,
  739. DWORD dwFlags
  740. )
  741. {
  742. CPidDrv *this = (CPidDrv *)ped;
  743. HRESULT hres = S_OK;
  744. DIEFFECT eff;
  745. DWORD rgdwAxes[MAX_AXES];
  746. LONG rglDirection[MAX_AXES];
  747. UINT uParameter = 0x0 ;
  748. UINT totalBlocks = 0x0;
  749. BOOL bBlocking = FALSE;
  750. EnterProcI( PID_DownloadEffectBlock, (_"xxxxxx", ped, dwId, dwEffectId, pdwEffect, peff, dwFlags));
  751. AssertF(peff->cAxes <= MAX_AXES);
  752. DllEnterCrit();
  753. // If new effect is being downloaded
  754. if( *pdwEffect == 0x0 )
  755. {
  756. // Verify that dwEffectId is supported
  757. DWORD dwJunk;
  758. PIDSUPPORT pidSupport;
  759. pidSupport.dwPidUsage = dwEffectId;
  760. pidSupport.HidP_Type = HidP_Output;
  761. pidSupport.Type = HID_BUTTON;
  762. hres = PID_Support
  763. (
  764. ped,
  765. 0x1,
  766. &pidSupport,
  767. &dwJunk
  768. );
  769. if(FAILED(hres))
  770. {
  771. SquirtSqflPtszV(sqfl | sqflError,
  772. TEXT("%s:FAIL dwEffectId(0x%x) not supported"),
  773. s_tszProc, dwEffectId );
  774. }
  775. }
  776. if( SUCCEEDED(hres) )
  777. {
  778. // Make a local copy of the effect structure
  779. // And sanitize the effect struct
  780. eff = *peff;
  781. memcpy(rgdwAxes, peff->rgdwAxes,eff.cAxes*cbX(*(eff.rgdwAxes)));
  782. memcpy(rglDirection, peff->rglDirection, eff.cAxes*cbX(*(eff.rglDirection)));
  783. eff.rgdwAxes = rgdwAxes;
  784. eff.rglDirection = rglDirection;
  785. hres = PID_SanitizeEffect(ped, &eff, dwFlags);
  786. }
  787. // Allocate new effect index or Validate Existing index
  788. if( SUCCEEDED(hres) )
  789. {
  790. if( *pdwEffect != 0x0 )
  791. {
  792. hres = PID_ValidateEffectIndex(ped, *pdwEffect);
  793. }
  794. else
  795. {
  796. if (! (dwFlags & DIEP_NODOWNLOAD))
  797. {
  798. hres = PID_NewEffectIndex(ped, &eff, dwEffectId, pdwEffect);
  799. //block the first time around
  800. bBlocking = TRUE;
  801. }
  802. }
  803. }
  804. if (dwFlags & DIEP_NODOWNLOAD)
  805. {
  806. goto done;
  807. }
  808. //if the DIEP_NORESTART flag is passed, we have no block because this may fail
  809. //if the device can't update the parameters on the fly
  810. if (dwFlags & DIEP_NORESTART)
  811. {
  812. bBlocking = TRUE;
  813. }
  814. if( SUCCEEDED(hres) )
  815. {
  816. //count up how many total blocks we will have in this download
  817. //check wether we're sending the effect block
  818. if (dwFlags & ( DIEP_DURATION | DIEP_SAMPLEPERIOD | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_STARTDELAY ) )
  819. {
  820. totalBlocks ++;
  821. }
  822. //check whether we're sending the type-specific params
  823. if (dwFlags & DIEP_TYPESPECIFICPARAMS)
  824. {
  825. //this is slightly different, in that conditions can have 1 type-specific block PER AXIS,
  826. //i.e. currently up to 2
  827. //so if we have a DICONDITION, we check how many type-specific blocks we've got
  828. if ((dwEffectId == PIDMAKEUSAGEDWORD(ET_SPRING)) ||
  829. (dwEffectId == PIDMAKEUSAGEDWORD(ET_DAMPER)) ||
  830. (dwEffectId == PIDMAKEUSAGEDWORD(ET_INERTIA)) ||
  831. (dwEffectId == PIDMAKEUSAGEDWORD(ET_FRICTION)))
  832. {
  833. totalBlocks +=(eff.cbTypeSpecificParams)/sizeof(DICONDITION);
  834. //DICONDITIONS also can't have envelopes
  835. dwFlags &= ~DIEP_ENVELOPE;
  836. }
  837. else
  838. {
  839. totalBlocks++;
  840. }
  841. }
  842. //check whether we're sending the envelope
  843. if ((dwFlags & DIEP_ENVELOPE) && (eff.lpEnvelope != NULL))
  844. {
  845. totalBlocks++;
  846. }
  847. //check whether we need to send the start reprot
  848. if (dwFlags & DIEP_START)
  849. {
  850. totalBlocks++;
  851. }
  852. //make sure that we haven't got more than the maximum
  853. AssertF(totalBlocks <= MAX_BLOCKS);
  854. // Do the parameter block
  855. if( SUCCEEDED(hres)
  856. && ( dwFlags & ( DIEP_TYPESPECIFICPARAMS | DIEP_ENVELOPE) )
  857. )
  858. {
  859. hres = PID_DoParameterBlocks
  860. (
  861. ped,
  862. dwId,
  863. dwEffectId,
  864. *pdwEffect,
  865. &eff,
  866. dwFlags,
  867. &uParameter,
  868. bBlocking,
  869. totalBlocks
  870. );
  871. }
  872. // Now do the effect report
  873. if( SUCCEEDED(hres)
  874. && ( dwFlags & ( DIEP_DURATION | DIEP_SAMPLEPERIOD | DIEP_GAIN | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_AXES | DIEP_DIRECTION | DIEP_STARTDELAY ) ) )
  875. {
  876. USHORT cbReport;
  877. PUCHAR pReport;
  878. AssertF(g_Effect.HidP_Type == HidP_Output);
  879. cbReport = this->cbReport[g_Effect.HidP_Type];
  880. pReport = this->pReport[g_Effect.HidP_Type];
  881. // Set the Effect Structure
  882. if( SUCCEEDED(hres) )
  883. {
  884. USHORT LinkCollection;
  885. PID_GetLinkCollectionIndex(ped, g_Effect.UsagePage, g_Effect.Collection, 0x0, &LinkCollection );
  886. ZeroBuf(pReport, cbReport);
  887. // Do the common elements of the effect structure
  888. hres = PID_PackValue
  889. (
  890. ped,
  891. &g_Effect,
  892. LinkCollection,
  893. &eff,
  894. eff.dwSize,
  895. pReport,
  896. cbReport
  897. );
  898. // Set the Effect Block Index
  899. if( SUCCEEDED(hres) )
  900. {
  901. hres = PID_PackValue
  902. (
  903. ped,
  904. &g_BlockIndex,
  905. LinkCollection,
  906. pdwEffect,
  907. cbX(*pdwEffect),
  908. pReport,
  909. cbReport
  910. );
  911. }
  912. // Set Direction and axis attributes
  913. if( SUCCEEDED(hres) )
  914. {
  915. USHORT DirectionCollection;
  916. PID_GetLinkCollectionIndex(ped, g_Direction.UsagePage, g_Direction.Collection, 0x0, &DirectionCollection );
  917. PID_ApplyScalingFactors(ped, &g_Direction, &this->DiSEffectAngleScale, cbX(this->DiSEffectAngleScale), &this->DiSEffectAngleOffset, cbX(this->DiSEffectAngleOffset), eff.rglDirection, eff.cAxes*cbX(LONG) );
  918. hres = PID_PackValue
  919. (
  920. ped,
  921. &g_Direction,
  922. DirectionCollection,
  923. eff.rglDirection,
  924. eff.cAxes * cbX(LONG),
  925. pReport,
  926. cbReport
  927. );
  928. if(SUCCEEDED(hres) &&
  929. ! ( eff.dwFlags & DIEFF_CARTESIAN ) )
  930. {
  931. // Direction Enable
  932. USHORT Usage;
  933. USHORT UsagePage;
  934. UINT nUsages = 0x1;
  935. NTSTATUS ntStat;
  936. // Direction Enable is in the set effect collection
  937. UsagePage = g_Effect.UsagePage;
  938. Usage = HID_USAGE_PID_DIRECTION_ENABLE;
  939. ntStat = HidP_SetUsages
  940. (
  941. HidP_Output,
  942. UsagePage,
  943. LinkCollection,
  944. &Usage,
  945. &nUsages,
  946. this->ppd,
  947. pReport,
  948. cbReport);
  949. if( FAILED(ntStat) )
  950. {
  951. SquirtSqflPtszV(sqfl | sqflError,
  952. TEXT("%s: FAIL HidP_SetUsages:0x%x for(%x,%x,%x:%s)"),
  953. s_tszProc, ntStat,
  954. LinkCollection, UsagePage, Usage,
  955. PIDUSAGETXT(UsagePage,Usage) );
  956. } else
  957. {
  958. SquirtSqflPtszV(sqfl | sqflVerbose,
  959. TEXT("%s: HidP_SetUsages:0x%x for(%x,%x,%x:%s)"),
  960. s_tszProc, ntStat,
  961. LinkCollection,UsagePage, Usage,
  962. PIDUSAGETXT(UsagePage,Usage) );
  963. }
  964. } else //if( dwFlags & DIEP_AXES )
  965. {
  966. UINT nAxis;
  967. USHORT LinkCollection_AE=0x0;
  968. if(SUCCEEDED(PID_GetLinkCollectionIndex(ped, HID_USAGE_PAGE_PID, HID_USAGE_PID_AXES_ENABLE, 0x0, &LinkCollection_AE)))
  969. {
  970. // ISSUE-2001/03/29-timgill Need to support axes within pointer collections
  971. // PID spec indicates a pointer collection,
  972. // Do we want to support axes enables within a pointer
  973. // collection ?
  974. // See if there is a pointer collection
  975. }
  976. for(nAxis = 0x0;
  977. nAxis < eff.cAxes;
  978. nAxis++ )
  979. {
  980. UINT nUsages = 0x1;
  981. USHORT Usage = DIGETUSAGE(eff.rgdwAxes[nAxis]);
  982. USHORT UsagePage = DIGETUSAGEPAGE(eff.rgdwAxes[nAxis]);
  983. NTSTATUS ntStat;
  984. //ISSUE-2001/03/29-timgill For now we assume any collection
  985. ntStat = HidP_SetUsages
  986. (
  987. HidP_Output,
  988. UsagePage,
  989. 0x0,
  990. &Usage,
  991. &nUsages,
  992. this->ppd,
  993. pReport,
  994. cbReport);
  995. if( FAILED(ntStat) )
  996. {
  997. SquirtSqflPtszV(sqfl | sqflError,
  998. TEXT("%s: FAIL HidP_SetUsages:0x%x for(%x,%x,%x:%s)"),
  999. s_tszProc, ntStat,
  1000. 0x0, UsagePage, Usage,
  1001. PIDUSAGETXT(UsagePage,Usage) );
  1002. hres = ntStat;
  1003. break;
  1004. } else
  1005. {
  1006. SquirtSqflPtszV(sqfl | sqflVerbose,
  1007. TEXT("%s: HidP_SetUsages:0x%x for(%x,%x,%x:%s)"),
  1008. s_tszProc, ntStat,
  1009. 0x0, UsagePage, Usage,
  1010. PIDUSAGETXT(UsagePage, Usage) );
  1011. }
  1012. }
  1013. }
  1014. }
  1015. if( SUCCEEDED(hres)
  1016. && !( this->uDeviceManaged & PID_DEVICEMANAGED )
  1017. )
  1018. {
  1019. // Need parameter block offsets
  1020. UINT indx;
  1021. USHORT LinkCollection;
  1022. LONG rglValue[MAX_ORDINALS];
  1023. PID_GetLinkCollectionIndex(ped, g_Effect.UsagePage, g_TypeSpBlockOffset.Collection, 0x0, &LinkCollection );
  1024. for(indx = 0x0; indx < this->cMaxParameters; indx++ )
  1025. {
  1026. hres = PID_GetParameterOffset(ped, *pdwEffect, indx, 0x0, &rglValue[indx]);
  1027. if(FAILED(hres))
  1028. {
  1029. break;
  1030. }
  1031. }
  1032. if(SUCCEEDED(hres))
  1033. {
  1034. hres = PID_PackValue
  1035. (
  1036. ped,
  1037. &g_TypeSpBlockOffset,
  1038. LinkCollection,
  1039. rglValue,
  1040. this->cMaxParameters*cbX(LONG),
  1041. pReport,
  1042. cbReport
  1043. );
  1044. }
  1045. }
  1046. // Set the Effect Type
  1047. if( SUCCEEDED(hres) )
  1048. {
  1049. USAGE UsagePage = DIGETUSAGEPAGE(dwEffectId);
  1050. USAGE Usage = DIGETUSAGE(dwEffectId);
  1051. UINT nUsages = 0x1;
  1052. USHORT LinkCollection_ET;
  1053. NTSTATUS ntStat;
  1054. PID_GetLinkCollectionIndex(ped, g_Effect.UsagePage, HID_USAGE_PID_EFFECT_TYPE, 0x0, &LinkCollection_ET);
  1055. ntStat = HidP_SetUsages
  1056. (
  1057. HidP_Output,
  1058. UsagePage,
  1059. LinkCollection_ET,
  1060. &Usage,
  1061. &nUsages,
  1062. this->ppd,
  1063. pReport,
  1064. cbReport);
  1065. if( FAILED(ntStat) )
  1066. {
  1067. SquirtSqflPtszV(sqfl | sqflError,
  1068. TEXT("%s: FAIL HidP_SetUsages:0x%x for(%x,%x,%x:%s)"),
  1069. s_tszProc, ntStat,
  1070. LinkCollection_ET, UsagePage, Usage,
  1071. PIDUSAGETXT(UsagePage,Usage) );
  1072. hres = ntStat;
  1073. } else
  1074. {
  1075. SquirtSqflPtszV(sqfl | sqflVerbose,
  1076. TEXT("%s: HidP_SetUsages:0x%x for(%x,%x,%x:%s)"),
  1077. s_tszProc, ntStat,
  1078. LinkCollection_ET, UsagePage, Usage,
  1079. PIDUSAGETXT(UsagePage,Usage) );
  1080. }
  1081. }
  1082. if( SUCCEEDED(hres) )
  1083. {
  1084. hres = PID_SendReport(ped, pReport, cbReport, g_Effect.HidP_Type, bBlocking, uParameter, totalBlocks);
  1085. uParameter ++;
  1086. }
  1087. }
  1088. }
  1089. }
  1090. if( FAILED(hres) )
  1091. {
  1092. PID_DestroyEffect(ped, dwId, *pdwEffect);
  1093. }
  1094. if( SUCCEEDED(hres)
  1095. && (dwFlags & DIEP_START) )
  1096. {
  1097. hres = PID_EffectOperation
  1098. (
  1099. ped,
  1100. dwId,
  1101. *pdwEffect,
  1102. PID_DIES_START,
  1103. 0x1,
  1104. bBlocking,
  1105. uParameter,
  1106. totalBlocks
  1107. );
  1108. if (SUCCEEDED(hres))
  1109. {
  1110. //set the status to DIEGES_PLAYING.
  1111. //we do this because of the following: if an app calls Start(), and then immediately
  1112. //calls GetEffectStatus(), it might happen that our second thread (pidrd.c)
  1113. //would not have time to update the status of the effect to DIEGES_PLAYING
  1114. //(see Whistler bug 287035).
  1115. //GetEffectStatus() returns (pEffectState->lEfState & DIEGES_PLAYING).
  1116. //in the blocking case, we know that the call to WriteFile() has succeeded, and that
  1117. //all the data has been written (see PID_SendReportBl() in pidhid.c) --
  1118. //so we might as well set the status.
  1119. //in the non-blocking case, the data can be buffered anyway -- so we might as well set the status.
  1120. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this, *pdwEffect);
  1121. pEffectState->lEfState |= DIEGES_PLAYING;
  1122. }
  1123. }
  1124. done:;
  1125. DllLeaveCrit();
  1126. ExitOleProc();
  1127. return hres;
  1128. }