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.

885 lines
28 KiB

  1. /****************************************************************************
  2. MODULE: SW_CImpI.CPP
  3. Tab Settings: 5 9
  4. Copyright 1995, 1996, Microsoft Corporation, All Rights Reserved.
  5. PURPOSE: IDEffect Implementation.
  6. Function(s):
  7. CImpIDirectInputEffectDriver::DeviceID
  8. CImpIDirectInputEffectDriver::GetVersions
  9. CImpIDirectInputEffectDriver::Escape
  10. CImpIDirectInputEffectDriver::SetGain
  11. CImpIDirectInputEffectDriver::SendForceFeedbackCommand
  12. CImpIDirectInputEffectDriver::GetForceFeedbackState
  13. CImpIDirectInputEffectDriver::DownloadEffect
  14. CImpIDirectInputEffectDriver::DestroyEffect
  15. CImpIDirectInputEffectDriver::StartEffect
  16. CImpIDirectInputEffectDriver::StopEffect
  17. CImpIDirectInputEffectDriver::GetEffectStatus
  18. Author(s): Name:
  19. ---------- ----------------
  20. MEA Manolito E. Adan
  21. Revision History:
  22. -----------------
  23. Version Date Author Comments
  24. ------- ------ ----- -------------------------------------------
  25. 1.0 06-Feb-97 MEA original, Based on SWForce
  26. 23-Feb-97 MEA Modified for DirectInput FF Device Driver
  27. 23-Mar-97 MEA/DS Added VFX support
  28. 16-Mar-99 waltw GetFirmwareParams, GetSystemParams,
  29. CMD_Download_RTCSpring, GetDelayParams,
  30. GetJoystickParams, & UpdateJoystickParams
  31. calls removed from DeviceID since they are
  32. called from g_pJoltMidi->Initialize.
  33. 23-Mar-99 waltw GetEffectStatus now uses data returned by
  34. Transmit instead of obsolete GetStatusGateData
  35. ****************************************************************************/
  36. #include <windows.h>
  37. #include <math.h>
  38. #include <assert.h>
  39. #include "dinput.h"
  40. #include "dinputd.h"
  41. #include "SW_objec.hpp"
  42. #include "hau_midi.hpp"
  43. #include "ffd_swff.hpp"
  44. #include "FFDevice.h"
  45. #include "DPack.h"
  46. #include "DTrans.h"
  47. #include <ntverp.h>
  48. #include "CritSec.h"
  49. /****************************************************************************
  50. Declaration of externs
  51. ****************************************************************************/
  52. #ifdef _DEBUG
  53. extern char g_cMsg[160];
  54. extern TCHAR szDeviceName[MAX_SIZE_SNAME];
  55. extern void DebugOut(LPCTSTR szDebug);
  56. #else !_DEBUG
  57. #define DebugOut(x)
  58. #endif _DEBUG
  59. extern CJoltMidi *g_pJoltMidi;
  60. // To convert a nack error code to a DIError code
  61. HRESULT g_NackToError[] =
  62. {
  63. SFERR_DRIVER_ERROR, // DEV_ERR_SUCCESS_200 - but it NACKd!
  64. SWDEV_ERR_INVALID_ID, // DEV_ERR_INVALID_ID_200
  65. SWDEV_ERR_INVALID_PARAM, // DEV_ERR_BAD_PARAM_200
  66. SWDEV_ERR_CHECKSUM, // DEV_ERR_BAD_CHECKSUM_200
  67. SFERR_DRIVER_ERROR, // DEV_ERR_BAD_INDEX_200
  68. SWDEV_ERR_UNKNOWN_CMD, // DEV_ERR_UNKNOWN_CMD_200
  69. SWDEV_ERR_PLAYLIST_FULL, // DEV_ERR_PLAY_FULL_200
  70. DIERR_DEVICEFULL, // DEV_ERR_MEM_FULL_200
  71. MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BUSY) // DEV_ERR_BANDWIDTH_FULL_200
  72. };
  73. // ****************************************************************************
  74. // *** --- Member functions for base class CImpIDirectInputEffectDriver Interface
  75. //
  76. // ****************************************************************************
  77. //
  78. // ----------------------------------------------------------------------------
  79. // Function: CImpIDirectInputEffectDriver::CImpIDirectInputEffectDriver
  80. // Purpose: Constructor(s)/Destructor for CImpIDirectInputEffectDriver Object
  81. // Parameters: PCDirectInputEffectDriver pObj - Ptr to the outer object
  82. //
  83. // Returns:
  84. // Algorithm:
  85. // ----------------------------------------------------------------------------
  86. CImpIDirectInputEffectDriver::CImpIDirectInputEffectDriver(PCDirectInputEffectDriver pObj)
  87. {
  88. m_cRef=0;
  89. m_pObj=pObj;
  90. m_pJoltMidi = NULL; // The Jolt Device object
  91. return;
  92. }
  93. CImpIDirectInputEffectDriver::~CImpIDirectInputEffectDriver(void)
  94. {
  95. DebugOut("CImpIDirectInputEffectDriver::~CImpIDirectInputEffectDriver()\n");
  96. // Destroy the CEffect object we created and release any interfaces
  97. if (g_pJoltMidi)
  98. {
  99. delete g_pJoltMidi;
  100. g_pJoltMidi = NULL;
  101. }
  102. // No critical section here because g_CriticalSection already destroyed
  103. DebugOut("CImpIDirectInputEffectDriver::~CimpIDEffect()\n");
  104. }
  105. // ----------------------------------------------------------------------------
  106. // Function: CImpIDirectInputEffectDriver::QueryInterface
  107. // CImpIDirectInputEffectDriver::AddRef
  108. // CImpIDirectInputEffectDriver::Release
  109. //
  110. // Purpose: IUnknown members that delegate to m_pObj
  111. // Parameters:
  112. //
  113. // Returns:
  114. // Algorithm:
  115. // ----------------------------------------------------------------------------
  116. STDMETHODIMP CImpIDirectInputEffectDriver::QueryInterface(REFIID riid, PPVOID ppv)
  117. {
  118. return m_pObj->QueryInterface(riid, ppv);
  119. }
  120. DWORD CImpIDirectInputEffectDriver::AddRef(void)
  121. {
  122. //
  123. // We maintain an "interface reference count" for debugging
  124. // purposes, because the client of an object should match
  125. // AddRef and Release calls through each interface pointer.
  126. //
  127. ++m_cRef;
  128. return m_pObj->AddRef();
  129. }
  130. DWORD CImpIDirectInputEffectDriver::Release(void)
  131. {
  132. // m_cRef is again only for debugging. It doesn't affect
  133. // CSWEffect although the call to m_pObj->Release does.
  134. --m_cRef;
  135. return m_pObj->Release();
  136. }
  137. // ----------------------------------------------------------------------------
  138. // Function: DeviceID
  139. //
  140. // Purpose:
  141. // Parameters: DWORD dwExternalID -The joystick ID number being us
  142. // DWORD fBegin -Nonzero if access to the device is beginning; Zero if ending
  143. // DWORD dwInternalID -Internal joystick id
  144. // LPVOID lpReserved -Reserved for future use (HID)
  145. //
  146. // Returns: SUCCESS or Error code
  147. //
  148. // Algorithm:
  149. // ----------------------------------------------------------------------------
  150. HRESULT CImpIDirectInputEffectDriver::DeviceID(
  151. IN DWORD dwDirectInputVersion,
  152. IN DWORD dwExternalID,
  153. IN DWORD fBegin,
  154. IN DWORD dwInternalID,
  155. LPVOID lpReserved)
  156. {
  157. #ifdef _DEBUG
  158. g_CriticalSection.Enter();
  159. wsprintf(g_cMsg,"CImpIDirectInputEffectDriver::DeviceID(%lu, %lu, %lu, %lu, %lx)\n", dwDirectInputVersion, dwExternalID, fBegin, dwInternalID, lpReserved);
  160. _RPT0(_CRT_WARN, g_cMsg);
  161. g_CriticalSection.Leave();
  162. #endif // _DEBUG
  163. if (g_pDataPackager) {
  164. g_pDataPackager->SetDirectInputVersion(dwDirectInputVersion);
  165. }
  166. assert(NULL == g_pJoltMidi);
  167. // Create and Initialize our CJoltMidi object
  168. #ifdef _DEBUG
  169. OutputDebugString("Creating and Initializing CJoltMidi object\n");
  170. #endif
  171. g_pJoltMidi = new CJoltMidi();
  172. if (NULL == g_pJoltMidi)
  173. {
  174. return (E_OUTOFMEMORY);
  175. }
  176. else
  177. {
  178. return g_pJoltMidi->Initialize(dwExternalID);
  179. }
  180. }
  181. // ----------------------------------------------------------------------------
  182. // Function: GetVersions
  183. //
  184. // Purpose:
  185. // Parameters: LPDIDRIVERVERSIONS pvers -Pointer to structure which receives version info
  186. //
  187. // Returns: SUCCESS or Error code
  188. //
  189. // Algorithm:
  190. // ----------------------------------------------------------------------------
  191. HRESULT CImpIDirectInputEffectDriver::GetVersions(
  192. IN OUT LPDIDRIVERVERSIONS pvers)
  193. {
  194. if (g_pJoltMidi == NULL) {
  195. return E_FAIL;
  196. }
  197. LOCAL_PRODUCT_ID* pProductID = g_pJoltMidi->ProductIDPtrOf();
  198. if (pProductID == NULL) {
  199. return E_FAIL;
  200. }
  201. pvers->dwFirmwareRevision = (pProductID->dwFWMajVersion << 8) | (pProductID->dwFWMinVersion);
  202. pvers->dwHardwareRevision = pProductID->dwProductID;
  203. // Get version from ntverp.h (was FULLVersion from version.h)
  204. pvers->dwFFDriverVersion = VER_PRODUCTVERSION_DW;
  205. #ifdef _DEBUG
  206. g_CriticalSection.Enter();
  207. wsprintf(g_cMsg,"CImpIDirectInputEffectDriver::GetVersions(%lu, %lu, %lu)\n", pvers->dwFirmwareRevision, pvers->dwHardwareRevision, pvers->dwFFDriverVersion);
  208. _RPT0(_CRT_WARN, g_cMsg);
  209. g_CriticalSection.Leave();
  210. #endif // _DEBUG
  211. return SUCCESS;
  212. }
  213. // ----------------------------------------------------------------------------
  214. // Function: Escape
  215. //
  216. // Purpose:
  217. // Parameters: DWORD dwDeviceID - Device ID
  218. // LPDIEFFESCAPE pEsc - Pointer to a DIFEFESCAPE struct
  219. //
  220. //
  221. // Returns: SUCCESS or Error code
  222. //
  223. // Algorithm:
  224. // ----------------------------------------------------------------------------
  225. HRESULT CImpIDirectInputEffectDriver::Escape(
  226. IN DWORD dwDeviceID,
  227. IN DWORD dwEffectID,
  228. IN OUT LPDIEFFESCAPE pEsc )
  229. {
  230. ASSUME_NOT_NULL(g_pDataPackager);
  231. ASSUME_NOT_NULL(g_pDataTransmitter);
  232. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  233. return SFERR_DRIVER_ERROR;
  234. }
  235. // Create a command/data packet - send it of to the stick
  236. HRESULT hr = g_pDataPackager->Escape(dwEffectID, pEsc);
  237. if (hr != SUCCESS) {
  238. return hr;
  239. }
  240. ACKNACK ackNack;
  241. return g_pDataTransmitter->Transmit(ackNack); // Send it off
  242. }
  243. // ----------------------------------------------------------------------------
  244. // Function: SetGain
  245. //
  246. // Purpose:
  247. // Parameters: DWORD dwDeviceID - Device ID
  248. // DWORD dwGain - Device gain
  249. //
  250. //
  251. // Returns: SUCCESS or Error code
  252. //
  253. // Algorithm:
  254. // ----------------------------------------------------------------------------
  255. HRESULT CImpIDirectInputEffectDriver::SetGain(
  256. IN DWORD dwDeviceID,
  257. IN DWORD dwGain)
  258. {
  259. #ifdef _DEBUG
  260. g_CriticalSection.Enter();
  261. wsprintf(g_cMsg, "SetGain: %s Gain=%ld\r\n", &szDeviceName, dwGain);
  262. _RPT0(_CRT_WARN, g_cMsg);
  263. g_CriticalSection.Leave();
  264. #endif
  265. ASSUME_NOT_NULL(g_pDataPackager);
  266. ASSUME_NOT_NULL(g_pDataTransmitter);
  267. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  268. return SFERR_DRIVER_ERROR;
  269. }
  270. BOOL truncation = (dwGain > 10000);
  271. if (truncation) {
  272. dwGain = 10000;
  273. }
  274. // Create a command/data packet - send it of to the stick
  275. HRESULT hr = g_pDataPackager->SetGain(dwGain);
  276. if (FAILED(hr)) {
  277. return hr;
  278. }
  279. ACKNACK ackNack;
  280. hr = g_pDataTransmitter->Transmit(ackNack); // Send it off
  281. if ((hr == SUCCESS) && (truncation)) {
  282. return DI_TRUNCATED;
  283. }
  284. return hr;
  285. }
  286. // ----------------------------------------------------------------------------
  287. // Function: SendForceFeedbackCommand
  288. //
  289. // Purpose:
  290. // Parameters: DWORD dwDeviceID - Device ID
  291. // DWORD dwState - Command to set Device state
  292. //
  293. //
  294. // Returns: SUCCESS or Error code
  295. //
  296. // Need to map the following DX to Jolt
  297. // DS_FORCE_SHUTDOWN 0x00000001 // Actuators (Motors) are enabled.
  298. // DS_FORCE_ON 0x00000002 // Actuators (Motors) are disabled.
  299. // DS_FORCE_OFF 0x00000003 // All Effects are "Paused"
  300. // DS_CONTINUE 0x00000004 // All "Paused" Effects are continued
  301. // DS_PAUSE 0x00000005 // All Effects are stopped.
  302. // DS_STOP_ALL 0x00000006 // All Effects destroyed,Motors disabled
  303. //
  304. // Jolt Device ulMode:
  305. // SWDEV_SHUTDOWN 1L // All Effects destroyed, Motors disabled
  306. // SWDEV_FORCE_ON 2L // Motors enabled. "Un-Mute"
  307. // SWDEV_FORCE_OFF 3L // Motors disabled. "Mute"
  308. // SWDEV_CONTINUE 4L // All "Paused" Effects are allow to continue
  309. // SWDEV_PAUSE 5L // All Effects are "Paused"
  310. // SWDEV_STOP_ALL 6L // Stops all Effects.
  311. //
  312. // Algorithm:
  313. // ----------------------------------------------------------------------------
  314. HRESULT CImpIDirectInputEffectDriver::SendForceFeedbackCommand(
  315. IN DWORD dwDeviceID,
  316. IN DWORD dwState)
  317. {
  318. ASSUME_NOT_NULL(g_pDataPackager);
  319. ASSUME_NOT_NULL(g_pDataTransmitter);
  320. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  321. return SFERR_DRIVER_ERROR;
  322. }
  323. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  324. // Create a command/data packet - send it of to the stick
  325. HRESULT hr = g_pDataPackager->SendForceFeedbackCommand(dwState);
  326. if (hr != SUCCESS) {
  327. return hr;
  328. }
  329. ACKNACK ackNack;
  330. hr = g_pDataTransmitter->Transmit(ackNack); // Send it off
  331. if (hr == SUCCESS) {
  332. g_ForceFeedbackDevice.StateChange(dwDeviceID, dwState);
  333. g_pJoltMidi->UpdateDeviceMode(dwState);
  334. }
  335. return hr;
  336. }
  337. // ----------------------------------------------------------------------------
  338. // Function: GetForceFeedbackState
  339. //
  340. // Purpose:
  341. // Parameters: DWORD dwDeviceID - Device ID
  342. // LPDIDEVICESTATE pDeviceState - Pointer to a DIDEVICESTATE struct
  343. //
  344. // Returns: SUCCESS or Error code and state updated in pDeviceState
  345. //
  346. // Member: dwState
  347. // DS_FORCE_SHUTDOWN 0x00000001
  348. // DS_FORCE_ON 0x00000002
  349. // DS_FORCE_OFF 0x00000003
  350. // DS_CONTINUE 0x00000004
  351. // DS_PAUSE 0x00000005
  352. // DS_STOP_ALL 0x00000006
  353. //
  354. // Member: dwSwitches
  355. // DSW_ACTUATORSON 0x00000001
  356. // DSW_ACTUATORSOFF 0x00000002
  357. // DSW_POWERON 0x00000004
  358. // DSW_POWEROFF 0x00000008
  359. // DSW_SAFETYSWITCHON 0x00000010
  360. // DSW_SAFETYSWITCHOFF 0x00000020
  361. // DSW_USERFFSWITCHON 0x00000040
  362. // DSW_USERFFSWTTCHOFF 0x00000080
  363. //
  364. // Algorithm:
  365. // This is the DI Device State structure
  366. //typedef struct DIDEVICESTATE {
  367. // DWORD dwSize;
  368. // DWORD dwState;
  369. // DWORD dwSwitches;
  370. // DWORD dwLoading;
  371. //} DEVICESTATE, *LPDEVICESTATE;
  372. //
  373. // This is the SideWinder State structure (copy kept in CJoltMidi object)
  374. //typedef struct _SWDEVICESTATE {
  375. // ULONG m_Bytes; // size of this structure
  376. // ULONG m_ForceState; // DS_FORCE_ON || DS_FORCE_OFF || DS_SHUTDOWN
  377. // ULONG m_EffectState; // DS_STOP_ALL || DS_CONTINUE || DS_PAUSE
  378. // ULONG m_HOTS; // Hands On Throttle and Stick Status
  379. // // 0 = Hands Off, 1 = Hands On
  380. // ULONG m_BandWidth; // Percentage of CPU available 1 to 100%
  381. // // Lower number indicates CPU is in trouble!
  382. // ULONG m_ACBrickFault; // 0 = AC Brick OK, 1 = AC Brick Fault
  383. // ULONG m_ResetDetect; // 1 = HW Reset Detected
  384. // ULONG m_ShutdownDetect; // 1 = Shutdown detected
  385. // ULONG m_CommMode; // 0 = Midi, 1-4 = Serial
  386. //} SWDEVICESTATE, *PSWDEVICESTATE;
  387. //
  388. // Note: Apparently, DSW_ACTUATORSON and DSW_ACTUATORSOFF is a mirrored state
  389. // from DS_FORCE_ON and DS_FORCE_OFF as set from SetForceFeedbackState
  390. //
  391. // ----------------------------------------------------------------------------
  392. HRESULT CImpIDirectInputEffectDriver::GetForceFeedbackState(
  393. IN DWORD dwDeviceID,
  394. IN LPDIDEVICESTATE pDeviceState)
  395. {
  396. // Driver sanity Check;
  397. if (g_pJoltMidi == NULL) {
  398. ASSUME_NOT_REACHED();
  399. return SFERR_DRIVER_ERROR;
  400. }
  401. // User sanity check
  402. if (pDeviceState == NULL) {
  403. ASSUME_NOT_REACHED();
  404. return SFERR_INVALID_PARAM;
  405. }
  406. if (pDeviceState->dwSize != sizeof(DIDEVICESTATE)) {
  407. ASSUME_NOT_REACHED(); // Has structure changed?
  408. return SFERR_INVALID_PARAM;
  409. }
  410. // Fix 1.20 state bug (needs to be changed for jolt support)
  411. if ((g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) && (g_ForceFeedbackDevice.GetFirmwareVersionMinor() == 20)) {
  412. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  413. return SFERR_DRIVER_ERROR;
  414. }
  415. HRESULT hr;
  416. if ((g_pJoltMidi->GetSWDeviceStateNoUpdate().m_ForceState == SWDEV_FORCE_OFF)) { // Echo state back to fix 1.20 bug
  417. hr = g_pDataPackager->SendForceFeedbackCommand(SWDEV_FORCE_OFF);
  418. } else {
  419. hr = g_pDataPackager->SendForceFeedbackCommand(SWDEV_FORCE_ON);
  420. }
  421. if (hr != SUCCESS) {
  422. return hr;
  423. }
  424. ACKNACK ackNack;
  425. g_pDataTransmitter->Transmit(ackNack); // Send it off
  426. }
  427. pDeviceState->dwState = 0;
  428. // Ask the device for state
  429. HRESULT hRet = g_ForceFeedbackDevice.QueryStatus();
  430. if (hRet != SUCCESS) {
  431. return hRet;
  432. }
  433. // Set flags from the device
  434. if (g_ForceFeedbackDevice.IsUserDisable()) {
  435. pDeviceState->dwState = DIGFFS_SAFETYSWITCHOFF;
  436. } else {
  437. pDeviceState->dwState = DIGFFS_SAFETYSWITCHON;
  438. }
  439. if (g_ForceFeedbackDevice.IsHostDisable()) {
  440. pDeviceState->dwState |= DIGFFS_ACTUATORSOFF;
  441. } else {
  442. pDeviceState->dwState |= DIGFFS_ACTUATORSON;
  443. }
  444. if (g_ForceFeedbackDevice.IsHostPause()) {
  445. pDeviceState->dwState |= DIGFFS_PAUSED;
  446. }
  447. // All effects been stopped from host?
  448. if (g_ForceFeedbackDevice.GetDIState() == DIGFFS_STOPPED) {
  449. pDeviceState->dwState |= DIGFFS_STOPPED;
  450. }
  451. // Have any effects been created?
  452. BOOL bEmpty = TRUE;
  453. for (int i=2; i < MAX_EFFECT_IDS; i++) {
  454. if (g_ForceFeedbackDevice.GetEffect(i) != NULL) {
  455. bEmpty = FALSE;
  456. break;
  457. }
  458. }
  459. if(bEmpty) {
  460. pDeviceState->dwState |= DIGFFS_EMPTY;
  461. }
  462. // NYI Firmware
  463. /* if (m_DeviceState.m_ACBrickFault)
  464. pDeviceState->dwState |= DIGFFS_POWEROFF;
  465. else
  466. pDeviceState->dwState |= DIGFFS_POWERON;
  467. */
  468. pDeviceState->dwState |= DIGFFS_POWERON; // Always on in Zep (and Zep is on or we wouldn't be here)
  469. pDeviceState->dwLoad = 0;
  470. return hRet;
  471. }
  472. // ----------------------------------------------------------------------------
  473. // Function: DownloadEffect
  474. //
  475. // Purpose:
  476. // Parameters: DWORD dwDeviceID - Device ID
  477. // DWORD dwInternalEffectType - Internal Effect Type
  478. // IN OUT LPDWORD pDnloadID - Pointer to a DWORD for DnloadID
  479. // IN LPCDIEFFECT pEffect - Pointer to a DIEFFECT structure
  480. // IN DWORD dwFlags - for parameters that changed
  481. //
  482. //
  483. // Returns: SUCCESS or Error code
  484. //
  485. // Algorithm:
  486. // The following dwFlags may be sent by the kernel
  487. //
  488. //#define DIEP_ALLPARAMS 0x000000FF - All fields valid
  489. //#define DIEP_AXES 0x00000020 - cAxes and rgdwAxes
  490. //#define DIEP_DIRECTION 0x00000040 - cAxes and rglDirection
  491. //#define DIEP_DURATION 0x00000001 - dwDuration
  492. //#define DIEP_ENVELOPE 0x00000080 - lpEnvelope
  493. //#define DIEP_GAIN 0x00000004 - dwGain
  494. //#define DIEP_NODOWNLOAD 0x80000000 - suppress auto - download
  495. //#define DIEP_SAMPLEPERIOD 0x00000002 - dwSamplePeriod
  496. //#define DIEP_TRIGGERBUTTON 0x00000008 - dwTriggerButton
  497. //#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 - dwTriggerRepeatInterval
  498. //#define DIEP_TYPESPECIFICPARAMS 0x00000100 - cbTypeSpecificParams
  499. // and lpTypeSpecificParams
  500. // Jolt has two options for downloading - Full SysEx or Modify Parameter
  501. // Pass the dwFlags to each CMD_xxx function and let the MIDI function
  502. // determine whether to use SysEx or Modify Parameter.
  503. //
  504. // ----------------------------------------------------------------------------
  505. HRESULT CImpIDirectInputEffectDriver::DownloadEffect(
  506. IN DWORD dwDeviceID,
  507. IN DWORD dwInternalEffectType,
  508. IN OUT LPDWORD pDnloadID,
  509. IN LPCDIEFFECT pEffect,
  510. IN DWORD dwFlags)
  511. {
  512. #ifdef _DEBUG
  513. g_CriticalSection.Enter();
  514. wsprintf(g_cMsg, "%s 3Effect. DnloadID= %ld, Type=%lx, dwFlags= %lx\r\n",
  515. &szDeviceName[0], *pDnloadID, dwInternalEffectType, dwFlags);
  516. _RPT0(_CRT_WARN, g_cMsg);
  517. g_CriticalSection.Leave();
  518. #endif
  519. // Quick sanity check
  520. if ((pEffect == NULL) || (pDnloadID == NULL)) {
  521. ASSUME_NOT_REACHED();
  522. return SFERR_INVALID_PARAM;
  523. }
  524. // Are we setup properly
  525. ASSUME_NOT_NULL(g_pDataPackager);
  526. ASSUME_NOT_NULL(g_pDataTransmitter);
  527. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  528. return SFERR_DRIVER_ERROR;
  529. }
  530. HRESULT hr = SFERR_DRIVER_ERROR;
  531. HRESULT createResult = SUCCESS;
  532. BOOL downLoad = (dwFlags & DIEP_NODOWNLOAD) == 0;
  533. BOOL createdAttempted = FALSE;
  534. InternalEffect* pLocalEffect = NULL;
  535. if (*pDnloadID != 0) { // 0 Indicates create new
  536. pLocalEffect = g_ForceFeedbackDevice.GetEffect(*pDnloadID);
  537. }
  538. if (pLocalEffect == NULL) { // New effect create it (or Raw Force)
  539. createdAttempted = TRUE;
  540. BOOL wasZero = (*pDnloadID == 0);
  541. pLocalEffect = g_ForceFeedbackDevice.CreateEffect(dwInternalEffectType, *pEffect, *pDnloadID, createResult, (downLoad == FALSE));
  542. if (FAILED(createResult)) {
  543. return createResult;
  544. }
  545. if (pLocalEffect == NULL) {
  546. if ((*pDnloadID == RAW_FORCE_ALIAS) && (wasZero == FALSE)) {
  547. if ((dwFlags & (DIEP_DURATION | DIEP_SAMPLEPERIOD | DIEP_GAIN | DIEP_TRIGGERREPEATINTERVAL | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE)) != 0) {
  548. return S_FALSE;
  549. }
  550. }
  551. return createResult;
  552. }
  553. hr = g_pDataPackager->CreateEffect(*pLocalEffect, dwFlags);
  554. if (!downLoad) {
  555. delete pLocalEffect;
  556. pLocalEffect = NULL;
  557. }
  558. } else { // Effect Exists, modify it
  559. InternalEffect* pDIEffect = g_ForceFeedbackDevice.CreateEffect(dwInternalEffectType, *pEffect, *pDnloadID, createResult, (downLoad == FALSE)); // Create new
  560. if ((pDIEffect == NULL) || (FAILED(createResult))) {
  561. return createResult;
  562. }
  563. hr = g_pDataPackager->ModifyEffect(*pLocalEffect, *pDIEffect, dwFlags); // Package relative changes
  564. if (FAILED(hr)) {
  565. delete pDIEffect;
  566. return hr;
  567. }
  568. if (downLoad) {
  569. g_ForceFeedbackDevice.SetEffect(BYTE(*pDnloadID), pDIEffect); // Replace the old with the new
  570. pDIEffect->SetDeviceID(pLocalEffect->GetDeviceID()); // Update device IDs
  571. delete pLocalEffect; // Delete the old
  572. } else {
  573. delete pDIEffect;
  574. }
  575. }
  576. if ((FAILED(hr)) || (downLoad == FALSE)) {
  577. return hr;
  578. }
  579. HRESULT modProblems = hr;
  580. ACKNACK ackNack;
  581. hr = g_pDataTransmitter->Transmit(ackNack); // Send it off
  582. if (hr == SFERR_DEVICE_NACK) {
  583. if (ackNack.dwErrorCode <= DEV_ERR_BANDWIDTH_FULL_200) {
  584. return g_NackToError[ackNack.dwErrorCode];
  585. } else {
  586. return SFERR_DRIVER_ERROR;
  587. }
  588. }
  589. if (FAILED(hr)) {
  590. return hr;
  591. }
  592. if (createdAttempted == TRUE) {
  593. g_ForceFeedbackDevice.SetDeviceIDFromStatusPacket(*pDnloadID);
  594. }
  595. // Check for start flag
  596. if (dwFlags & DIEP_START) {
  597. // Create a command/data packet - send it of to the stick
  598. HRESULT hr = g_pDataPackager->StartEffect(*pDnloadID, 0, 1);
  599. if (hr != SUCCESS) {
  600. return hr;
  601. }
  602. hr = g_pDataTransmitter->Transmit(ackNack); // Send it off
  603. if (hr == SFERR_DEVICE_NACK) {
  604. if (ackNack.dwErrorCode <= DEV_ERR_BANDWIDTH_FULL_200) {
  605. return g_NackToError[ackNack.dwErrorCode];
  606. } else {
  607. return SFERR_DRIVER_ERROR;
  608. }
  609. }
  610. pLocalEffect->SetPlaying(TRUE);
  611. return hr;
  612. }
  613. if (createResult != SUCCESS) { // Truncation and whatnot
  614. return createResult;
  615. }
  616. return modProblems; // Wow we got this far!
  617. }
  618. // ----------------------------------------------------------------------------
  619. // Function: DestroyEffect
  620. //
  621. // Purpose:
  622. // Parameters: DWORD dwDeviceID - Device ID
  623. // DWORD DnloadID - Download ID to destroy
  624. //
  625. //
  626. // Returns: SUCCESS or Error code
  627. //
  628. // Algorithm:
  629. // ----------------------------------------------------------------------------
  630. HRESULT CImpIDirectInputEffectDriver::DestroyEffect(
  631. IN DWORD dwDeviceID,
  632. IN DWORD DnloadID)
  633. {
  634. #ifdef _DEBUG
  635. g_CriticalSection.Enter();
  636. wsprintf(g_cMsg, "%s DestroyEffect. DnloadID:%ld\r\n",
  637. &szDeviceName[0], DnloadID);
  638. _RPT0(_CRT_WARN, g_cMsg);
  639. g_CriticalSection.Leave();
  640. #endif
  641. ASSUME_NOT_NULL(g_pDataPackager);
  642. ASSUME_NOT_NULL(g_pDataTransmitter);
  643. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  644. return SFERR_DRIVER_ERROR;
  645. }
  646. // Create a command/data packet - send it of to the stick
  647. HRESULT hr = g_pDataPackager->DestroyEffect(DnloadID);
  648. if (hr != SUCCESS) {
  649. return hr;
  650. }
  651. ACKNACK ackNack;
  652. return g_pDataTransmitter->Transmit(ackNack); // Send it off
  653. }
  654. // ----------------------------------------------------------------------------
  655. // Function: StartEffect
  656. //
  657. // Purpose:
  658. // Parameters: DWORD dwDeviceID - Device ID
  659. // DWORD DnloadID - Download ID to Start
  660. // DWORD dwMode - Playback mode
  661. // DWORD dwCount - Loop count
  662. //
  663. //
  664. // Returns: SUCCESS or Error code
  665. //
  666. // dwMode: Playback mode is available with the following options:
  667. // PLAY_SOLO - stop other forces playing, make this the only one.
  668. // PLAY_SUPERIMPOSE- mix with currently playing device
  669. // Algorithm:
  670. // ----------------------------------------------------------------------------
  671. HRESULT CImpIDirectInputEffectDriver::StartEffect(
  672. IN DWORD dwDeviceID,
  673. IN DWORD DnloadID,
  674. IN DWORD dwMode,
  675. IN DWORD dwCount)
  676. {
  677. #ifdef _DEBUG
  678. g_CriticalSection.Enter();
  679. wsprintf(g_cMsg, "%s StartEffect. DnloadID:%ld, Mode:%lx, Count:%lx\r\n",
  680. &szDeviceName[0], DnloadID, dwMode, dwCount);
  681. _RPT0(_CRT_WARN, g_cMsg);
  682. g_CriticalSection.Leave();
  683. #endif
  684. ASSUME_NOT_NULL(g_pDataPackager);
  685. ASSUME_NOT_NULL(g_pDataTransmitter);
  686. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  687. return SFERR_DRIVER_ERROR;
  688. }
  689. // Create a command/data packet - send it of to the stick
  690. HRESULT packageResult = g_pDataPackager->StartEffect(DnloadID, dwMode, dwCount);
  691. if (FAILED(packageResult)) {
  692. return packageResult;
  693. }
  694. ACKNACK ackNack;
  695. HRESULT hr = g_pDataTransmitter->Transmit(ackNack); // Send it off
  696. if (hr == SFERR_DEVICE_NACK) {
  697. if (ackNack.dwErrorCode <= DEV_ERR_BANDWIDTH_FULL_200) {
  698. return g_NackToError[ackNack.dwErrorCode];
  699. } else {
  700. return SFERR_DRIVER_ERROR;
  701. }
  702. }
  703. InternalEffect* pEffect = g_ForceFeedbackDevice.GetEffect(DnloadID);
  704. if (pEffect != NULL) {
  705. pEffect->SetPlaying(TRUE);
  706. }
  707. if (hr == SUCCESS) {
  708. return packageResult;
  709. }
  710. return hr;
  711. }
  712. // ----------------------------------------------------------------------------
  713. // Function: StopEffect
  714. //
  715. // Purpose:
  716. // Parameters: DWORD dwDeviceID - Device ID
  717. // DWORD DnloadID - Download ID to Stop
  718. //
  719. //
  720. // Returns: SUCCESS or Error code
  721. //
  722. // Algorithm:
  723. // ----------------------------------------------------------------------------
  724. HRESULT CImpIDirectInputEffectDriver::StopEffect(
  725. IN DWORD dwDeviceID,
  726. IN DWORD DnloadID)
  727. {
  728. #ifdef _DEBUG
  729. g_CriticalSection.Enter();
  730. wsprintf(g_cMsg, "%s StopEffect. DnloadID:%ld\r\n",
  731. &szDeviceName[0], DnloadID);
  732. _RPT0(_CRT_WARN, g_cMsg);
  733. g_CriticalSection.Leave();
  734. #endif
  735. ASSUME_NOT_NULL(g_pDataPackager);
  736. ASSUME_NOT_NULL(g_pDataTransmitter);
  737. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  738. return SFERR_DRIVER_ERROR;
  739. }
  740. // Create a command/data packet - send it of to the stick
  741. HRESULT hr = g_pDataPackager->StopEffect(DnloadID);
  742. if (hr != SUCCESS) {
  743. return hr;
  744. }
  745. ACKNACK ackNack;
  746. return g_pDataTransmitter->Transmit(ackNack); // Send it off
  747. }
  748. // ----------------------------------------------------------------------------
  749. // Function: GetEffectStatus
  750. //
  751. // Purpose:
  752. // Parameters: DWORD dwDeviceID - Device ID
  753. // DWORD DnloadID - Download ID to get Status
  754. // LPDWORD pdwStatusCode - Pointer to a DWORD for Status
  755. //
  756. //
  757. // Returns: SUCCESS or Error code
  758. // Status Code: DEV_STS_EFFECT_STOPPED
  759. // DEV_STS_EFFECT_RUNNING
  760. //
  761. // Algorithm:
  762. // ----------------------------------------------------------------------------
  763. HRESULT CImpIDirectInputEffectDriver::GetEffectStatus(
  764. IN DWORD dwDeviceID,
  765. IN DWORD DnloadID,
  766. OUT LPDWORD pdwStatusCode)
  767. {
  768. HRESULT hRet = SUCCESS;
  769. #ifdef _DEBUG
  770. g_CriticalSection.Enter();
  771. wsprintf(g_cMsg, "GetEffectStatus, DnloadID=%d\r\n", DnloadID);
  772. _RPT0(_CRT_WARN, g_cMsg);
  773. g_CriticalSection.Leave();
  774. #endif
  775. ASSUME_NOT_NULL(g_pDataPackager);
  776. ASSUME_NOT_NULL(g_pDataTransmitter);
  777. ASSUME_NOT_NULL(pdwStatusCode);
  778. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL) || (pdwStatusCode == NULL)) {
  779. return SFERR_DRIVER_ERROR;
  780. }
  781. // Create a command/data packet - send it of to the stick
  782. HRESULT hr = g_pDataPackager->GetEffectStatus(DnloadID);
  783. if (hr != SUCCESS) {
  784. return hr;
  785. }
  786. ACKNACK ackNack;
  787. hr = g_pDataTransmitter->Transmit(ackNack); // Send it off
  788. if (hr != SUCCESS) {
  789. return hr;
  790. }
  791. // Use result returned by GetAckNackData in Transmit
  792. DWORD dwIn = ackNack.dwEffectStatus;
  793. // Interpret result (cooked RUNNING_MASK_200 becomes SWDEV_STS_EFFECT_RUNNING)
  794. if ((g_ForceFeedbackDevice.GetDriverVersionMajor() != 1) && (dwIn & SWDEV_STS_EFFECT_RUNNING)) {
  795. *pdwStatusCode = DIEGES_PLAYING;
  796. } else {
  797. *pdwStatusCode = NULL; // Stopped;
  798. }
  799. g_ForceFeedbackDevice.GetEffect(DnloadID)->SetPlaying(*pdwStatusCode == DIEGES_PLAYING);
  800. return SUCCESS;
  801. }