/private/ntos/nthals/halalpha/pciesc.c

https://github.com/ZoloZiak/WinNT4 · C · 477 lines · 190 code · 98 blank · 189 comment · 18 complexity · a7368c461796ffcd590cf3c3b7dbacf4 MD5 · raw file

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
  4. Module Name:
  5. pciesc.c
  6. Abstract:
  7. The module provides the interrupt support for the PCI ESC's
  8. cascaded 82c59 programmable interrupt controllers.
  9. Author:
  10. Eric Rehm (DEC) 4-Feburary-1994
  11. Revision History:
  12. James Livingston 29-Apr-1994
  13. Adapted from pcisio.c module for Intel 82374EB (ESC).
  14. --*/
  15. #include "halp.h"
  16. #include "eisa.h"
  17. //
  18. // Import save area for ESC interrupt mask registers.
  19. //
  20. UCHAR HalpEisaInterrupt1Mask;
  21. UCHAR HalpEisaInterrupt2Mask;
  22. UCHAR HalpEisaInterrupt1Level;
  23. UCHAR HalpEisaInterrupt2Level;
  24. BOOLEAN
  25. HalpInitializeEisaInterrupts (
  26. VOID
  27. )
  28. /*++
  29. Routine Description:
  30. This routine initializes the standard dual 82c59 programmable interrupt
  31. controller.
  32. Arguments:
  33. None.
  34. Return Value:
  35. None.
  36. --*/
  37. {
  38. UCHAR DataByte;
  39. //
  40. // Initialize the ESC interrupt controller. There are two cascaded
  41. // interrupt controllers, each of which must be initialized with 4
  42. // control words.
  43. //
  44. DataByte = 0;
  45. ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1;
  46. ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1;
  47. WRITE_PORT_UCHAR(
  48. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
  49. DataByte
  50. );
  51. WRITE_PORT_UCHAR(
  52. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
  53. DataByte
  54. );
  55. //
  56. // The second intitialization control word sets the interrupt vector to
  57. // 0-15.
  58. //
  59. DataByte = 0;
  60. WRITE_PORT_UCHAR(
  61. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  62. DataByte
  63. );
  64. DataByte = 0x08;
  65. WRITE_PORT_UCHAR(
  66. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  67. DataByte
  68. );
  69. //
  70. // The third initialization control word sets the controls for slave mode.
  71. // The master ICW3 uses bit position and the slave ICW3 uses a numeric.
  72. //
  73. DataByte = 1 << SLAVE_IRQL_LEVEL;
  74. WRITE_PORT_UCHAR(
  75. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  76. DataByte
  77. );
  78. DataByte = SLAVE_IRQL_LEVEL;
  79. WRITE_PORT_UCHAR(
  80. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  81. DataByte
  82. );
  83. //
  84. // The fourth initialization control word is used to specify normal
  85. // end-of-interrupt mode and not special-fully-nested mode.
  86. //
  87. DataByte = 0;
  88. ((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1;
  89. WRITE_PORT_UCHAR(
  90. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  91. DataByte
  92. );
  93. WRITE_PORT_UCHAR(
  94. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  95. DataByte
  96. );
  97. //
  98. // Disable all of the interrupts except the slave.
  99. //
  100. HalpEisaInterrupt1Mask = (UCHAR)(~(1 << SLAVE_IRQL_LEVEL));
  101. WRITE_PORT_UCHAR(
  102. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  103. HalpEisaInterrupt1Mask
  104. );
  105. HalpEisaInterrupt2Mask = 0xFF;
  106. WRITE_PORT_UCHAR(
  107. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  108. HalpEisaInterrupt2Mask
  109. );
  110. //
  111. // Initialize the edge/level register masks to 0, which is the default
  112. // edge-sensitive value.
  113. //
  114. HalpEisaInterrupt1Level = 0;
  115. HalpEisaInterrupt2Level = 0;
  116. return (TRUE);
  117. }
  118. VOID
  119. HalpDisableEisaInterrupt(
  120. IN ULONG Vector
  121. )
  122. /*++
  123. Routine Description:
  124. This function Disables the EISA interrupt specified by Vector.
  125. Arguments:
  126. Vector - Supplies the vector of the ESIA interrupt that is Disabled.
  127. Return Value:
  128. None.
  129. --*/
  130. {
  131. //
  132. // Calculate the EISA interrupt vector.
  133. //
  134. Vector -= EISA_VECTORS;
  135. //
  136. // Determine if this vector is for interrupt controller 1 or 2.
  137. //
  138. if (Vector & 0x08) {
  139. //
  140. // The interrupt is for controller 2.
  141. //
  142. Vector &= 0x7;
  143. HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector;
  144. WRITE_PORT_UCHAR(
  145. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  146. HalpEisaInterrupt2Mask
  147. );
  148. } else {
  149. //
  150. // The interrupt is in controller 1.
  151. //
  152. Vector &= 0x7;
  153. //
  154. // never disable IRQL2; it is the slave interrupt
  155. //
  156. if (Vector != SLAVE_IRQL_LEVEL) {
  157. HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector;
  158. WRITE_PORT_UCHAR(
  159. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  160. HalpEisaInterrupt1Mask
  161. );
  162. }
  163. }
  164. }
  165. VOID
  166. HalpEnableEisaInterrupt(
  167. IN ULONG Vector,
  168. IN KINTERRUPT_MODE InterruptMode
  169. )
  170. /*++
  171. Routine Description:
  172. This function enables the EISA interrupt specified by Vector.
  173. Arguments:
  174. Vector - Supplies the vector of the EISA interrupt that is enabled.
  175. InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
  176. Latched.
  177. Return Value:
  178. None.
  179. --*/
  180. {
  181. //
  182. // Calculate the EISA interrupt vector.
  183. //
  184. Vector -= EISA_VECTORS;
  185. //
  186. // Determine if this vector is for interrupt controller 1 or 2.
  187. //
  188. if (Vector & 0x08) {
  189. //
  190. // The interrupt is in controller 2.
  191. //
  192. Vector &= 0x7;
  193. HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector);
  194. WRITE_PORT_UCHAR(
  195. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  196. HalpEisaInterrupt2Mask
  197. );
  198. //
  199. // Set the level/edge control register.
  200. //
  201. if (InterruptMode == LevelSensitive) {
  202. HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector);
  203. } else {
  204. HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector);
  205. }
  206. WRITE_PORT_UCHAR(
  207. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
  208. HalpEisaInterrupt2Level
  209. );
  210. } else {
  211. //
  212. // The interrupt is in controller 1.
  213. //
  214. Vector &= 0x7;
  215. HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector);
  216. WRITE_PORT_UCHAR(
  217. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  218. HalpEisaInterrupt1Mask
  219. );
  220. //
  221. // Set the level/edge control register.
  222. //
  223. if (InterruptMode == LevelSensitive) {
  224. HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector);
  225. } else {
  226. HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector);
  227. }
  228. WRITE_PORT_UCHAR(
  229. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
  230. HalpEisaInterrupt1Level
  231. );
  232. }
  233. }
  234. BOOLEAN
  235. HalpEisaDispatch(
  236. IN PKINTERRUPT Interrupt,
  237. IN PVOID ServiceContext,
  238. IN PKTRAP_FRAME TrapFrame
  239. )
  240. /*++
  241. Routine Description:
  242. This routine is entered as the result of an interrupt being generated
  243. via the vector that is connected to an interrupt object that describes
  244. the EISA device interrupts. Its function is to call the second-level
  245. interrupt dispatch routine and acknowledge the interrupt at the ESC
  246. controller.
  247. This service routine could be connected as follows:
  248. KeInitializeInterrupt(&Interrupt, HalpDispatch,
  249. EISA_VIRTUAL_BASE,
  250. (PKSPIN_LOCK)NULL, ISA_LEVEL, ISA_LEVEL, ISA_LEVEL,
  251. LevelSensitive, TRUE, 0, FALSE);
  252. KeConnectInterrupt(&Interrupt);
  253. Arguments:
  254. Interrupt - Supplies a pointer to the interrupt object.
  255. ServiceContext - Supplies a pointer to the EISA interrupt acknowledge
  256. register.
  257. TrapFrame - Supplies a pointer to the trap frame for this interrupt.
  258. Return Value:
  259. Returns the value returned from the second level routine.
  260. --*/
  261. {
  262. UCHAR EISAVector;
  263. PKPRCB Prcb;
  264. BOOLEAN returnValue;
  265. USHORT PCRInOffset;
  266. UCHAR Int1Isr;
  267. UCHAR Int2Isr;
  268. //
  269. // Acknowledge the Interrupt controller and receive the returned
  270. // interrupt vector.
  271. //
  272. EISAVector = HalpAcknowledgeEisaInterrupt(ServiceContext);
  273. if ((EISAVector & 0x07) == 0x07) {
  274. //
  275. // Check for a passive release by looking at the inservice register.
  276. // If there is a real IRQL7 interrupt, just go along normally. If there
  277. // is not, then it is a passive release. So just dismiss it.
  278. //
  279. WRITE_PORT_UCHAR(
  280. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
  281. 0x0B
  282. );
  283. Int1Isr = READ_PORT_UCHAR(
  284. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0);
  285. //
  286. // do second controller
  287. //
  288. WRITE_PORT_UCHAR(
  289. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
  290. 0x0B
  291. );
  292. Int2Isr = READ_PORT_UCHAR(
  293. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0);
  294. if (!(Int2Isr & 0x80) && !(Int1Isr & 0x80)) {
  295. //
  296. // Clear the master controller to clear situation
  297. //
  298. if (!(Int2Isr & 0x80)) {
  299. WRITE_PORT_UCHAR(
  300. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
  301. NONSPECIFIC_END_OF_INTERRUPT
  302. );
  303. }
  304. return FALSE; // ecrfix - now returns a value
  305. }
  306. }
  307. //
  308. // Dispatch to the secondary interrupt service routine.
  309. //
  310. PCRInOffset = EISAVector + EISA_VECTORS;
  311. returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])(
  312. PCR->InterruptRoutine[PCRInOffset],
  313. TrapFrame
  314. );
  315. //
  316. // Dismiss the interrupt in the ESC interrupt controllers.
  317. //
  318. //
  319. // If this is a cascaded interrupt then the interrupt must be dismissed in
  320. // both controlles.
  321. //
  322. if (EISAVector & 0x08) {
  323. WRITE_PORT_UCHAR(
  324. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
  325. NONSPECIFIC_END_OF_INTERRUPT
  326. );
  327. }
  328. WRITE_PORT_UCHAR(
  329. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
  330. NONSPECIFIC_END_OF_INTERRUPT
  331. );
  332. return(returnValue);
  333. }