blob: 0dc59cf272b8a54a65198b2fac63d1c4f329e913 [file] [log] [blame]
/*
* Basic support for controlling the 8259 Programmable Interrupt Controllers.
*
* Initially written by Michael Brown (mcb30).
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef PIC8259_H
#define PIC8259_H
#include <ipxe/io.h>
#define IRQ_PIC_CUTOFF 8
/* 8259 register locations */
#define PIC1_ICW1 0x20
#define PIC1_OCW2 0x20
#define PIC1_OCW3 0x20
#define PIC1_ICR 0x20
#define PIC1_IRR 0x20
#define PIC1_ISR 0x20
#define PIC1_ICW2 0x21
#define PIC1_ICW3 0x21
#define PIC1_ICW4 0x21
#define PIC1_IMR 0x21
#define PIC2_ICW1 0xa0
#define PIC2_OCW2 0xa0
#define PIC2_OCW3 0xa0
#define PIC2_ICR 0xa0
#define PIC2_IRR 0xa0
#define PIC2_ISR 0xa0
#define PIC2_ICW2 0xa1
#define PIC2_ICW3 0xa1
#define PIC2_ICW4 0xa1
#define PIC2_IMR 0xa1
/* Register command values */
#define OCW3_ID 0x08
#define OCW3_READ_IRR 0x02
#define OCW3_READ_ISR 0x03
#define ICR_EOI_NON_SPECIFIC 0x20
#define ICR_EOI_NOP 0x40
#define ICR_EOI_SPECIFIC 0x60
#define ICR_EOI_SET_PRIORITY 0xc0
/* Macros to enable/disable IRQs */
#define IMR_REG(x) ( (x) < IRQ_PIC_CUTOFF ? PIC1_IMR : PIC2_IMR )
#define IMR_BIT(x) ( 1 << ( (x) % IRQ_PIC_CUTOFF ) )
/* Macros for acknowledging IRQs */
#define ICR_REG( irq ) ( (irq) < IRQ_PIC_CUTOFF ? PIC1_ICR : PIC2_ICR )
#define ICR_VALUE( irq ) ( (irq) % IRQ_PIC_CUTOFF )
#define CHAINED_IRQ 2
/* Utility macros to convert IRQ numbers to INT numbers and INT vectors */
#define IRQ_INT( irq ) ( ( ( (irq) - IRQ_PIC_CUTOFF ) ^ 0x70 ) & 0x7f )
/* Other constants */
#define IRQ_MAX 15
#define IRQ_NONE -1U
/**
* Check if interrupt is enabled
*
* @v irq Interrupt number
* @ret enabled Interrupt is currently enabled
*/
static inline __attribute__ (( always_inline )) int
irq_enabled ( unsigned int irq ) {
int imr = inb ( IMR_REG ( irq ) );
int mask = IMR_BIT ( irq );
return ( ( imr & mask ) == 0 );
}
/**
* Enable interrupt
*
* @v irq Interrupt number
* @ret enabled Interrupt was previously enabled
*/
static inline __attribute__ (( always_inline )) int
enable_irq ( unsigned int irq ) {
int imr = inb ( IMR_REG ( irq ) );
int mask = IMR_BIT ( irq );
outb ( ( imr & ~mask ), IMR_REG ( irq ) );
return ( ( imr & mask ) == 0 );
}
/**
* Disable interrupt
*
* @v irq Interrupt number
* @ret enabled Interrupt was previously enabled
*/
static inline __attribute__ (( always_inline )) int
disable_irq ( unsigned int irq ) {
int imr = inb ( IMR_REG ( irq ) );
int mask = IMR_BIT ( irq );
outb ( ( imr | mask ), IMR_REG ( irq ) );
return ( ( imr & mask ) == 0 );
}
/* Function prototypes
*/
void send_eoi ( unsigned int irq );
#endif /* PIC8259_H */