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.

424 lines
14 KiB

  1. //**************************************************************************
  2. //
  3. // PORTIO.C -- Xena Gaming Project
  4. //
  5. // Version 3.XX
  6. //
  7. // Copyright (c) 1997 Microsoft Corporation. All rights reserved.
  8. //
  9. // @doc
  10. // @module PORTIO.C | Gameport Input/Output Routines
  11. //**************************************************************************
  12. #include "msgame.h"
  13. //---------------------------------------------------------------------------
  14. // Alloc_text pragma to specify routines that can be paged out.
  15. //---------------------------------------------------------------------------
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text (INIT, PORTIO_DriverEntry)
  18. #endif
  19. //---------------------------------------------------------------------------
  20. // Private Data
  21. //---------------------------------------------------------------------------
  22. static ULONG PortTimeOut = ONE_MILLI_SEC;
  23. static KIRQL MaskedIrql = PASSIVE_LEVEL;
  24. static KIRQL SpinLockIrql = PASSIVE_LEVEL;
  25. static KSPIN_LOCK IoSpinLock = {0};
  26. //---------------------------------------------------------------------------
  27. // @func Driver entry point for portio layer
  28. // @rdesc Returns NT status code
  29. // @comm Public function
  30. //---------------------------------------------------------------------------
  31. NTSTATUS PORTIO_DriverEntry (VOID)
  32. {
  33. KeInitializeSpinLock (&IoSpinLock);
  34. return (STATUS_SUCCESS);
  35. }
  36. //---------------------------------------------------------------------------
  37. // @func Masks system interrupts for access to gameport
  38. // @rdesc Returns nothing
  39. // @comm Public function
  40. //---------------------------------------------------------------------------
  41. VOID PORTIO_MaskInterrupts (VOID)
  42. {
  43. KeRaiseIrql (PROFILE_LEVEL, &MaskedIrql);
  44. }
  45. //---------------------------------------------------------------------------
  46. // @func Unmasks system interrupts for access to gameport
  47. // @rdesc Returns nothing
  48. // @comm Public function
  49. //---------------------------------------------------------------------------
  50. VOID PORTIO_UnMaskInterrupts (VOID)
  51. {
  52. KeLowerIrql (MaskedIrql);
  53. }
  54. //---------------------------------------------------------------------------
  55. // @func Acquires exclusive access to gameport (mutex)
  56. // @parm PGAMEPORT | PortInfo | Gameport parameters
  57. // @rdesc Returns true if successful
  58. // @comm Public function
  59. //---------------------------------------------------------------------------
  60. BOOLEAN PORTIO_AcquirePort (PGAMEPORT PortInfo)
  61. {
  62. if (PortInfo->AcquirePort (PortInfo->PortContext) != STATUS_SUCCESS)
  63. return (FALSE);
  64. KeAcquireSpinLock (&IoSpinLock, &SpinLockIrql);
  65. return (TRUE);
  66. }
  67. //---------------------------------------------------------------------------
  68. // @func Releases exclusive access to gameport (mutex)
  69. // @parm PGAMEPORT | PortInfo | Gameport parameters
  70. // @rdesc Returns nothing
  71. // @comm Public function
  72. //---------------------------------------------------------------------------
  73. VOID PORTIO_ReleasePort (PGAMEPORT PortInfo)
  74. {
  75. KeReleaseSpinLock (&IoSpinLock, SpinLockIrql);
  76. PortInfo->ReleasePort (PortInfo->PortContext);
  77. }
  78. //---------------------------------------------------------------------------
  79. // @func Calculates port timeout value
  80. // @parm PGAMEPORT | PortInfo | Gameport parameters
  81. // @rdesc Returns nothing
  82. // @comm Public function
  83. //---------------------------------------------------------------------------
  84. VOID PORTIO_CalibrateTimeOut (PGAMEPORT PortInfo)
  85. {
  86. PortTimeOut = TIMER_CalibratePort (PortInfo, ONE_MILLI_SEC);
  87. }
  88. //---------------------------------------------------------------------------
  89. // @func Reads byte from IO port
  90. // @parm PGAMEPORT | PortInfo | Gameport parameters
  91. // @rdesc Returns byte from port
  92. // @comm Public function
  93. //---------------------------------------------------------------------------
  94. #if _MSC_FULL_VER <= 13008829
  95. #pragma optimize("y", off)
  96. #endif
  97. UCHAR PORTIO_Read (PGAMEPORT PortInfo)
  98. {
  99. UCHAR Value;
  100. __asm pushad
  101. Value = PortInfo->ReadAccessor (PortInfo->GameContext);
  102. __asm popad
  103. return (Value);
  104. }
  105. //---------------------------------------------------------------------------
  106. // @func Write byte To IO port
  107. // @parm PGAMEPORT | PortInfo | Gameport parameters
  108. // @parm UCHAR | Value | Value to write
  109. // @rdesc Returns nothing
  110. // @comm Public function
  111. //---------------------------------------------------------------------------
  112. VOID PORTIO_Write (PGAMEPORT PortInfo, UCHAR Value)
  113. {
  114. __asm pushad
  115. PortInfo->WriteAccessor (PortInfo->GameContext, Value);
  116. __asm popad
  117. }
  118. #if _MSC_FULL_VER <= 13008829
  119. #pragma optimize("", on)
  120. #endif
  121. //---------------------------------------------------------------------------
  122. // @func Get AckNak (buttons) from gameport
  123. // @parm PGAMEPORT | PortInfo | Gameport parameters
  124. // @parm ULONG | Timeout | Calibrated status gate timeout
  125. // @parm PUCHAR | AckNak | Pointer to AckNak buffer
  126. // @rdesc Returns True if active, False otherwise
  127. // @comm Public function
  128. //---------------------------------------------------------------------------
  129. BOOLEAN PORTIO_GetAckNak (PGAMEPORT PortInfo, ULONG Timeout, PUCHAR AckNak)
  130. {
  131. if (!PORTIO_WaitForStatusGate (PortInfo, CLOCK_BIT_MASK, Timeout))
  132. return (FALSE);
  133. TIMER_DelayMicroSecs (10);
  134. *AckNak = PORTIO_Read (PortInfo);
  135. return (TRUE);
  136. }
  137. //---------------------------------------------------------------------------
  138. // @func Get NakAck (buttons) from gameport
  139. // @parm PGAMEPORT | PortInfo | Gameport parameters
  140. // @parm ULONG | Timeout | Calibrated status gate timeout
  141. // @parm PUCHAR | NakAck | Pointer to NakAck buffer
  142. // @rdesc Returns True if active, False otherwise
  143. // @comm Public function
  144. //---------------------------------------------------------------------------
  145. BOOLEAN PORTIO_GetNakAck (PGAMEPORT PortInfo, ULONG Timeout, PUCHAR NakAck)
  146. {
  147. if (!PORTIO_WaitForStatusGate (PortInfo, STATUS_GATE_MASK, Timeout))
  148. return (FALSE);
  149. TIMER_DelayMicroSecs (10);
  150. *NakAck = PORTIO_Read (PortInfo);
  151. return (TRUE);
  152. }
  153. //---------------------------------------------------------------------------
  154. // @func Determines whether gameport clock is active
  155. // @parm PGAMEPORT | PortInfo | Gameport parameters
  156. // @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
  157. // @rdesc Returns True if active, False otherwise
  158. // @comm Public function
  159. //---------------------------------------------------------------------------
  160. BOOLEAN PORTIO_IsClockActive (PGAMEPORT PortInfo, ULONG DutyCycle)
  161. {
  162. UCHAR Value;
  163. Value = PORTIO_Read (PortInfo);
  164. do if ((PORTIO_Read (PortInfo) ^ Value) & CLOCK_BIT_MASK)
  165. return (TRUE);
  166. while (--DutyCycle);
  167. return (FALSE);
  168. }
  169. //---------------------------------------------------------------------------
  170. // @func Waits until gameport clock line goes inactive
  171. // @parm PGAMEPORT | PortInfo | Gameport parameters
  172. // @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
  173. // @rdesc Returns True is sucessful, false on timeout
  174. // @comm Public function
  175. //---------------------------------------------------------------------------
  176. BOOLEAN PORTIO_WaitClockInActive (PGAMEPORT PortInfo, ULONG DutyCycle)
  177. {
  178. ULONG TimeOut = PortTimeOut;
  179. do if (!PORTIO_IsClockActive (PortInfo, DutyCycle))
  180. return (TRUE);
  181. while (--TimeOut);
  182. MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitClockInActive)\n"));
  183. return (FALSE);
  184. }
  185. //---------------------------------------------------------------------------
  186. // @func Waits until gameport clock line goes low
  187. // @parm PGAMEPORT | PortInfo | Gameport parameters
  188. // @rdesc Returns True is sucessfull, false on timeout
  189. // @comm Public function
  190. //---------------------------------------------------------------------------
  191. BOOLEAN PORTIO_WaitClockLow (PGAMEPORT PortInfo)
  192. {
  193. ULONG TimeOut = PortTimeOut;
  194. do if ((PORTIO_Read (PortInfo) & CLOCK_BIT_MASK) == 0)
  195. return (TRUE);
  196. while (--TimeOut);
  197. MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitClockLow)\n"));
  198. return (FALSE);
  199. }
  200. //---------------------------------------------------------------------------
  201. // @func Waits until gameport clock line goes high
  202. // @parm PGAMEPORT | PortInfo | Gameport parameters
  203. // @rdesc Returns True is sucessfull, false on timeout
  204. // @comm Public function
  205. //---------------------------------------------------------------------------
  206. BOOLEAN PORTIO_WaitClockHigh (PGAMEPORT PortInfo)
  207. {
  208. ULONG TimeOut = PortTimeOut;
  209. do if ((PORTIO_Read (PortInfo) & CLOCK_BIT_MASK))
  210. return (TRUE);
  211. while (--TimeOut);
  212. MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitClockHigh)\n"));
  213. return (FALSE);
  214. }
  215. //---------------------------------------------------------------------------
  216. // @func Waits until gameport data2 line goes low
  217. // @parm PGAMEPORT | PortInfo | Gameport parameters
  218. // @rdesc Returns True is sucessfull, false on timeout
  219. // @comm Public function
  220. //---------------------------------------------------------------------------
  221. BOOLEAN PORTIO_WaitDataLow (PGAMEPORT PortInfo)
  222. {
  223. ULONG TimeOut = PortTimeOut;
  224. do if ((PORTIO_Read (PortInfo) & DATA2_BIT_MASK) == 0)
  225. return (TRUE);
  226. while (--TimeOut);
  227. MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitDataLow)\n"));
  228. return (FALSE);
  229. }
  230. //---------------------------------------------------------------------------
  231. // @func Waits until gameport XA line goes high to low
  232. // @parm PGAMEPORT | PortInfo | Gameport parameters
  233. // @rdesc Returns True is sucessful, false on timeout
  234. // @comm Public function
  235. //---------------------------------------------------------------------------
  236. BOOLEAN PORTIO_WaitXA_HighLow (PGAMEPORT PortInfo)
  237. {
  238. ULONG TimeOut = PortTimeOut;
  239. if ((PORTIO_Read (PortInfo) & INTXA_BIT_MASK) == 0)
  240. {
  241. MsGamePrint ((DBG_SEVERE, "PORTIO: Initial (WaitXA_HighLow) Was Low\n"));
  242. return (FALSE);
  243. }
  244. do if ((PORTIO_Read (PortInfo) & INTXA_BIT_MASK) == 0)
  245. return (TRUE);
  246. while (--TimeOut);
  247. MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitXALow)\n"));
  248. return (FALSE);
  249. }
  250. //---------------------------------------------------------------------------
  251. // @func Waits until gameport XA and clock lines go low
  252. // @parm PGAMEPORT | PortInfo | Gameport parameters
  253. // @rdesc Returns True is sucessful, false on timeout
  254. // @comm Public function
  255. //---------------------------------------------------------------------------
  256. BOOLEAN PORTIO_WaitForIdle (PGAMEPORT PortInfo)
  257. {
  258. ULONG TimeOut = PortTimeOut;
  259. do if ((PORTIO_Read (PortInfo) & (INTXA_BIT_MASK|CLOCK_BIT_MASK)) == 0)
  260. return (TRUE);
  261. while (--TimeOut);
  262. MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitForIdle)\n"));
  263. return (FALSE);
  264. }
  265. //---------------------------------------------------------------------------
  266. // @func Waits until gameport XA and clock lines go low
  267. // @parm PGAMEPORT | PortInfo | Gameport parameters
  268. // @parm UCHAR | Mask | Button mask to wait on
  269. // @parm ULONG | Timeout | Calibrated status gate timeout
  270. // @rdesc Returns True is sucessful, false on timeout
  271. // @comm Public function
  272. //---------------------------------------------------------------------------
  273. BOOLEAN PORTIO_WaitForStatusGate (PGAMEPORT PortInfo, UCHAR Mask, ULONG Timeout)
  274. {
  275. do if ((PORTIO_Read (PortInfo) & STATUS_GATE_MASK) == Mask)
  276. return (TRUE);
  277. while (--Timeout);
  278. MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitForStatusGate)\n"));
  279. return (FALSE);
  280. }
  281. //---------------------------------------------------------------------------
  282. // @func Waits for gameport XA low, clock inactive and then clock low
  283. // @parm PGAMEPORT | PortInfo | Gameport parameters
  284. // @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
  285. // @rdesc Returns True is sucessful, false on timeout
  286. // @comm Public function
  287. //---------------------------------------------------------------------------
  288. BOOLEAN PORTIO_WaitForHandshake (PGAMEPORT PortInfo, ULONG DutyCycle)
  289. {
  290. return
  291. (
  292. PORTIO_WaitXA_HighLow (PortInfo) &&
  293. PORTIO_WaitClockInActive (PortInfo, DutyCycle) &&
  294. PORTIO_WaitClockLow (PortInfo)
  295. );
  296. }
  297. //---------------------------------------------------------------------------
  298. // @func Waits for gameport XA low, clock inactive and then clock low
  299. // @parm PGAMEPORT | PortInfo | Gameport parameters
  300. // @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
  301. // @rdesc Returns True is sucessful, false on timeout
  302. // @comm Public function
  303. //---------------------------------------------------------------------------
  304. BOOLEAN PORTIO_WaitForIdleHandshake (PGAMEPORT PortInfo, ULONG DutyCycle)
  305. {
  306. ULONG TimeOut = PortTimeOut;
  307. if (!PORTIO_WaitClockHigh (PortInfo))
  308. return (FALSE);
  309. if (!PORTIO_WaitForIdle (PortInfo))
  310. return (FALSE);
  311. do if (!PORTIO_IsClockActive (PortInfo, DutyCycle))
  312. return (TRUE);
  313. while (--TimeOut);
  314. return (FALSE);
  315. }
  316. //---------------------------------------------------------------------------
  317. // @func Pulses port and the waits for gameport handshake
  318. // @parm PGAMEPORT | PortInfo | Gameport parameters
  319. // @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
  320. // @parm ULONG | Pulses | Number of pulses to perform
  321. // @rdesc Returns True is sucessfull, false on timeout
  322. // @comm Public function
  323. //---------------------------------------------------------------------------
  324. BOOLEAN PORTIO_PulseAndWaitForHandshake (PGAMEPORT PortInfo, ULONG DutyCycle, ULONG Pulses)
  325. {
  326. while (Pulses--)
  327. {
  328. PORTIO_Write (PortInfo, 0);
  329. if (!PORTIO_WaitForHandshake (PortInfo, DutyCycle))
  330. return (FALSE);
  331. }
  332. return (TRUE);
  333. }
  334. //---------------------------------------------------------------------------
  335. // @func Pulses port and the waits for gameport idle handshake
  336. // @parm PGAMEPORT | PortInfo | Gameport parameters
  337. // @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
  338. // @parm ULONG | Pulses | Number of pulses to perform
  339. // @rdesc Returns True is sucessfull, false on timeout
  340. // @comm Public function
  341. //---------------------------------------------------------------------------
  342. BOOLEAN PORTIO_PulseAndWaitForIdleHandshake (PGAMEPORT PortInfo, ULONG DutyCycle, ULONG Pulses)
  343. {
  344. while (Pulses--)
  345. {
  346. PORTIO_Write (PortInfo, 0);
  347. if (!PORTIO_WaitForIdleHandshake (PortInfo, DutyCycle))
  348. return (FALSE);
  349. }
  350. return (TRUE);
  351. }