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.

677 lines
17 KiB

  1. /*****************************************************************************
  2. *
  3. * DIHel.c
  4. *
  5. * Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Hardware emulation layer for DirectInput.
  10. *
  11. * Contents:
  12. *
  13. * Hel_AcquireInstance
  14. * Hel_UnacquireInstance
  15. * Hel_SetBufferSize
  16. * Hel_DestroyInstance
  17. *
  18. * Hel_SetDataFormat
  19. * Hel_SetNotifyHandle
  20. *
  21. * Hel_Mouse_CreateInstance
  22. * Hel_Kbd_CreateInstance
  23. * Hel_Kbd_InitKeys
  24. * Hel_Joy_CreateInstance
  25. * Hel_Joy_Ping
  26. * Hel_Joy_GetInitParms
  27. *
  28. * IoctlHw
  29. *
  30. *****************************************************************************/
  31. #include "dinputpr.h"
  32. /*****************************************************************************
  33. *
  34. * The sqiffle for this file.
  35. *
  36. *****************************************************************************/
  37. #define sqfl sqflHel
  38. /*****************************************************************************
  39. *
  40. * @doc INTERNAL
  41. *
  42. * @func HRESULT | IoctlHw |
  43. *
  44. * Send the IOCtl to the hardware device.
  45. *
  46. * @parm DWORD | ioctl |
  47. *
  48. * I/O control code.
  49. *
  50. * @parm IN LPVOID | pvIn |
  51. *
  52. * Optional input parameter.
  53. *
  54. * @parm DWORD | cbIn |
  55. *
  56. * Size of input buffer in bytes.
  57. *
  58. * @parm IN LPVOID | pvOut |
  59. *
  60. * Optional output parameter.
  61. *
  62. * @parm DWORD | cbOut |
  63. *
  64. * Size of output buffer in bytes.
  65. *
  66. * @returns
  67. *
  68. * <c S_OK> if the ioctl succeeded and returned the correct
  69. * number of bytes, else something based on the Win32 error code.
  70. *
  71. *****************************************************************************/
  72. #ifndef WINNT
  73. HRESULT EXTERNAL
  74. IoctlHw(DWORD ioctl, LPVOID pvIn, DWORD cbIn, LPVOID pvOut, DWORD cbOut)
  75. {
  76. HRESULT hres;
  77. DWORD cbRc;
  78. if (g_hVxD != INVALID_HANDLE_VALUE) {
  79. if (DeviceIoControl(g_hVxD, ioctl, pvIn, cbIn,
  80. pvOut, cbOut, &cbRc, 0)) {
  81. if (cbRc == cbOut) {
  82. hres = S_OK;
  83. } else {
  84. SquirtSqflPtszV(sqfl, TEXT("Ioctl(%08x) returned wrong cbOut"),
  85. ioctl);
  86. hres = DIERR_BADDRIVERVER;
  87. }
  88. } else {
  89. SquirtSqflPtszV(sqfl | sqflError,
  90. TEXT("Ioctl(%08x) failed, error %d"),
  91. ioctl, GetLastError());
  92. hres = hresLe(GetLastError());
  93. }
  94. } else {
  95. hres = DIERR_BADDRIVERVER;
  96. }
  97. return hres;
  98. }
  99. #endif
  100. /*****************************************************************************
  101. *
  102. * @doc INTERNAL
  103. *
  104. * @func HRESULT | Hel_IoctlChoose |
  105. *
  106. * Send the IOCtl to the hardware device if it is native,
  107. * or perform the operation through emulation if it is emulated.
  108. *
  109. * @parm PVXDINSTANCE | pvi |
  110. *
  111. * The device in question.
  112. *
  113. * @parm PFNHANDLER | pfn |
  114. *
  115. * The emulation function to call to carry out the operation.
  116. *
  117. * @parm DWORD | ioctl |
  118. *
  119. * I/O control code.
  120. *
  121. * @parm IN LPVOID | pvIn |
  122. *
  123. * Optional input parameter.
  124. *
  125. * @parm DWORD | cbIn |
  126. *
  127. * Size of input buffer in bytes.
  128. *
  129. *****************************************************************************/
  130. typedef HRESULT (EXTERNAL *PFNHANDLER)(PV pv);
  131. HRESULT INTERNAL
  132. Hel_IoctlChoose(PVXDINSTANCE pvi, PFNHANDLER pfn,
  133. DWORD ioctl, LPVOID pvIn, DWORD cbIn)
  134. {
  135. HRESULT hres;
  136. if (!(pvi->fl & VIFL_EMULATED)) {
  137. hres = IoctlHw(ioctl, pvIn, cbIn, 0, 0);
  138. } else {
  139. hres = pfn(pvIn);
  140. }
  141. return hres;
  142. }
  143. /*****************************************************************************
  144. *
  145. * @doc INTERNAL
  146. *
  147. * @func HRESULT | Hel_AcquireInstance |
  148. *
  149. * Attempt to acquire the device instance, using either the
  150. * device driver or emulation, whichever is appropriate.
  151. *
  152. * @parm PVXDINSTANCE | pvi |
  153. *
  154. * The instance to acquire.
  155. *
  156. *****************************************************************************/
  157. HRESULT EXTERNAL
  158. Hel_AcquireInstance(PVXDINSTANCE pvi)
  159. {
  160. return Hel_IoctlChoose(pvi, CEm_AcquireInstance,
  161. IOCTL_ACQUIREINSTANCE, &pvi, cbX(pvi));
  162. }
  163. /*****************************************************************************
  164. *
  165. * @doc INTERNAL
  166. *
  167. * @func HRESULT | Hel_UnacquireInstance |
  168. *
  169. * Attempt to unacquire the device instance.
  170. *
  171. * @parm PVXDINSTANCE | pvi |
  172. *
  173. * The instance to unacquire.
  174. *
  175. *****************************************************************************/
  176. HRESULT EXTERNAL
  177. Hel_UnacquireInstance(PVXDINSTANCE pvi)
  178. {
  179. return Hel_IoctlChoose(pvi, CEm_UnacquireInstance,
  180. IOCTL_UNACQUIREINSTANCE, &pvi, cbX(pvi));
  181. }
  182. /*****************************************************************************
  183. *
  184. * @doc INTERNAL
  185. *
  186. * @func HRESULT | Hel_SetBufferSize |
  187. *
  188. * Set the buffer size.
  189. *
  190. * @parm PVXDDWORDDATA | pvdd |
  191. *
  192. * Information about the buffer size.
  193. *
  194. *****************************************************************************/
  195. HRESULT EXTERNAL
  196. Hel_SetBufferSize(PVXDDWORDDATA pvdd)
  197. {
  198. HRESULT hres;
  199. EnterProc(Hel_SetBufferSize, (_ "pxx", pvdd->pvi, pvdd->dw, pvdd->pvi->fl));
  200. hres = Hel_IoctlChoose(pvdd->pvi, CEm_SetBufferSize,
  201. IOCTL_SETBUFFERSIZE, pvdd, cbX(*pvdd));
  202. ExitOleProc();
  203. return hres;
  204. }
  205. /*****************************************************************************
  206. *
  207. * @doc INTERNAL
  208. *
  209. * @func HRESULT | Hel_DestroyInstance |
  210. *
  211. * Destroy the device instance in the appropriate way.
  212. *
  213. * @parm PVXDINSTANCE | pvi |
  214. *
  215. * The instance.
  216. *
  217. *****************************************************************************/
  218. HRESULT EXTERNAL
  219. Hel_DestroyInstance(PVXDINSTANCE pvi)
  220. {
  221. return Hel_IoctlChoose(pvi, CEm_DestroyInstance,
  222. IOCTL_DESTROYINSTANCE, &pvi, cbX(pvi));
  223. }
  224. /*****************************************************************************
  225. *
  226. * @doc INTERNAL
  227. *
  228. * @func HRESULT | Hel_SetDataFormat |
  229. *
  230. * Set the data format.
  231. *
  232. * @parm PVXDDATAFORMAT | pvdf |
  233. *
  234. * Information about the data format.
  235. *
  236. *****************************************************************************/
  237. HRESULT EXTERNAL
  238. Hel_SetDataFormat(PVXDDATAFORMAT pvdf)
  239. {
  240. return Hel_IoctlChoose(pvdf->pvi, CEm_SetDataFormat,
  241. IOCTL_SETDATAFORMAT, pvdf, cbX(*pvdf));
  242. }
  243. /*****************************************************************************
  244. *
  245. * @doc INTERNAL
  246. *
  247. * @func HRESULT | Hel_SetNotifyHandle |
  248. *
  249. * Set the event handle for notification.
  250. *
  251. * @parm PVXDDWORDDATA | pvdd |
  252. *
  253. * 9x: dw = ring 0 handle. Dinput calls _OpenVxDHandle to get ring 0 handle.
  254. * NT: dw = ring 3 handle. DINPUT.SYS translates the handle to pointer.
  255. *
  256. *****************************************************************************/
  257. HRESULT EXTERNAL
  258. Hel_SetNotifyHandle(PVXDDWORDDATA pvdd)
  259. {
  260. HRESULT hres;
  261. if (!(pvdd->pvi->fl & VIFL_EMULATED)) {
  262. #ifndef WINNT
  263. AssertF(_OpenVxDHandle);
  264. if (pvdd->dw) {
  265. pvdd->dw = _OpenVxDHandle((HANDLE)pvdd->dw);
  266. }
  267. #endif
  268. hres = IoctlHw(IOCTL_SETNOTIFYHANDLE, pvdd, cbX(*pvdd), 0, 0);
  269. } else {
  270. hres = S_OK;
  271. }
  272. return hres;
  273. }
  274. /*****************************************************************************
  275. *
  276. * @doc INTERNAL
  277. *
  278. * @struct CREATEDEVICEINFO |
  279. *
  280. * Describes how to create the device either via the driver or
  281. * via emulation.
  282. *
  283. * @parm DWORD | dwIoctl |
  284. *
  285. * IOCtl code to try.
  286. *
  287. * @parm DWORD | flEmulation |
  288. *
  289. * Flag in registry that forces emulation.
  290. *
  291. * @parm EMULATIONCREATEPROC | pfnCreate |
  292. *
  293. * Function that creates emulation object.
  294. *
  295. *****************************************************************************/
  296. #pragma BEGIN_CONST_DATA
  297. typedef HRESULT (EXTERNAL *EMULATIONCREATEPROC)
  298. (PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut);
  299. typedef struct CREATEDEVICEINFO {
  300. DWORD dwIoctl;
  301. DWORD flEmulation;
  302. EMULATIONCREATEPROC pfnCreate;
  303. } CREATEDEVICEINFO, *PCREATEDEVICEINFO;
  304. CREATEDEVICEINFO c_cdiMouse = {
  305. IOCTL_MOUSE_CREATEINSTANCE,
  306. DIEMFL_MOUSE,
  307. CEm_Mouse_CreateInstance,
  308. };
  309. CREATEDEVICEINFO c_cdiKbd = {
  310. IOCTL_KBD_CREATEINSTANCE,
  311. DIEMFL_KBD | DIEMFL_KBD2,
  312. CEm_Kbd_CreateInstance,
  313. };
  314. CREATEDEVICEINFO c_cdiJoy = {
  315. IOCTL_JOY_CREATEINSTANCE,
  316. DIEMFL_JOYSTICK,
  317. CEm_Joy_CreateInstance,
  318. };
  319. #pragma END_CONST_DATA
  320. /*****************************************************************************
  321. *
  322. * @doc INTERNAL
  323. *
  324. * @func HRESULT | Hel_CreateInstance |
  325. *
  326. * Attempt to create the device instance through the driver
  327. * with the specified IOCtl.
  328. *
  329. * If that is not possible, then use the emulation callback.
  330. *
  331. * @parm PCREATEDEVICEINFO | pcdi |
  332. *
  333. * Describes how to create the device.
  334. *
  335. * @parm PVXDDEVICEFORMAT | pdevf |
  336. *
  337. * Describes the device being created.
  338. *
  339. * @parm PVXDINSTANCE * | ppviOut |
  340. *
  341. * Receives created instance.
  342. *
  343. *****************************************************************************/
  344. HRESULT EXTERNAL
  345. Hel_CreateInstance(PCREATEDEVICEINFO pcdi,
  346. PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  347. {
  348. HRESULT hres;
  349. pdevf->dwEmulation |= g_flEmulation;
  350. pdevf->dwEmulation &= pcdi->flEmulation;
  351. if (pdevf->dwEmulation ||
  352. (FAILED(hres = IoctlHw(pcdi->dwIoctl, pdevf, cbX(*pdevf),
  353. ppviOut, cbX(*ppviOut))))) {
  354. hres = pcdi->pfnCreate(pdevf, ppviOut);
  355. }
  356. return hres;
  357. }
  358. /*****************************************************************************
  359. *
  360. * @doc INTERNAL
  361. *
  362. * @func HRESULT | Hel_Mouse_CreateInstance |
  363. *
  364. * Attempt to create the device instance through the driver.
  365. * If that is not possible, then use the emulation layer.
  366. *
  367. * @parm PVXDDEVICEFORMAT | pdevf |
  368. *
  369. * Describes the device being created.
  370. *
  371. * @parm PVXDINSTANCE * | ppviOut |
  372. *
  373. * Receives created instance.
  374. *
  375. *****************************************************************************/
  376. HRESULT EXTERNAL
  377. Hel_Mouse_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  378. {
  379. return Hel_CreateInstance(&c_cdiMouse, pdevf, ppviOut);
  380. }
  381. /*****************************************************************************
  382. *
  383. * @doc INTERNAL
  384. *
  385. * @func HRESULT | Hel_Kbd_CreateInstance |
  386. *
  387. * Attempt to create the device instance through the driver.
  388. * If that is not possible, then use the emulation layer.
  389. *
  390. * @parm PVXDDEVICEFORMAT | pdevf |
  391. *
  392. * Describes the device being created.
  393. *
  394. * @parm PVXDINSTANCE * | ppviOut |
  395. *
  396. * Receives created instance.
  397. *
  398. *****************************************************************************/
  399. HRESULT EXTERNAL
  400. Hel_Kbd_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  401. {
  402. return Hel_CreateInstance(&c_cdiKbd, pdevf, ppviOut);
  403. }
  404. /*****************************************************************************
  405. *
  406. * @doc INTERNAL
  407. *
  408. * @func HRESULT | Hel_Kbd_InitKeys |
  409. *
  410. * Tell the device driver (or emulation) about the key state.
  411. *
  412. * @parm PVXDDWORDDATA | pvdd |
  413. *
  414. * The instance and the key state.
  415. *
  416. *****************************************************************************/
  417. HRESULT EXTERNAL
  418. Hel_Kbd_InitKeys(PVXDDWORDDATA pvdd)
  419. {
  420. return Hel_IoctlChoose(pvdd->pvi, CEm_Kbd_InitKeys,
  421. IOCTL_KBD_INITKEYS, pvdd, cbX(*pvdd));
  422. }
  423. /*****************************************************************************
  424. *
  425. * @doc INTERNAL
  426. *
  427. * @func HRESULT | Hel_Joy_CreateInstance |
  428. *
  429. * Attempt to create the device instance through the driver.
  430. * If that is not possible, then use the emulation layer.
  431. *
  432. * @parm PVXDDEVICEFORMAT | pdevf |
  433. *
  434. * Describes the device being created.
  435. *
  436. * @parm PVXDINSTANCE * | ppviOut |
  437. *
  438. * Receives created instance.
  439. *
  440. *****************************************************************************/
  441. HRESULT EXTERNAL
  442. Hel_Joy_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  443. {
  444. return Hel_CreateInstance(&c_cdiJoy, pdevf, ppviOut);
  445. }
  446. /*****************************************************************************
  447. *
  448. * @doc INTERNAL
  449. *
  450. * @func HRESULT | Hel_Joy_Ping |
  451. *
  452. * Ask the device driver (or emulation) to get the joystick info.
  453. *
  454. * @parm PVXDDWORDDATA | pvdd |
  455. *
  456. * The instance and the key state.
  457. *
  458. *****************************************************************************/
  459. HRESULT EXTERNAL
  460. Hel_Joy_Ping(PVXDINSTANCE pvi)
  461. {
  462. return Hel_IoctlChoose(pvi, CEm_Joy_Ping,
  463. IOCTL_JOY_PING8, &pvi, cbX(pvi));
  464. }
  465. /*****************************************************************************
  466. *
  467. * @doc INTERNAL
  468. *
  469. * @func HRESULT | Hel_Joy_ConfigChanged |
  470. *
  471. * Tell vjoyd config has been changed.
  472. *
  473. *****************************************************************************/
  474. HRESULT EXTERNAL
  475. Hel_Joy_ConfigChanged(DWORD dwFlags)
  476. {
  477. return IoctlHw(IOCTL_JOY_CONFIGCHANGED, &dwFlags, cbX(dwFlags), NULL, 0);
  478. }
  479. /*****************************************************************************
  480. *
  481. * @doc INTERNAL
  482. *
  483. * @func HRESULT | Hel_Joy_GetInitParms |
  484. *
  485. * Ask the device driver (or emulation) for
  486. * VJOYD initialization parameters.
  487. *
  488. * In emulation, we assume the internal and external
  489. * IDs are equal (because they may as well be),
  490. * that no flags are set, and there are no versions.
  491. *
  492. * @parm DWORD | dwExternalID |
  493. *
  494. * The external joystick number.
  495. *
  496. * @parm PVXDINITPARMS | pvip |
  497. *
  498. * Receives assorted information.
  499. *
  500. *****************************************************************************/
  501. HRESULT EXTERNAL
  502. Hel_Joy_GetInitParms(DWORD dwExternalID, PVXDINITPARMS pvip)
  503. {
  504. HRESULT hres;
  505. if ((g_flEmulation & DIEMFL_JOYSTICK) ||
  506. FAILED(hres = IoctlHw(IOCTL_JOY_GETINITPARMS,
  507. &dwExternalID, cbX(dwExternalID),
  508. pvip, cbX(*pvip))) ||
  509. FAILED(hres = pvip->hres)) {
  510. /*
  511. * Do it the emulation way.
  512. */
  513. ZeroX(*pvip);
  514. pvip->dwId = dwExternalID;
  515. hres = S_OK;
  516. }
  517. return hres;
  518. }
  519. /*****************************************************************************
  520. *
  521. * @doc INTERNAL
  522. *
  523. * @func HRESULT | Hel_Joy_GetAxisCaps |
  524. *
  525. * Obtain a bitmask of the axes supported by the joystick.
  526. * If VJOYD won't tell us, then we figure it out from the
  527. * registry structure passed in.
  528. *
  529. * @parm DWORD | dwExternalID |
  530. *
  531. * The external joystick number.
  532. *
  533. * @parm PVXDAXISCAPS | pvac |
  534. *
  535. * Structure to receive the axis capabilities.
  536. *
  537. * @parm LPJOYREGHWCONFIG | phwc |
  538. *
  539. * The joystick settings as reported by the registry.
  540. *
  541. *****************************************************************************/
  542. HRESULT EXTERNAL
  543. Hel_Joy_GetAxisCaps
  544. (
  545. DWORD dwExternalID,
  546. PVXDAXISCAPS pvac,
  547. LPJOYREGHWCONFIG phwc
  548. )
  549. {
  550. HRESULT hres;
  551. DWORD dwRegAxes;
  552. /*
  553. * Every joystick has an X and Y (no way to tell)
  554. * Mark as position axes or they won't count!
  555. */
  556. dwRegAxes = JOYPF_X | JOYPF_Y | JOYPF_POSITION;
  557. if (phwc->hws.dwFlags & JOY_HWS_HASZ) {
  558. dwRegAxes |= JOYPF_Z;
  559. }
  560. if ( (phwc->hws.dwFlags & JOY_HWS_HASR) || (phwc->dwUsageSettings & JOY_US_HASRUDDER) ){
  561. dwRegAxes |= JOYPF_R;
  562. }
  563. if (phwc->hws.dwFlags & JOY_HWS_HASU) {
  564. dwRegAxes |= JOYPF_U;
  565. }
  566. if (phwc->hws.dwFlags & JOY_HWS_HASV) {
  567. dwRegAxes |= JOYPF_V;
  568. }
  569. if ((g_flEmulation & DIEMFL_JOYSTICK) ||
  570. FAILED(hres = IoctlHw(IOCTL_JOY_GETAXES,
  571. &dwExternalID, cbX(dwExternalID),
  572. pvac, cbX(*pvac)))) {
  573. /*
  574. * If that didn't work, then just use the registry.
  575. */
  576. if (phwc->hws.dwFlags & JOY_HWS_HASPOV) {
  577. pvac->dwPos |= JOYPF_POV0;
  578. }
  579. /*
  580. * Old VJOYD clients do not support velocity or any of the
  581. * other stuff.
  582. */
  583. pvac->dwVel = 0;
  584. pvac->dwAccel = 0;
  585. pvac->dwForce = 0;
  586. hres = S_OK;
  587. }
  588. else
  589. {
  590. /*
  591. * ManBug 28971: Logitech drivers (and probably others) respond to
  592. * probing on axes for which they do not report data so set the
  593. * position axes to whatever is reported in the registry.
  594. * Note this still allows multiple POVs to be picked up as only one
  595. * POV is supported by the registry flags.
  596. */
  597. pvac->dwPos &= ~JOYPF_ALLAXES;
  598. pvac->dwPos |= dwRegAxes;
  599. }
  600. /*
  601. * CJoy_InitRing3 assumes that this never fails.
  602. */
  603. AssertF(SUCCEEDED(hres));
  604. return hres;
  605. }