Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:58

0001 /*
0002  *  This file contains the implementation of the function described in irq.h
0003  *  related to Intel 8259 Programmable Interrupt controller.
0004  *
0005  *  Copyright (C) 1998, 1999 valette@crf.canon.fr
0006  *
0007  *  The license and distribution terms for this file may be
0008  *  found in the file LICENSE in this distribution or at
0009  *  http://www.rtems.org/license/LICENSE.
0010  */
0011 
0012 #include <bsp.h>
0013 #include <bsp/irq.h>
0014 
0015 #define PIC_EOSI        0x60    ///< End of Specific Interrupt (EOSI)
0016 #define PIC_EOI         0x20    ///< Generic End of Interrupt (EOI)
0017 
0018 /* Operation control word type 3.  Bit 3 (0x08) must be set. Even address. */
0019 #define PIC_OCW3_RIS        0x01            /* 1 = read IS, 0 = read IR */
0020 #define PIC_OCW3_RR         0x02            /* register read */
0021 #define PIC_OCW3_P          0x04            /* poll mode command */
0022 /* 0x08 must be 1 to select OCW3 vs OCW2 */
0023 #define PIC_OCW3_SEL        0x08            /* must be 1 */
0024 /* 0x10 must be 0 to select OCW3 vs ICW1 */
0025 #define PIC_OCW3_SMM        0x20            /* special mode mask */
0026 #define PIC_OCW3_ESMM       0x40            /* enable SMM */
0027 
0028 /*-------------------------------------------------------------------------+
0029 | Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
0030 +--------------------------------------------------------------------------*/
0031 /*
0032  * lower byte is interrupt mask on the master PIC.
0033  * while upper bits are interrupt on the slave PIC.
0034  */
0035 static rtems_i8259_masks i8259s_imr_cache = 0xFFFB;
0036 static rtems_i8259_masks i8259s_in_progress = 0;
0037 
0038 static inline
0039 void BSP_i8259s_irq_update_master_imr( void )
0040 {
0041   rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
0042   outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff );
0043 }
0044 
0045 static inline
0046 void BSP_i8259s_irq_update_slave_imr( void )
0047 {
0048   rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
0049   outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff );
0050 }
0051 
0052 /*
0053  * Is the IRQ valid?
0054  */
0055 static inline bool BSP_i8259s_irq_valid(const rtems_irq_number irqLine)
0056 {
0057   return ((int)irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET) &&
0058     ((int)irqLine <= BSP_ISA_IRQ_MAX_OFFSET);
0059 }
0060 
0061 /*
0062  * Read the IRR register. The default.
0063  */
0064 static inline uint8_t BSP_i8259s_irq_int_request_reg(uint32_t ioport)
0065 {
0066   uint8_t isr;
0067   inport_byte(ioport, isr);
0068   return isr;
0069 }
0070 
0071 /*
0072  * Read the ISR register. Keep the default of the IRR.
0073  */
0074 static inline uint8_t BSP_i8259s_irq_in_service_reg(uint32_t ioport)
0075 {
0076   uint8_t isr;
0077   outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
0078   inport_byte(ioport, isr);
0079   outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
0080   return isr;
0081 }
0082 
0083 /*-------------------------------------------------------------------------+
0084 |         Function:  BSP_irq_disable_at_i8259s
0085 |      Description: Mask IRQ line in appropriate PIC chip.
0086 | Global Variables: i8259s_imr_cache, i8259s_in_progress
0087 |        Arguments: vector_offset - number of IRQ line to mask.
0088 |          Returns: 0 is OK.
0089 +--------------------------------------------------------------------------*/
0090 int BSP_irq_disable_at_i8259s(const rtems_irq_number irqLine)
0091 {
0092   unsigned short        mask;
0093   rtems_interrupt_level level;
0094 
0095   if (!BSP_i8259s_irq_valid(irqLine))
0096     return -1;
0097 
0098   rtems_interrupt_disable(level);
0099 
0100   mask = 1 << irqLine;
0101   i8259s_imr_cache |= mask;
0102 
0103   if (irqLine < 8)
0104   {
0105     BSP_i8259s_irq_update_master_imr();
0106   }
0107   else
0108   {
0109     BSP_i8259s_irq_update_slave_imr();
0110   }
0111 
0112   rtems_interrupt_enable(level);
0113 
0114   return 0;
0115 }
0116 
0117 /*-------------------------------------------------------------------------+
0118 |         Function:  BSP_irq_enable_at_i8259s
0119 |      Description: Unmask IRQ line in appropriate PIC chip.
0120 | Global Variables: i8259s_imr_cache, i8259s_in_progress
0121 |        Arguments: irqLine - number of IRQ line to mask.
0122 |          Returns: Nothing.
0123 +--------------------------------------------------------------------------*/
0124 int BSP_irq_enable_at_i8259s(const rtems_irq_number irqLine)
0125 {
0126   rtems_interrupt_level level;
0127   unsigned short        mask;
0128 
0129   if (!BSP_i8259s_irq_valid(irqLine))
0130     return 1;
0131 
0132   rtems_interrupt_disable(level);
0133 
0134   mask = 1 << irqLine;
0135   i8259s_imr_cache &= ~mask;
0136 
0137   if (irqLine < 8)
0138   {
0139     BSP_i8259s_irq_update_master_imr();
0140   }
0141   else
0142   {
0143     BSP_i8259s_irq_update_slave_imr();
0144   }
0145 
0146   rtems_interrupt_enable(level);
0147 
0148   return 0;
0149 } /* mask_irq */
0150 
0151 int BSP_irq_enabled_at_i8259s(const rtems_irq_number irqLine)
0152 {
0153   unsigned short mask;
0154 
0155   if (!BSP_i8259s_irq_valid(irqLine))
0156     return 1;
0157 
0158   mask = (1 << irqLine);
0159   return  (~(i8259s_imr_cache & mask));
0160 }
0161 
0162 /*-------------------------------------------------------------------------+
0163 |         Function: BSP_irq_ack_at_i8259s
0164 |      Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
0165 | Global Variables: None.
0166 |        Arguments: irqLine - number of IRQ line to acknowledge.
0167 |          Returns: Nothing.
0168 +--------------------------------------------------------------------------*/
0169 int BSP_irq_ack_at_i8259s(const rtems_irq_number irqLine)
0170 {
0171   uint8_t slave_isr = 0;
0172 
0173   if (irqLine >= 8) {
0174    outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
0175    slave_isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
0176   }
0177 
0178   /*
0179    * Only issue the EOI to the master if there are no more interrupts in
0180    * service for the slave. i8259a data sheet page 18, The Special Fully Nested
0181    * Mode, b.
0182    */
0183   if (slave_isr == 0)
0184     outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
0185 
0186   return 0;
0187 
0188 } /* ackIRQ */
0189 
0190 unsigned short BSP_irq_suspend_i8259s(unsigned short mask)
0191 {
0192   unsigned short in_progress_save = i8259s_in_progress;
0193   i8259s_in_progress |= mask;
0194   BSP_i8259s_irq_update_master_imr();
0195   BSP_i8259s_irq_update_slave_imr();
0196   return in_progress_save;
0197 }
0198 
0199 void BSP_irq_resume_i8259s(unsigned short in_progress_save)
0200 {
0201   i8259s_in_progress = in_progress_save;
0202   BSP_i8259s_irq_update_master_imr();
0203   BSP_i8259s_irq_update_slave_imr();
0204 }
0205 
0206 void BSP_i8259s_init(void)
0207 {
0208   /*
0209    * Always mask at least current interrupt to prevent re-entrance
0210    */
0211   outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */
0212   outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base  = 0 */
0213   outport_byte(PIC_MASTER_IMR_IO_PORT, 0x04);/* edge tiggered, Cascade (slave) on IRQ2 */
0214   outport_byte(PIC_MASTER_IMR_IO_PORT, 0x01);/* Select 8086 mode */
0215   outport_byte(PIC_MASTER_IMR_IO_PORT, 0xFB); /* Mask all except cascade */
0216   /*
0217    * init slave  interrupt controller
0218    */
0219   outport_byte(PIC_SLAVE_COMMAND_IO_PORT, 0x11); /* Start init sequence */
0220   outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x08);/* Vector base  = 8 */
0221   outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x02);/* edge triggered, Cascade (slave) on IRQ2 */
0222   outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x01); /* Select 8086 mode */
0223   outport_byte(PIC_SLAVE_IMR_IO_PORT, 0xFF); /* Mask all */
0224 
0225 }