i8259Intr.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:20k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* i8259Intr.c - Intel 8259A PIC (Programmable Interrupt Controller) driver */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01p,16apr02,hdn  added support for the Special Fully Nested Mode, IRQ0 Early
  8.  EOI Mode, IRQ0 Special Mask Mode, AEOI Mode (spr 76411)
  9. 01o,29mar02,hdn  added forgotten back slash to the optimized code
  10. 01n,21mar02,hdn  fixed doc build by removing comments in the optimized code
  11. 01m,25feb02,hdn  updated i8259Init() for HTT (spr 73738)
  12.  added optimized version of EOI routines
  13. 01l,11sep01,hdn  updated comment regarding the spr-28547 fix.
  14. 01k,27aug99,hdn  fixed a bug for stray interrupt in i8259IntBoi(SPR 28547).
  15. 01j,11oct98,ms   fixed compiler warning via typecast
  16. 01i,04jun98,hdn  changed a method to exit i8259IntBoi().
  17. 01h,25may98,hdn  changed function name starting from "i8259".
  18.  added i8259IntEoiMaster(), i8259IntEoiSlave(), i8259IntBoi().
  19.  removed sysIntEOI().
  20. 01g,17mar97,hdn  added sysIntLock(), sysIntUnlock() for the system mode.
  21. 01f,25jun96,hdn  added sysIntLevel() for windview.
  22. 01e,23may96,wlf  doc: cleanup.
  23. 01d,14jun95,hdn  renamed sysEndOfInt to sysIntEOI.
  24.  moved global function prototypes to sysLib.h.
  25. 01c,08aug94,hdn  stopped toggling IRQ9 in enabling and disabling.
  26. 01b,22apr94,hdn  made IRQ9 off in the initialization.
  27.  moved sysVectorIRQ0 to sysLib.c.
  28. 01a,05sep93,hdn  written.
  29. */
  30. /*
  31. DESCRIPTION
  32. This module is a driver for the Intel 8259A PIC (Programmable Interrupt
  33. Controller).  The Intel 8259A handles up to 8 vectored priority interrupts
  34. for the CPU.  It is cascadable for up to 64 vectored priority interrupts,
  35. though this driver assumes two cascaded 8259A.  It is initialized for
  36. "Fully Nested Mode", "Non-Specific EOI" mode.
  37. Fully Nested Mode.
  38. In this mode, interrupt requests are ordered in priority
  39. from 0 through 7 (0 is the highest priority).  When an interrupt is
  40. acknowledged, the highest priority request is determined and its vector is
  41. placed on the bus.  Additionally, a bit of the Interrupt Service (IS)
  42. register is set.  This bit remains set until the microprocessor issues an
  43. EOI command immediately before returning from the service routine.  While
  44. the IS bit is set, all further interrupts of the same or lower priority
  45. are inhibited, while higher level interrupts are allowed.  The
  46. i8259IntEoiSlaveNfnm() routine is used to issue the EOI command.  The PICs
  47. in a PC typically operate in this mode (normal nested mode).  In this mode,
  48. while the slave PIC is being serviced by the master PIC, the slave PIC blocks
  49. all higher priority interrupt requests.  Alternatively, to allow interrupts of
  50. a higher priority, enable the Special Fully Nested Mode.
  51. Special Fully Nested Mode: I8259_SPECIAL_FULLY_NESTED_MODE.
  52. This mode is similar to the Fully Nested Mode with the following exceptions:
  53. 1) When an interrupt request from a slave PIC is in service, the slave is
  54. not locked out from the master's priority logic and further interrupt
  55. requests from higher priority IRs within the slave will be recognized by
  56. the master and will initiate interrupts to the processor.  2) When exiting
  57. the interrupt service routine, the software must check whether or not the
  58. interrupt serviced was the only interrupt request from the slave.  If it
  59. was the only interrupt request, a non-specific EOI is sent to the master.
  60. If not, no EOI is sent.  This is implemented by the i8259EoiSlaveSfnm()
  61. routine.
  62. Non-Specific EOI: When the 8259A is operated in the Fully Nested Mode, it
  63. can determine which IS bit to reset on EOI.  When a non-specific EOI
  64. command is issued, the 8259A will automatically reset the highest IS bit of
  65. those that are set, since in the fully nested mode the highest IS level is
  66. the last level acknowledged and serviced.
  67. Spurious/Phantom Interrupt: The IR inputs must remain high until after the
  68. falling edge of the first INTA.  If the IR input goes low before this time,
  69. a DEFAULT(Spurious/Phantom) IR7 will occur when the CPU acknowledges the
  70. interrupt.  The interrupt handler should simply return without sending
  71. an EOI command.
  72. The PIC(8259A) IRQ0 is hard wired to the PIT(8253) channel 0 in a PC
  73. motherboard.  IRQ0 is the highest priority in the 8259A interrupt
  74. controller.  Thus, the system clock interrupt handler blocks all lower
  75. level interrupts.  This may cause a delay of the lower level interrupts in
  76. some situations even though the system clock interrupt handler finishes its
  77. job without any delay.  This is quite natural from the hardware point of
  78. view, but may not be ideal from the application software standpoint.  The
  79. following modes are supplied to mitigate this situation by providing
  80. corresponding configuration macros in the BSP.  The three modes are mutually
  81. exclusive.
  82. Early EOI Issue in IRQ0 ISR.
  83. In this mode, the EOI command is issued before the IRQ0 system clock interrupt
  84. service routine starts the kernel work.  This lowers the IRQ0 ISR blocking
  85. level to the next lower level.  If no IRQs are in service, the next lower
  86. level is the lowest level.  If IRQn is in service, the next lower level
  87. corresponds to the next lower priority.  As a result, the kernel work in the
  88. system clock interrupt service routine can be interrupted by an interrupt
  89. with a higher priority than the blocking level.  The i8259IntBoiEem() routine 
  90. is called before the interrupt service routine, and no EOI is sent after 
  91. the interrupt service routine.
  92. Special Mask Mode in IRQ0 ISR.
  93. In this mode, the Special Mask Mode is used in the IRQ0 system clock
  94. service routine.  This lowers the blocking level to the specified level
  95. (currently hard coded to the lowest level).  The i8259IntBoiSmm() routine
  96. is called before the interrupt service routine, and the i8259IntEoiSmm()
  97. routine is called after the interrupt service routine.
  98. Automatic EOI Mode: I8259_AUTO_EOI.
  99. This mode provides no nested multi-level interrupt structure in PIC1.  The
  100. EOI command is automatically sent to the master PIC at the end of the
  101. interrupt acknowledge cycle.  Thus, no software intervention is needed.  The
  102. i8259IntBoi() routine is called before the IRQ7 and IRQ15 interrupt service
  103. routines.  Either the i8259IntEoiSlaveNfnm() routine or the
  104. i8259IntEoiSlaveSfnm() routine is called after the slave PIC's interrupt
  105. service routine.
  106. SEE ALSO: pc386/target.nr
  107. */
  108. #include "drv/intrCtl/i8259.h"
  109. /* externs */
  110. IMPORT void intBoiExit ();
  111. IMPORT UINT32 sysStrayIntCount;
  112. IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
  113. /* defines */
  114. #define I8259_EOI_OPTIMIZED /* use the optimized version */
  115. /* globals */
  116. /* local */
  117. #ifndef SYMMETRIC_IO_MODE
  118. LOCAL INT8 i8259IntMask1; /* interrupt mask for PIC1 */
  119. LOCAL INT8 i8259IntMask2; /* interrupt mask for PIC2 */
  120. LOCAL INT8 i8259Mask = 0; /* interrupt mask for PIC1 */
  121. #endif /* SYMMETRIC_IO_MODE */
  122. /* forward static functions */
  123. /*******************************************************************************
  124. *
  125. * i8259Init - initialize the PIC
  126. *
  127. * This routine initializes the PIC.
  128. *
  129. */
  130. VOID i8259Init (void)
  131.     {
  132.     UINT8 icw4 = 0x01;
  133.     /* return if it is not the Boot Processor (BP) */
  134.     if (sysBp == FALSE)
  135. return;
  136.     /* initialize the PIC (Programmable Interrupt Controller) */
  137.     sysOutByte (PIC_port1 (PIC1_BASE_ADR),0x11);        /* ICW1 */
  138.     sysOutByte (PIC_port2 (PIC1_BASE_ADR),INT_NUM_IRQ0); /* ICW2 */
  139.     sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x04);        /* ICW3 */
  140. #ifdef I8259_SPECIAL_FULLY_NESTED_MODE
  141.     icw4 |= 0x10; /* SFNM */
  142. #endif /* I8259_SPECIAL_FULLY_NESTED_MODE */
  143. #ifdef I8259_AUTO_EOI
  144.     icw4 |= 0x02; /* AEOI */
  145. #endif /* I8259_AUTO_EOI */
  146.     sysOutByte (PIC_port2 (PIC1_BASE_ADR),icw4);        /* ICW4 */
  147.     sysOutByte (PIC_port1 (PIC2_BASE_ADR),0x11);        /* ICW1 */
  148.     sysOutByte (PIC_port2 (PIC2_BASE_ADR),INT_NUM_IRQ0+8); /* ICW2 */
  149.     sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x02);        /* ICW3 */
  150.     sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x01);        /* ICW4 */
  151.     /* disable interrupts */
  152.     sysOutByte (PIC_IMASK (PIC1_BASE_ADR),0xfb);
  153.     sysOutByte (PIC_IMASK (PIC2_BASE_ADR),0xff);
  154.     }
  155. #ifndef SYMMETRIC_IO_MODE
  156. /*******************************************************************************
  157. *
  158. * i8259IntBoiEem - issue EOI before the IRQ0 interrupt handler
  159. *
  160. * This routine is called before the IRQ0 interrupt handler that is PIT(8253)
  161. * channel 0 system clock interrupt handler in the Early EOI Mode.
  162. *
  163. */
  164. VOID i8259IntBoiEem
  165.     (
  166.     int irqNo /* IRQ number of the interrupt */
  167.     )
  168.     {
  169.     INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
  170.     sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
  171.     intUnlock (oldLevel); /* UNLOCK INTERRUPT */
  172.     }
  173. /*******************************************************************************
  174. *
  175. * i8259IntBoiSmm - enable Special Mask Mode before the IRQ0 interrupt handler
  176. *
  177. * This routine is called before the IRQ0 interrupt handler that is PIT(8253)
  178. * channel 0 system clock interrupt handler, in the Special Mask Mode.
  179. *
  180. */
  181. VOID i8259IntBoiSmm
  182.     (
  183.     int irqNo /* IRQ number of the interrupt */
  184.     )
  185.     {
  186.     INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
  187.     sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x68); /* enable SMM PIC1 */
  188.     i8259Mask = sysInByte (PIC_IMASK (PIC1_BASE_ADR)); /* save int mask */
  189.     sysOutByte (PIC_IMASK (PIC1_BASE_ADR), 0x01); /* unlock except IRQ0 */
  190.     intUnlock (oldLevel); /* UNLOCK INTERRUPT */
  191.     }
  192. /*******************************************************************************
  193. *
  194. * i8259IntBoi - detect whether it is spurious interrupt or not
  195. *
  196. * This routine is called before the user's interrupt handler to detect the
  197. * spurious interrupt.
  198. *
  199. */
  200. VOID i8259IntBoi
  201.     (
  202.     INT32 irqNo /* IRQ number of the interrupt */
  203.     )
  204.     {
  205.     INT32 oldLevel;
  206.     INT8 inserviceReg;
  207.     /* we are interested in IRQ7 and IRQ15 */
  208.     if ((irqNo != 7) && (irqNo != 15))
  209. return;
  210.     /* if ISR bit is not set, we change the return address */
  211.     oldLevel = intLock (); /* LOCK INTERRUPT */
  212.     if (irqNo == 7)
  213. {
  214.         sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
  215.         inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
  216. }
  217.     else
  218. {
  219.         sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);
  220.         inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));
  221. }
  222.     
  223.     intUnlock (oldLevel); /* UNLOCK INTERRUPT */
  224.     /*
  225.      * another implementation idea...
  226.      *
  227.      * *((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit;
  228.      * This changes the return addr on the stack.  This is architecture
  229.      * specific and tricky.  Thus making following change may be good idea.
  230.      * 
  231.      * - let this routine return OK or ERROR
  232.      * - let interrupt stub code check the ret value and jump to intExit.
  233.      *
  234.      * New code would be like this:
  235.      * :
  236.      * if ((irqNo != 7) && (irqNo != 15))
  237.      * return (OK);
  238.      * :
  239.      * if ((inserviceReg & 0x80) == 0) * check bit7 for IRQ7 and IRQ15 *
  240.      * {
  241.      * sysStrayIntCount++; * increment the counter *
  242.      *  return (ERROR);
  243.      * }
  244.      * }
  245.      *
  246.      * 00  e8 kk kk kk kk           call    _intEnt         * tell kernel
  247.      * 05  50                       pushl   %eax            * save regs
  248.      * 06  52                       pushl   %edx
  249.      * 07  51                       pushl   %ecx
  250.      * 08  68 pp pp pp pp           pushl   $_parameterBoi  * push BOI param
  251.      * 13  e8 rr rr rr rr           call    _routineBoi     * call BOI routine
  252.      *                              addl    $4, %esp
  253.      *                              cmpl    $0, %eax
  254.      *                              jne     intConnectCode0
  255.      * 18  68 pp pp pp pp           pushl   $_parameter     * push param
  256.      * 23  e8 rr rr rr rr           call    _routine        * call C routine
  257.      *                              addl    $4, %esp
  258.      * 28  68 pp pp pp pp           pushl   $_parameterEoi  * push EOI param
  259.      * 33  e8 rr rr rr rr           call    _routineEoi     * call EOI routine
  260.      * 38  83 c4 04                 addl    $4, %esp        * pop param
  261.      * intConnectCode0:
  262.      * 41  59                       popl    %ecx            * restore regs
  263.      * 42  5a                       popl    %edx
  264.      * 43  58                       popl    %eax
  265.      * 44  e9 kk kk kk kk           jmp     _intExit        *  exit via kernel
  266.      */
  267.      
  268.     if ((inserviceReg & 0x80) == 0) /* check bit7 for IRQ7 and IRQ15 */
  269. {
  270. sysStrayIntCount++; /* increment the counter */
  271.         *((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit; /* change return addr */
  272. }
  273.     }
  274. /*******************************************************************************
  275. *
  276. * i8259IntEoiSmm - disable Special Mask Mode with EOI signal to the master PIC
  277. *
  278. * This routine is called at the end of the IRQ0 interrupt handler that is 
  279. * PIT(8253) channel 0 system clock interrupt handler in the Special Mask Mode.
  280. *
  281. */
  282. VOID i8259IntEoiSmm 
  283.     (
  284.     int irqNo /* IRQ number to send EOI */
  285.     )
  286.     {
  287.     INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
  288.     sysOutByte (PIC_IMASK (PIC1_BASE_ADR), i8259Mask); /* restore old mask */
  289.     sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x08); /* disable SMM PIC1 */
  290.     sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
  291.     intUnlock (oldLevel); /* UNLOCK INTERRUPT */
  292.     }
  293. /*******************************************************************************
  294. *
  295. * i8259IntEoiMaster - send EOI(end of interrupt) signal to the master PIC.
  296. *
  297. * This routine is called at the end of the interrupt handler.
  298. *
  299. */
  300. VOID i8259IntEoiMaster 
  301.     (
  302.     INT32 irqNo /* IRQ number to send EOI */
  303.     )
  304.     {
  305. #ifdef I8259_EOI_OPTIMIZED /* optimized version */
  306.     WRS_ASM ("
  307. pushfl;
  308. cli;
  309. movl $0x20, %edx;
  310. movl $0x20, %eax;
  311. outb %al, %dx;
  312. popfl;
  313. ");
  314. #else /* portable version */
  315.     INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
  316.     sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
  317.     intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
  318. #endif /* I8259_EOI_OPTIMIZED */
  319.     }
  320. /*******************************************************************************
  321. *
  322. * i8259IntEoiSlave - send EOI(end of interrupt) signal to the slave PIC.
  323. *
  324. * This routine is called at the end of the interrupt handler in the Normal 
  325. * Fully Nested Mode.  This is kept for the backward compatibility.
  326. *
  327. */
  328. VOID i8259IntEoiSlave
  329.     (
  330.     INT32 irqNo /* IRQ number to send EOI */
  331.     )
  332.     {
  333. #ifdef I8259_EOI_OPTIMIZED /* optimized version */
  334.     WRS_ASM ("
  335. pushfl;
  336. cli;
  337. movl $0xa0, %edx;
  338. movl $0x20, %eax;
  339. outb %al, %dx;
  340. movl $0x20, %edx;
  341. outb %al, %dx;
  342. popfl;
  343. ");
  344. #else /* portable version */
  345.     INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
  346.     sysOutByte (PIC_IACK (PIC2_BASE_ADR), I8259_EOI); /* non-specific EOI */
  347.     sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
  348.     intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
  349. #endif /* I8259_EOI_OPTIMIZED */
  350.     }
  351. /*******************************************************************************
  352. *
  353. * i8259IntEoiSlaveNfnm - send EOI(end of interrupt) signal to the slave PIC.
  354. *
  355. * This routine is called at the end of the interrupt handler in the Normal 
  356. * Fully Nested Mode.
  357. *
  358. */
  359. VOID i8259IntEoiSlaveNfnm
  360.     (
  361.     INT32 irqNo /* IRQ number to send EOI */
  362.     )
  363.     {
  364. #ifdef I8259_EOI_OPTIMIZED /* optimized version */
  365.     WRS_ASM ("
  366. pushfl;
  367. cli;
  368. movl $0xa0, %edx;
  369. movl $0x20, %eax;
  370. outb %al, %dx;
  371. movl $0x20, %edx;
  372. outb %al, %dx;
  373. popfl;
  374. ");
  375. #else /* portable version */
  376.     INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
  377.     sysOutByte (PIC_IACK (PIC2_BASE_ADR), I8259_EOI); /* non-specific EOI */
  378.     sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
  379.     intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
  380. #endif /* I8259_EOI_OPTIMIZED */
  381.     }
  382. /*******************************************************************************
  383. *
  384. * i8259IntEoiSlaveSfnm - send EOI(end of interrupt) signal to the slave PIC.
  385. *
  386. * This routine is called at the end of the interrupt handler in the Special 
  387. * Fully Nested Mode.
  388. *
  389. */
  390. VOID i8259IntEoiSlaveSfnm
  391.     (
  392.     int irqNo /* IRQ number to send EOI */
  393.     )
  394.     {
  395.     INT8  inserviceReg;
  396.     INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
  397.     sysOutByte (PIC_IACK (PIC2_BASE_ADR), 0x20); /* NS EOI to PIC2 */
  398.     sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b); /* issue OCW3 */
  399.     inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR)); /* read ISR */
  400.     if (inserviceReg == 0) 
  401.         sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
  402.     intUnlock (oldLevel); /* UNLOCK INTERRUPT */
  403.     }
  404. /*******************************************************************************
  405. *
  406. * i8259IntDisable - disable a specified PIC interrupt input line
  407. *
  408. * This routine disables a specified PIC interrupt input line.
  409. *
  410. * RETURNS: OK, always.
  411. *
  412. * SEE ALSO: i8259IntEnable()
  413. *
  414. * ARGSUSED0
  415. */
  416. LOCAL STATUS i8259IntDisable
  417.     (
  418.     INT32 irqNo        /* IRQ number to disable */
  419.     )
  420.     {
  421.     if (irqNo < 8)
  422. {
  423. sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
  424.     sysInByte (PIC_IMASK (PIC1_BASE_ADR)) | (1 << irqNo));
  425. }
  426.     else
  427. {
  428. sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
  429.     sysInByte (PIC_IMASK (PIC2_BASE_ADR)) | (1 << (irqNo - 8)));
  430. }
  431.     return (OK);
  432.     }
  433. /*******************************************************************************
  434. *
  435. * i8259IntEnable - enable a specified PIC interrupt input line
  436. *
  437. * This routine enables a specified PIC interrupt input line.
  438. *
  439. * RETURNS: OK, always.
  440. *
  441. * SEE ALSO: i8259IntDisable()
  442. *
  443. * ARGSUSED0
  444. */
  445. LOCAL STATUS i8259IntEnable
  446.     (
  447.     INT32 irqNo        /* IRQ number to enable */
  448.     )
  449.     {
  450.     if (irqNo < 8)
  451. {
  452. sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
  453.     sysInByte (PIC_IMASK (PIC1_BASE_ADR)) & ~(1 << irqNo));
  454. }
  455.     else
  456. {
  457. sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
  458.     sysInByte (PIC_IMASK (PIC2_BASE_ADR)) & ~(1 << (irqNo - 8)));
  459. }
  460.     return (OK);
  461.     }
  462. /*******************************************************************************
  463. *
  464. * i8259IntLock - lock out all PIC interrupts
  465. *
  466. * This routine saves the mask and locks out all PIC interrupts.
  467. * It should be called in the interrupt disable state(IF bit is 0).
  468. *
  469. * SEE ALSO: i8259IntUnlock()
  470. *
  471. * ARGSUSED0
  472. */
  473. LOCAL VOID i8259IntLock (void)
  474.     {
  475.     i8259IntMask1 = sysInByte (PIC_IMASK (PIC1_BASE_ADR));
  476.     i8259IntMask2 = sysInByte (PIC_IMASK (PIC2_BASE_ADR));
  477.     sysOutByte (PIC_IMASK (PIC1_BASE_ADR), 0xff);
  478.     sysOutByte (PIC_IMASK (PIC2_BASE_ADR), 0xff);
  479.     }
  480. /*******************************************************************************
  481. *
  482. * i8259IntUnlock - unlock the PIC interrupts
  483. *
  484. * This routine restores the mask and unlocks the PIC interrupts
  485. * It should be called in the interrupt disable state(IF bit is 0).
  486. *
  487. * SEE ALSO: i8259IntLock()
  488. *
  489. * ARGSUSED0
  490. */
  491. LOCAL VOID i8259IntUnlock (void)
  492.     {
  493.     sysOutByte (PIC_IMASK (PIC1_BASE_ADR), i8259IntMask1);
  494.     sysOutByte (PIC_IMASK (PIC2_BASE_ADR), i8259IntMask2);
  495.     }
  496. #if FALSE
  497. /*
  498.  * There is a function sysIntLevel() which get the interrupt level from the 
  499.  * interrupt stub, so we don't need it anymore.
  500.  */
  501. /*******************************************************************************
  502. *
  503. * i8259IntLevel - Get IRQ number by reading Interrupt Service Register.
  504. *
  505. * This routine is called to get an IRQ number in service.
  506. *
  507. * RETURNS: 0 - 15.
  508. *
  509. * ARGSUSED0
  510. */
  511. LOCAL INT32 i8259IntLevel (void)
  512.     {
  513.     INT32 inserviceReg;
  514.     INT32 irq;
  515.     INT32 oldLevel;
  516.     INT32 retry;
  517.     oldLevel = intLock ();
  518.     for (retry=0; retry < 1; retry ++)
  519. {
  520.         sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
  521.         inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
  522.         for (irq=0; irq < 8; irq++)
  523.     if ((inserviceReg & 1) && (irq != 2))
  524.         goto i8259IntLevelExit;
  525.     else
  526.         inserviceReg >>= 1;
  527.         sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);
  528.         inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));
  529.         for (irq=8; irq < 16; irq++)
  530.     if (inserviceReg & 1)
  531.         goto i8259IntLevelExit;
  532.     else
  533.         inserviceReg >>= 1;
  534. }
  535.     i8259IntLevelExit:
  536.     intUnlock (oldLevel);
  537.     return (irq);
  538.     }
  539. #endif /* FALSE */
  540. #endif /* SYMMETRIC_IO_MODE */