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.

679 lines
18 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. #ifndef WINNT
  424. /*****************************************************************************
  425. *
  426. * @doc INTERNAL
  427. *
  428. * @func HRESULT | Hel_Joy_CreateInstance |
  429. *
  430. * Attempt to create the device instance through the driver.
  431. * If that is not possible, then use the emulation layer.
  432. *
  433. * @parm PVXDDEVICEFORMAT | pdevf |
  434. *
  435. * Describes the device being created.
  436. *
  437. * @parm PVXDINSTANCE * | ppviOut |
  438. *
  439. * Receives created instance.
  440. *
  441. *****************************************************************************/
  442. HRESULT EXTERNAL
  443. Hel_Joy_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  444. {
  445. return Hel_CreateInstance(&c_cdiJoy, pdevf, ppviOut);
  446. }
  447. /*****************************************************************************
  448. *
  449. * @doc INTERNAL
  450. *
  451. * @func HRESULT | Hel_Joy_Ping |
  452. *
  453. * Ask the device driver (or emulation) to get the joystick info.
  454. *
  455. * @parm PVXDDWORDDATA | pvdd |
  456. *
  457. * The instance and the key state.
  458. *
  459. *****************************************************************************/
  460. HRESULT EXTERNAL
  461. Hel_Joy_Ping(PVXDINSTANCE pvi)
  462. {
  463. return Hel_IoctlChoose(pvi, CEm_Joy_Ping,
  464. IOCTL_JOY_PING8, &pvi, cbX(pvi));
  465. }
  466. /*****************************************************************************
  467. *
  468. * @doc INTERNAL
  469. *
  470. * @func HRESULT | Hel_Joy_ConfigChanged |
  471. *
  472. * Tell vjoyd config has been changed.
  473. *
  474. *****************************************************************************/
  475. HRESULT EXTERNAL
  476. Hel_Joy_ConfigChanged(DWORD dwFlags)
  477. {
  478. return IoctlHw(IOCTL_JOY_CONFIGCHANGED, &dwFlags, cbX(dwFlags), NULL, 0);
  479. }
  480. /*****************************************************************************
  481. *
  482. * @doc INTERNAL
  483. *
  484. * @func HRESULT | Hel_Joy_GetAxisCaps |
  485. *
  486. * Obtain a bitmask of the axes supported by the joystick.
  487. * If VJOYD won't tell us, then we figure it out from the
  488. * registry structure passed in.
  489. *
  490. * @parm DWORD | dwExternalID |
  491. *
  492. * The external joystick number.
  493. *
  494. * @parm PVXDAXISCAPS | pvac |
  495. *
  496. * Structure to receive the axis capabilities.
  497. *
  498. * @parm LPJOYREGHWCONFIG | phwc |
  499. *
  500. * The joystick settings as reported by the registry.
  501. *
  502. *****************************************************************************/
  503. HRESULT EXTERNAL
  504. Hel_Joy_GetAxisCaps
  505. (
  506. DWORD dwExternalID,
  507. PVXDAXISCAPS pvac,
  508. LPJOYREGHWCONFIG phwc
  509. )
  510. {
  511. HRESULT hres;
  512. DWORD dwRegAxes;
  513. /*
  514. * Every joystick has an X and Y (no way to tell)
  515. * Mark as position axes or they won't count!
  516. */
  517. dwRegAxes = JOYPF_X | JOYPF_Y | JOYPF_POSITION;
  518. if (phwc->hws.dwFlags & JOY_HWS_HASZ) {
  519. dwRegAxes |= JOYPF_Z;
  520. }
  521. if ( (phwc->hws.dwFlags & JOY_HWS_HASR) || (phwc->dwUsageSettings & JOY_US_HASRUDDER) ){
  522. dwRegAxes |= JOYPF_R;
  523. }
  524. if (phwc->hws.dwFlags & JOY_HWS_HASU) {
  525. dwRegAxes |= JOYPF_U;
  526. }
  527. if (phwc->hws.dwFlags & JOY_HWS_HASV) {
  528. dwRegAxes |= JOYPF_V;
  529. }
  530. if ((g_flEmulation & DIEMFL_JOYSTICK) ||
  531. FAILED(hres = IoctlHw(IOCTL_JOY_GETAXES,
  532. &dwExternalID, cbX(dwExternalID),
  533. pvac, cbX(*pvac)))) {
  534. /*
  535. * If that didn't work, then just use the registry.
  536. */
  537. if (phwc->hws.dwFlags & JOY_HWS_HASPOV) {
  538. pvac->dwPos |= JOYPF_POV0;
  539. }
  540. /*
  541. * Old VJOYD clients do not support velocity or any of the
  542. * other stuff.
  543. */
  544. pvac->dwVel = 0;
  545. pvac->dwAccel = 0;
  546. pvac->dwForce = 0;
  547. hres = S_OK;
  548. }
  549. else
  550. {
  551. /*
  552. * ManBug 28971: Logitech drivers (and probably others) respond to
  553. * probing on axes for which they do not report data so set the
  554. * position axes to whatever is reported in the registry.
  555. * Note this still allows multiple POVs to be picked up as only one
  556. * POV is supported by the registry flags.
  557. */
  558. pvac->dwPos &= ~JOYPF_ALLAXES;
  559. pvac->dwPos |= dwRegAxes;
  560. }
  561. /*
  562. * CJoy_InitRing3 assumes that this never fails.
  563. */
  564. AssertF(SUCCEEDED(hres));
  565. return hres;
  566. }
  567. #endif //WINNT
  568. /*****************************************************************************
  569. *
  570. * @doc INTERNAL
  571. *
  572. * @func HRESULT | Hel_Joy_GetInitParms |
  573. *
  574. * Ask the device driver (or emulation) for
  575. * VJOYD initialization parameters.
  576. *
  577. * In emulation, we assume the internal and external
  578. * IDs are equal (because they may as well be),
  579. * that no flags are set, and there are no versions.
  580. *
  581. * @parm DWORD | dwExternalID |
  582. *
  583. * The external joystick number.
  584. *
  585. * @parm PVXDINITPARMS | pvip |
  586. *
  587. * Receives assorted information.
  588. *
  589. *****************************************************************************/
  590. HRESULT EXTERNAL
  591. Hel_Joy_GetInitParms(DWORD dwExternalID, PVXDINITPARMS pvip)
  592. {
  593. HRESULT hres;
  594. if ((g_flEmulation & DIEMFL_JOYSTICK) ||
  595. FAILED(hres = IoctlHw(IOCTL_JOY_GETINITPARMS,
  596. &dwExternalID, cbX(dwExternalID),
  597. pvip, cbX(*pvip))) ||
  598. FAILED(hres = pvip->hres)) {
  599. /*
  600. * Do it the emulation way.
  601. */
  602. ZeroX(*pvip);
  603. pvip->dwId = dwExternalID;
  604. hres = S_OK;
  605. }
  606. return hres;
  607. }