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.

943 lines
28 KiB

  1. /*****************************************************************************
  2. *
  3. * PidParam.c
  4. *
  5. * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Download PID parameter block(s) .
  10. *
  11. *****************************************************************************/
  12. #include "pidpr.h"
  13. #define sqfl ( sqflParam )
  14. //struct to keep in relevant data for g_Custom
  15. typedef struct PIDCUSTOM
  16. {
  17. DWORD DataOffset;
  18. DWORD cSamples;
  19. DWORD dwSamplePeriod;
  20. } PIDCUSTOM, *PPIDCUSTOM;
  21. #pragma BEGIN_CONST_DATA
  22. static PIDUSAGE c_rgUsgEnvelope[] =
  23. {
  24. MAKE_PIDUSAGE(ATTACK_LEVEL, FIELD_OFFSET(DIENVELOPE,dwAttackLevel) ),
  25. MAKE_PIDUSAGE(ATTACK_TIME, FIELD_OFFSET(DIENVELOPE,dwAttackTime) ),
  26. MAKE_PIDUSAGE(FADE_LEVEL, FIELD_OFFSET(DIENVELOPE,dwFadeLevel) ),
  27. MAKE_PIDUSAGE(FADE_TIME, FIELD_OFFSET(DIENVELOPE,dwFadeTime) ),
  28. };
  29. PIDREPORT g_Envelope =
  30. {
  31. HidP_Output,
  32. HID_USAGE_PAGE_PID,
  33. HID_USAGE_PID_SET_ENVELOPE_REPORT,
  34. cbX(DIENVELOPE),
  35. cA(c_rgUsgEnvelope),
  36. c_rgUsgEnvelope
  37. };
  38. static PIDUSAGE c_rgUsgCondition[] =
  39. {
  40. MAKE_PIDUSAGE(CP_OFFSET, FIELD_OFFSET(DICONDITION, lOffset) ),
  41. MAKE_PIDUSAGE(POSITIVE_COEFFICIENT, FIELD_OFFSET(DICONDITION, lPositiveCoefficient)),
  42. MAKE_PIDUSAGE(NEGATIVE_COEFFICIENT, FIELD_OFFSET(DICONDITION, lNegativeCoefficient)),
  43. MAKE_PIDUSAGE(POSITIVE_SATURATION, FIELD_OFFSET(DICONDITION, dwPositiveSaturation)),
  44. MAKE_PIDUSAGE(NEGATIVE_SATURATION, FIELD_OFFSET(DICONDITION, dwNegativeSaturation)),
  45. MAKE_PIDUSAGE(DEAD_BAND, FIELD_OFFSET(DICONDITION, lDeadBand)),
  46. };
  47. PIDREPORT g_Condition =
  48. {
  49. HidP_Output,
  50. HID_USAGE_PAGE_PID,
  51. HID_USAGE_PID_SET_CONDITION_REPORT,
  52. cbX(DICONDITION),
  53. cA(c_rgUsgCondition),
  54. c_rgUsgCondition
  55. };
  56. static PIDUSAGE c_rgUsgPeriodic[] =
  57. {
  58. MAKE_PIDUSAGE(OFFSET, FIELD_OFFSET(DIPERIODIC,lOffset)),
  59. MAKE_PIDUSAGE(MAGNITUDE, FIELD_OFFSET(DIPERIODIC,dwMagnitude)),
  60. MAKE_PIDUSAGE(PHASE, FIELD_OFFSET(DIPERIODIC,dwPhase)),
  61. MAKE_PIDUSAGE(PERIOD, FIELD_OFFSET(DIPERIODIC,dwPeriod)),
  62. };
  63. PIDREPORT g_Periodic =
  64. {
  65. HidP_Output,
  66. HID_USAGE_PAGE_PID,
  67. HID_USAGE_PID_SET_PERIODIC_REPORT,
  68. cbX(DIPERIODIC),
  69. cA(c_rgUsgPeriodic),
  70. c_rgUsgPeriodic
  71. };
  72. static PIDUSAGE c_rgUsgConstant[] =
  73. {
  74. MAKE_PIDUSAGE(MAGNITUDE, FIELD_OFFSET(DICONSTANTFORCE, lMagnitude)),
  75. };
  76. PIDREPORT g_Constant =
  77. {
  78. HidP_Output,
  79. HID_USAGE_PAGE_PID,
  80. HID_USAGE_PID_SET_CONSTANT_FORCE_REPORT,
  81. cbX(DICONSTANTFORCE),
  82. cA(c_rgUsgConstant),
  83. c_rgUsgConstant
  84. };
  85. static PIDUSAGE c_rgUsgRamp[] =
  86. {
  87. MAKE_PIDUSAGE(RAMP_START, FIELD_OFFSET(DIRAMPFORCE, lStart)),
  88. MAKE_PIDUSAGE(RAMP_END, FIELD_OFFSET(DIRAMPFORCE, lEnd)),
  89. };
  90. PIDREPORT g_Ramp =
  91. {
  92. HidP_Output,
  93. HID_USAGE_PAGE_PID,
  94. HID_USAGE_PID_SET_RAMP_FORCE_REPORT,
  95. cbX(DIRAMPFORCE),
  96. cA(c_rgUsgRamp),
  97. c_rgUsgRamp
  98. };
  99. static PIDUSAGE c_rgUsgCustom[]=
  100. {
  101. MAKE_PIDUSAGE(CUSTOM_FORCE_DATA_OFFSET, FIELD_OFFSET(PIDCUSTOM, DataOffset)),
  102. MAKE_PIDUSAGE(SAMPLE_COUNT, FIELD_OFFSET(PIDCUSTOM, cSamples)),
  103. MAKE_PIDUSAGE(SAMPLE_PERIOD, FIELD_OFFSET(PIDCUSTOM, dwSamplePeriod)),
  104. };
  105. PIDREPORT g_Custom =
  106. {
  107. HidP_Output,
  108. HID_USAGE_PAGE_PID,
  109. HID_USAGE_PID_SET_CUSTOM_FORCE_REPORT,
  110. cbX(PIDCUSTOM),
  111. cA(c_rgUsgCustom),
  112. c_rgUsgCustom,
  113. };
  114. static PIDUSAGE c_rgUsgCustomData[]=
  115. {
  116. MAKE_PIDUSAGE(CUSTOM_FORCE_DATA_OFFSET, 0x0),
  117. MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_BYTE_COUNT, 0x0),
  118. MAKE_PIDUSAGE(CUSTOM_FORCE_DATA, 0x0 ),
  119. };
  120. PIDREPORT g_CustomData =
  121. {
  122. HidP_Output,
  123. HID_USAGE_PAGE_PID,
  124. HID_USAGE_PID_CUSTOM_FORCE_DATA_REPORT,
  125. cbX(DWORD),
  126. cA(c_rgUsgCustomData),
  127. c_rgUsgCustomData,
  128. };
  129. static PIDUSAGE c_rgUsgDirectionAxes[]=
  130. {
  131. MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_X, 0*cbX(ULONG)),
  132. MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_Y, 1*cbX(ULONG)),
  133. MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_Z, 2*cbX(ULONG)),
  134. };
  135. PIDREPORT g_CustomSample =
  136. {
  137. HidP_Output,
  138. HID_USAGE_PAGE_PID,
  139. HID_USAGE_PID_DOWNLOAD_FORCE_SAMPLE ,
  140. cbX(DWORD),
  141. cA(c_rgUsgDirectionAxes),
  142. c_rgUsgDirectionAxes,
  143. };
  144. static PIDUSAGE c_rgUsgParameterOffset[] =
  145. {
  146. MAKE_PIDUSAGE(PARAMETER_BLOCK_OFFSET, 0x0 ),
  147. };
  148. static PIDREPORT g_ParameterOffset =
  149. {
  150. HidP_Output,
  151. HID_USAGE_PAGE_PID,
  152. 0x0,
  153. cbX(DWORD),
  154. cA(c_rgUsgParameterOffset),
  155. c_rgUsgParameterOffset
  156. };
  157. #pragma END_CONST_DATA
  158. //global variable to keep in relevant data for g_Custom
  159. PIDCUSTOM g_PidCustom;
  160. STDMETHODIMP
  161. PID_GetParameterOffset
  162. (
  163. IDirectInputEffectDriver *ped,
  164. DWORD dwEffectIndex,
  165. UINT uParameter,
  166. DWORD dwSz,
  167. PLONG plValue
  168. )
  169. {
  170. CPidDrv *this = (CPidDrv *)ped;
  171. HRESULT hres = S_OK;
  172. USHORT uOffset = (USHORT)-1;
  173. PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,dwEffectIndex);
  174. PPIDMEM pMem = &pEffectState->PidMem[uParameter];
  175. EnterProcI( PID_GetParameterOffset, (_"xxxxx", ped, dwEffectIndex, uParameter, dwSz, plValue));
  176. AssertF(uParameter < this->cMaxParameters);
  177. *plValue = 0x0;
  178. hres = PID_ValidateEffectIndex(ped, dwEffectIndex);
  179. if(SUCCEEDED(hres))
  180. {
  181. // We have already allocated memory,
  182. // Just return the last size
  183. if( PIDMEM_SIZE(pMem) != 0x0 )
  184. {
  185. uOffset = PIDMEM_OFFSET(pMem);
  186. } else if( dwSz == 0x0 )
  187. {
  188. // Logitech device wants parameter blocks to
  189. // set to -1 if they do not exist
  190. uOffset = (USHORT)-1;
  191. } else
  192. {
  193. // New Allocation
  194. PPIDMEM pTmp, pNext;
  195. UINT nAlloc;
  196. USHORT uSz;
  197. PUNITSTATE pUnitState = (PUNITSTATE)(g_pshmem + this->iUnitStateOffset);
  198. hres = DIERR_OUTOFMEMORY;
  199. // Align memory request
  200. uSz = (USHORT)((dwSz / this->ReportPool.uPoolAlign + 1) * (this->ReportPool.uPoolAlign));
  201. AssertF(uSz >= (USHORT)this->ReportPool.uPoolAlign);
  202. //To be doubly sure.
  203. uSz = max( uSz, (USHORT)this->ReportPool.uPoolAlign);
  204. WaitForSingleObject(g_hmtxShared, INFINITE);
  205. for(nAlloc = 0x0, pTmp = &(pUnitState->Guard[0]), pNext = (PPIDMEM)((PUCHAR)pUnitState + pTmp->iNext);
  206. nAlloc < pUnitState->nAlloc && pTmp != &(pUnitState->Guard[1]);
  207. nAlloc++, pTmp = pNext, pNext = (PPIDMEM)((PUCHAR)pUnitState + pTmp->iNext))
  208. {
  209. SquirtSqflPtszV(sqfl | sqflVerbose,
  210. TEXT("%d %x(%x), Next:%x (%x) "),
  211. nAlloc, pTmp, pTmp->uOfSz, pNext, pNext->uOfSz );
  212. AssertF(pNext != NULL );
  213. // If pNext == pUnitState, it means that the offset is 0.
  214. // The offset of 0 is invalid.
  215. AssertF((PUCHAR)pNext != (PUCHAR)pUnitState);
  216. // Is there space in the cracks
  217. if( GET_NEXTOFFSET(pTmp) + uSz < PIDMEM_OFFSET(pNext) )
  218. {
  219. pMem->iNext = (PUCHAR)pNext - (PUCHAR)pUnitState;
  220. pTmp->iNext = (PUCHAR)pMem - (PUCHAR)pUnitState;
  221. uOffset = GET_NEXTOFFSET(pTmp) ;
  222. pMem->uOfSz = PIDMEM_OFSZ(uOffset, uSz);
  223. pUnitState->nAlloc++;
  224. pUnitState->cbAlloc += uSz;
  225. hres = S_OK;
  226. SquirtSqflPtszV(sqfl | sqflVerbose,
  227. TEXT("%d %p (%x), Next: %p (%x) "),
  228. nAlloc, pMem, pMem->uOfSz, pNext, pNext->uOfSz );
  229. break;
  230. }
  231. }
  232. ReleaseMutex(g_hmtxShared);
  233. }
  234. }
  235. if( SUCCEEDED(hres) )
  236. {
  237. *plValue = (ULONG)uOffset;
  238. } else
  239. {
  240. SquirtSqflPtszV(sqfl | sqflError,
  241. TEXT("%s:FAIL Could not allocate %d bytes, UsedMem:%d, Allocs%d"),
  242. s_tszProc, dwSz, ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cbAlloc, ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->nAlloc );
  243. }
  244. ExitOleProc();
  245. return hres;
  246. }
  247. HRESULT
  248. PID_SendParameterBlock
  249. (
  250. IDirectInputEffectDriver *ped,
  251. DWORD dwEffectIndex,
  252. DWORD dwMemSz,
  253. PUINT puParameter,
  254. PPIDREPORT pPidReport,
  255. PVOID pvData,
  256. UINT cbData,
  257. BOOL bBlocking,
  258. UINT totalBlocks
  259. )
  260. {
  261. CPidDrv *this = (CPidDrv *)ped;
  262. HRESULT hres=S_OK;
  263. PUCHAR pReport;
  264. UINT cbReport;
  265. EnterProcI( PID_SendParameterBlock, (_"xxxxx", ped, dwEffectIndex, dwMemSz, pPidReport, pvData, cbData));
  266. AssertF(pPidReport->HidP_Type == HidP_Output);
  267. cbReport = this->cbReport[pPidReport->HidP_Type];
  268. pReport = this->pReport[pPidReport->HidP_Type];
  269. if( *puParameter >= this->cMaxParameters )
  270. {
  271. SquirtSqflPtszV(sqfl | sqflError,
  272. TEXT("%s:FAIL Only support %d parameter blocks per effect "),
  273. s_tszProc, *puParameter );
  274. hres = E_NOTIMPL;
  275. }
  276. if( SUCCEEDED(hres) )
  277. {
  278. USHORT LinkCollection;
  279. ZeroBuf(pReport, cbReport);
  280. PID_GetLinkCollectionIndex(ped, pPidReport->UsagePage, pPidReport->Collection, 0x0, &LinkCollection);
  281. hres = PID_PackValue
  282. (
  283. ped,
  284. pPidReport,
  285. LinkCollection,
  286. pvData,
  287. cbData,
  288. pReport,
  289. cbReport
  290. );
  291. // For device managed memory, we need to send the
  292. // effect index
  293. if( SUCCEEDED(hres) )
  294. {
  295. if( this->uDeviceManaged & PID_DEVICEMANAGED )
  296. {
  297. // Must be a valid effect ID
  298. AssertF(dwEffectIndex != 0x0 );
  299. /*hres =*/
  300. PID_PackValue
  301. (
  302. ped,
  303. &g_BlockIndex,
  304. LinkCollection,
  305. &dwEffectIndex,
  306. cbX(dwEffectIndex),
  307. pReport,
  308. cbReport
  309. );
  310. // Send down the paramter block index
  311. /*hres =*/PID_PackValue
  312. (
  313. ped,
  314. &g_ParameterOffset,
  315. LinkCollection,
  316. puParameter,
  317. cbX(*puParameter),
  318. pReport,
  319. cbReport
  320. );
  321. } else
  322. {
  323. LONG lValue;
  324. hres = PID_GetParameterOffset(ped, dwEffectIndex, *puParameter, dwMemSz, &lValue);
  325. if( SUCCEEDED(hres) )
  326. {
  327. hres = PID_PackValue
  328. (
  329. ped,
  330. &g_ParameterOffset,
  331. LinkCollection,
  332. &lValue,
  333. cbX(lValue),
  334. pReport,
  335. cbReport
  336. );
  337. }
  338. }
  339. }
  340. if( SUCCEEDED(hres) )
  341. {
  342. hres = PID_SendReport(ped, pReport, cbReport, pPidReport->HidP_Type, bBlocking, *puParameter, totalBlocks);
  343. }
  344. if(SUCCEEDED(hres))
  345. {
  346. (*puParameter)++;
  347. }
  348. }
  349. ExitOleProc();
  350. return hres;
  351. }
  352. /*****************************************************************************
  353. *
  354. * PID_DownloadCustomForceData
  355. *
  356. * Download custom force sample data to the device.
  357. *
  358. *****************************************************************************/
  359. STDMETHODIMP
  360. PID_DownloadCustomForceData
  361. (
  362. IDirectInputEffectDriver *ped,
  363. DWORD dwEffectIndex,
  364. PUINT puParameter,
  365. LPCDICUSTOMFORCE pCustom,
  366. LPCDIEFFECT peff
  367. )
  368. {
  369. CPidDrv *this = (CPidDrv *)ped;
  370. HRESULT hres = S_OK;
  371. PCHAR pData = NULL;
  372. PCHAR pBuff = NULL;
  373. USHORT cbData;
  374. USHORT nBytes;
  375. USHORT bitsX;
  376. USHORT bitsY;
  377. USHORT bitsZ;
  378. LPLONG pSample;
  379. EnterProcI( PID_DownloadCustomForceData, (_"xxx", ped, dwEffectIndex, pCustom, puParameter ));
  380. //zero out g_PidCustom
  381. g_PidCustom.cSamples = g_PidCustom.DataOffset = g_PidCustom.dwSamplePeriod = 0;
  382. //get bytes per sample and allocate the buffer
  383. bitsX = this->customCaps[0].BitSize;
  384. bitsY = this->customCaps[1].BitSize;
  385. bitsZ = this->customCaps[2].BitSize;
  386. //byte count must be multiple of 8!
  387. if ((bitsX%8 != 0) || (bitsY%8 != 0) || (bitsZ%8 != 0))
  388. {
  389. SquirtSqflPtszV(sqfl | sqflError,
  390. TEXT("%s:FAIL Download Force Sample report fields that are not multiples of 8 are not supported!\n"),
  391. s_tszProc );
  392. hres = E_NOTIMPL;
  393. }
  394. //report count shouldn't be bigger than 1!
  395. AssertF(this->customCaps[0].ReportCount <= 1);
  396. AssertF(this->customCaps[1].ReportCount <= 1);
  397. AssertF(this->customCaps[2].ReportCount <= 1);
  398. if (SUCCEEDED(hres))
  399. {
  400. nBytes = (bitsX + bitsY + bitsZ)/8;
  401. cbData = (USHORT) (pCustom->cSamples * nBytes);
  402. hres = AllocCbPpv(cbData, &pBuff);
  403. if( pBuff != NULL)
  404. {
  405. //determine which effect axis corresponds to which report axis
  406. LONG Offset[3] = {-1, -1, -1};
  407. int nAxis = 0;
  408. int nChannel = 0;
  409. int nSample = 0;
  410. for (nChannel = 0; nChannel < (int)pCustom->cChannels, nChannel < (int)peff->cAxes; nChannel ++)
  411. {
  412. for (nAxis = 0; nAxis < 3; nAxis ++)
  413. {
  414. if (DIGETUSAGE(peff->rgdwAxes[nChannel]) == DIGETUSAGE(g_CustomSample.rgPidUsage[nAxis].dwUsage))
  415. {
  416. Offset[nAxis] = nChannel;
  417. }
  418. }
  419. }
  420. ZeroBuf(pBuff, cbData);
  421. pData = pBuff;
  422. pSample = pCustom->rglForceData;
  423. //scale all the samples
  424. //loop through samples
  425. for (nSample = 0; nSample < (int)pCustom->cSamples; nSample ++)
  426. {
  427. //loop through report axis
  428. for (nAxis = 0; nAxis < 3; nAxis++)
  429. {
  430. LONG lSampleValue = 0;
  431. //check if this axis is used
  432. if (Offset[nAxis] == -1)
  433. {
  434. pData += this->customCaps[nAxis].BitSize/8;
  435. continue;
  436. }
  437. lSampleValue = *(pSample + Offset[nAxis]);
  438. switch (this->customCaps[nAxis].BitSize)
  439. {
  440. case 8:
  441. //8-bit reports
  442. {
  443. (*((BYTE*)pData)) = (BYTE)(this->customCaps[nAxis].LogicalMin + ((lSampleValue + DI_FFNOMINALMAX) * (this->customCaps[nAxis].LogicalMax - this->customCaps[nAxis].LogicalMin))/(2*DI_FFNOMINALMAX));
  444. pData++;
  445. break;
  446. }
  447. case 16:
  448. //16-bit reports
  449. {
  450. (*((SHORT*)pData)) = (SHORT)(this->customCaps[nAxis].LogicalMin + ((lSampleValue + DI_FFNOMINALMAX) * (this->customCaps[nAxis].LogicalMax - this->customCaps[nAxis].LogicalMin))/(2*DI_FFNOMINALMAX));
  451. pData++;
  452. break;
  453. }
  454. case 32:
  455. //assume 32-bit reports as default
  456. {
  457. (*((LONG*)pData)) = (LONG)(this->customCaps[nAxis].LogicalMin + ((lSampleValue + DI_FFNOMINALMAX) * (this->customCaps[nAxis].LogicalMax - this->customCaps[nAxis].LogicalMin))/(2*DI_FFNOMINALMAX));
  458. pData++;
  459. break;
  460. }
  461. default:
  462. {
  463. SquirtSqflPtszV(sqfl | sqflError,
  464. TEXT("%s:FAIL Download Force Sample report fields that are not 8, 16 or 32 are not supported\n"),
  465. s_tszProc );
  466. hres = E_NOTIMPL;
  467. }
  468. }
  469. }
  470. pSample += pCustom->cChannels;
  471. }
  472. }
  473. if(SUCCEEDED(hres))
  474. {
  475. PCHAR pReport;
  476. UINT cbReport;
  477. HIDP_REPORT_TYPE HidP_Type = HidP_Output;
  478. USAGE UsagePage = HID_USAGE_PAGE_PID;
  479. USAGE UsageData = HID_USAGE_PID_CUSTOM_FORCE_DATA;
  480. USAGE UsageOffset = HID_USAGE_PID_CUSTOM_FORCE_DATA_OFFSET;
  481. USHORT LinkCollection = 0x0;
  482. cbReport = this->cbReport[g_CustomData.HidP_Type];
  483. pReport = this->pReport[g_CustomData.HidP_Type];
  484. if ((this->customDataCaps.ReportCount > 0) && (this->customDataCaps.BitSize >=8))
  485. {
  486. USHORT nOffset = 0;
  487. LONG lOffset = 0;
  488. USHORT nIncrement = (this->customDataCaps.ReportCount * this->customDataCaps.BitSize)/8;
  489. // For memory managed device allocate enough memory
  490. // holding the custom force samples
  491. if( ! (this->uDeviceManaged & PID_DEVICEMANAGED ))
  492. {
  493. hres = PID_GetParameterOffset(ped, dwEffectIndex, *puParameter, this->SzPool.uSzCustom, &lOffset);
  494. }
  495. pData = pBuff;
  496. if (SUCCEEDED(hres))
  497. {
  498. //send data in a loop
  499. for (nOffset = 0; nOffset < cbData; nOffset += nIncrement)
  500. {
  501. //create a new buffer and copy data into it
  502. PCHAR pIncrement = NULL;
  503. hres = AllocCbPpv(nIncrement, &pIncrement);
  504. if (pIncrement != NULL)
  505. {
  506. ZeroBuf(pIncrement, nIncrement);
  507. memcpy(pIncrement, pData, min((cbData - nOffset), nIncrement));
  508. ZeroBuf(pReport, cbReport);
  509. //set the byte count
  510. hres = HidP_SetScaledUsageValue
  511. (
  512. HidP_Type,
  513. HID_USAGE_PAGE_GENERIC,
  514. LinkCollection,
  515. HID_USAGE_GENERIC_BYTE_COUNT,
  516. (LONG)nIncrement,
  517. this->ppd,
  518. pReport,
  519. cbReport
  520. );
  521. //set the offset
  522. hres = HidP_SetScaledUsageValue
  523. (
  524. HidP_Type,
  525. UsagePage,
  526. 0x0,
  527. //LinkCollection,
  528. UsageOffset,
  529. (LONG) (nOffset + lOffset),
  530. this->ppd,
  531. pReport,
  532. cbReport
  533. );
  534. //set the data
  535. hres = HidP_SetUsageValueArray
  536. (
  537. HidP_Type, // IN HIDP_REPORT_TYPE ReportType,
  538. UsagePage, // IN USAGE UsagePage,
  539. 0x0, // IN USHORT LinkCollection, // Optional
  540. UsageData,
  541. pIncrement, // IN PCHAR UsageValue,
  542. nIncrement, // IN USHORT UsageValueByteLength,
  543. this->ppd, // IN PHIDP_PREPARSED_DATA PreparsedData,
  544. pReport, // OUT PCHAR Report,
  545. cbReport // IN ULONG ReportLength
  546. );
  547. //set the effect index
  548. PID_PackValue
  549. (
  550. ped,
  551. &g_BlockIndex,
  552. LinkCollection,
  553. &dwEffectIndex,
  554. cbX(dwEffectIndex),
  555. pReport,
  556. cbReport
  557. );
  558. //send the report
  559. hres = PID_SendReport(ped, pReport, cbReport, HidP_Type, TRUE, 0, 1);
  560. pData += nIncrement;
  561. FreePpv(&pIncrement);
  562. }
  563. }
  564. //put data into g_PidCustom
  565. g_PidCustom.DataOffset = (DWORD)lOffset;
  566. g_PidCustom.cSamples = pCustom->cSamples;
  567. //ISSUE-2001/03/29-timgill May need to do real scaling.
  568. g_PidCustom.dwSamplePeriod = pCustom->dwSamplePeriod/1000; //in milliseconds
  569. //and increment puParameter
  570. (*puParameter)++;
  571. }
  572. }
  573. else
  574. {
  575. //do nothing
  576. }
  577. FreePpv(&pBuff);
  578. }
  579. }
  580. ExitOleProc();
  581. return hres;
  582. }
  583. STDMETHODIMP
  584. PID_DoParameterBlocks
  585. (
  586. IDirectInputEffectDriver *ped,
  587. DWORD dwId,
  588. DWORD dwEffectId,
  589. DWORD dwEffectIndex,
  590. LPCDIEFFECT peff,
  591. DWORD dwFlags,
  592. PUINT puParameter,
  593. BOOL bBlocking,
  594. UINT totalBlocks
  595. )
  596. {
  597. CPidDrv *this = (CPidDrv *)ped;
  598. HRESULT hres = S_OK;
  599. EnterProcI( PID_DoParameterBlocks, (_"xxxxxxx", ped, dwId, dwEffectId, dwEffectIndex, peff, dwFlags, puParameter ));
  600. if( SUCCEEDED(hres)
  601. && (dwFlags & DIEP_TYPESPECIFICPARAMS) )
  602. {
  603. AssertF(peff->lpvTypeSpecificParams != NULL);
  604. AssertF(peff->cbTypeSpecificParams != 0x0 );
  605. switch(dwEffectId)
  606. {
  607. case PIDMAKEUSAGEDWORD(ET_CONSTANT) :
  608. {
  609. DICONSTANTFORCE DiParam;
  610. AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
  611. memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
  612. // Constant Force:
  613. // Scale the magnitude.
  614. DiParam.lMagnitude = Clamp(-DI_FFNOMINALMAX, DiParam.lMagnitude, DI_FFNOMINALMAX);
  615. PID_ApplyScalingFactors(ped, &g_Constant, &this->DiSConstScale, cbX(this->DiSConstScale), &this->DiSConstOffset, cbX(this->DiSConstOffset), &DiParam, cbX(DiParam) );
  616. hres = PID_SendParameterBlock
  617. (
  618. ped,
  619. dwEffectIndex,
  620. this->SzPool.uSzConstant,
  621. puParameter,
  622. &g_Constant,
  623. &DiParam,
  624. cbX(DiParam),
  625. bBlocking,
  626. totalBlocks
  627. );
  628. break;
  629. }
  630. case PIDMAKEUSAGEDWORD(ET_RAMP):
  631. {
  632. // Ramp Force
  633. DIRAMPFORCE DiParam;
  634. AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
  635. memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
  636. //Scale the magnitude
  637. DiParam.lStart = Clamp(-DI_FFNOMINALMAX, DiParam.lStart, DI_FFNOMINALMAX);
  638. DiParam.lEnd = Clamp(-DI_FFNOMINALMAX, DiParam.lEnd, DI_FFNOMINALMAX);
  639. PID_ApplyScalingFactors(ped, &g_Ramp, &this->DiSRampScale, cbX(this->DiSRampScale), &this->DiSRampOffset, cbX(this->DiSRampOffset), &DiParam, cbX(DiParam) );
  640. hres = PID_SendParameterBlock
  641. (
  642. ped,
  643. dwEffectIndex,
  644. this->SzPool.uSzRamp,
  645. puParameter,
  646. &g_Ramp,
  647. &DiParam,
  648. cbX(DiParam),
  649. bBlocking,
  650. totalBlocks
  651. );
  652. break;
  653. }
  654. case PIDMAKEUSAGEDWORD(ET_SQUARE):
  655. case PIDMAKEUSAGEDWORD(ET_SINE):
  656. case PIDMAKEUSAGEDWORD(ET_TRIANGLE):
  657. case PIDMAKEUSAGEDWORD(ET_SAWTOOTH_UP):
  658. case PIDMAKEUSAGEDWORD(ET_SAWTOOTH_DOWN):
  659. {
  660. DIPERIODIC DiParam;
  661. AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
  662. memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
  663. //Scale the parameters
  664. DiParam.dwMagnitude = Clip( DiParam.dwMagnitude, DI_FFNOMINALMAX);
  665. DiParam.lOffset = Clamp(-DI_FFNOMINALMAX, DiParam.lOffset, DI_FFNOMINALMAX);
  666. //Wrap the phase around
  667. DiParam.dwPhase %= (360*DI_DEGREES);
  668. PID_ApplyScalingFactors(ped, &g_Periodic, &this->DiSPeriodicScale, cbX(this->DiSPeriodicScale), &this->DiSPeriodicOffset, cbX(this->DiSPeriodicOffset), &DiParam, cbX(DiParam) );
  669. hres = PID_SendParameterBlock
  670. (
  671. ped,
  672. dwEffectIndex,
  673. this->SzPool.uSzPeriodic,
  674. puParameter,
  675. &g_Periodic,
  676. &DiParam,
  677. cbX(DiParam),
  678. bBlocking,
  679. totalBlocks
  680. );
  681. break;
  682. }
  683. case PIDMAKEUSAGEDWORD(ET_SPRING):
  684. case PIDMAKEUSAGEDWORD(ET_DAMPER):
  685. case PIDMAKEUSAGEDWORD(ET_INERTIA):
  686. case PIDMAKEUSAGEDWORD(ET_FRICTION):
  687. {
  688. LPDICONDITION lpCondition;
  689. DWORD nStruct;
  690. DWORD cStruct = (peff->cbTypeSpecificParams)/sizeof(DICONDITION);
  691. AssertF(cStruct <= peff->cAxes);
  692. for(nStruct = 0x0, lpCondition = (LPDICONDITION)peff->lpvTypeSpecificParams;
  693. nStruct < cStruct && SUCCEEDED(hres);
  694. nStruct++, lpCondition++ )
  695. {
  696. DICONDITION DiCondition;
  697. DiCondition = *lpCondition;
  698. //Scale the values
  699. DiCondition.lOffset = Clamp(-DI_FFNOMINALMAX, DiCondition.lOffset, DI_FFNOMINALMAX);
  700. DiCondition.lPositiveCoefficient = Clamp(-DI_FFNOMINALMAX, DiCondition.lPositiveCoefficient, DI_FFNOMINALMAX);
  701. DiCondition.lNegativeCoefficient = Clamp(-DI_FFNOMINALMAX, DiCondition.lNegativeCoefficient, DI_FFNOMINALMAX);
  702. DiCondition.dwPositiveSaturation = Clip( DiCondition.dwPositiveSaturation, DI_FFNOMINALMAX);
  703. DiCondition.dwNegativeSaturation = Clip( DiCondition.dwNegativeSaturation, DI_FFNOMINALMAX);
  704. DiCondition.lDeadBand = Clamp(0, DiCondition.lDeadBand, DI_FFNOMINALMAX);
  705. PID_ApplyScalingFactors(ped, &g_Condition, &this->DiSCondScale, cbX(this->DiSCondScale), &this->DiSCondOffset, cbX(this->DiSCondOffset), &DiCondition, cbX(DiCondition) );
  706. hres = PID_SendParameterBlock
  707. (
  708. ped,
  709. dwEffectIndex,
  710. this->SzPool.uSzCondition,
  711. puParameter,
  712. &g_Condition,
  713. &DiCondition,
  714. sizeof(DiCondition),
  715. bBlocking,
  716. totalBlocks
  717. );
  718. }
  719. //Conditions can't have envelopes!
  720. //So if there's a flag indicating an envelope, take it out.
  721. dwFlags &= ~(DIEP_ENVELOPE);
  722. break;
  723. }
  724. case PIDMAKEUSAGEDWORD(ET_CUSTOM):
  725. {
  726. // Custom Force
  727. DICUSTOMFORCE DiParam;
  728. AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
  729. memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
  730. // Download Custom Force -- always a blocking call
  731. hres = PID_DownloadCustomForceData(ped, dwEffectIndex, puParameter, &DiParam, peff);
  732. if( SUCCEEDED(hres) )
  733. {
  734. // Set custom Effect parameter block header -- always a blocking call
  735. hres = PID_SendParameterBlock
  736. (
  737. ped,
  738. dwEffectIndex,
  739. this->SzPool.uSzCustom,
  740. puParameter,
  741. &g_Custom,
  742. &g_PidCustom,
  743. cbX(DiParam),
  744. TRUE,
  745. totalBlocks
  746. );
  747. }
  748. break;
  749. }
  750. default:
  751. hres = DIERR_PID_USAGENOTFOUND;
  752. SquirtSqflPtszV(sqfl | sqflError,
  753. TEXT("%s:FAIL Unknown parameter block for dwEffectId(0x%x)"),
  754. s_tszProc, dwEffectId );
  755. break;
  756. }
  757. }
  758. if( SUCCEEDED(hres)
  759. && (dwFlags & DIEP_ENVELOPE)
  760. && peff->lpEnvelope != NULL )
  761. {
  762. DIENVELOPE DiEnv;
  763. DiEnv = *peff->lpEnvelope;
  764. //Scale the values
  765. DiEnv.dwAttackLevel = Clip(DiEnv.dwAttackLevel, DI_FFNOMINALMAX);
  766. DiEnv.dwFadeLevel = Clip(DiEnv.dwFadeLevel, DI_FFNOMINALMAX);
  767. PID_ApplyScalingFactors(ped, &g_Envelope, &this->DiSEnvScale, cbX(this->DiSEnvScale), &this->DiSEnvOffset, cbX(this->DiSEnvOffset), &DiEnv, DiEnv.dwSize );
  768. hres = PID_SendParameterBlock
  769. (
  770. ped,
  771. dwEffectIndex,
  772. this->SzPool.uSzEnvelope,
  773. puParameter,
  774. &g_Envelope,
  775. &DiEnv,
  776. DiEnv.dwSize,
  777. bBlocking,
  778. totalBlocks
  779. );
  780. }
  781. ExitOleProc();
  782. return hres;
  783. }