2006-06-16 22:29:25 +02:00
|
|
|
#include "types.h"
|
|
|
|
#include "x86.h"
|
2006-09-03 17:39:29 +02:00
|
|
|
#include "traps.h"
|
2006-06-16 22:29:25 +02:00
|
|
|
#include "defs.h"
|
|
|
|
|
2006-07-05 22:00:14 +02:00
|
|
|
// I/O Addresses of the two 8259A programmable interrupt controllers
|
2006-09-06 19:04:06 +02:00
|
|
|
#define IO_PIC1 0x20 // Master (IRQs 0-7)
|
|
|
|
#define IO_PIC2 0xA0 // Slave (IRQs 8-15)
|
2006-07-05 22:00:14 +02:00
|
|
|
|
2006-09-06 19:04:06 +02:00
|
|
|
#define IRQ_SLAVE 2 // IRQ at which slave connects to master
|
2006-07-05 22:00:14 +02:00
|
|
|
|
2006-06-16 22:29:25 +02:00
|
|
|
// Current IRQ mask.
|
|
|
|
// Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
|
2006-09-07 17:29:54 +02:00
|
|
|
static ushort irq_mask_8259A = 0xFFFF & ~(1<<IRQ_SLAVE);
|
2006-08-04 20:23:23 +02:00
|
|
|
|
2006-09-07 17:29:54 +02:00
|
|
|
static void
|
2006-08-04 20:23:23 +02:00
|
|
|
irq_setmask_8259A(ushort mask)
|
|
|
|
{
|
|
|
|
irq_mask_8259A = mask;
|
|
|
|
|
|
|
|
outb(IO_PIC1+1, (char)mask);
|
|
|
|
outb(IO_PIC2+1, (char)(mask >> 8));
|
|
|
|
}
|
2006-06-16 22:29:25 +02:00
|
|
|
|
2006-09-07 17:29:54 +02:00
|
|
|
void
|
|
|
|
irq_enable(int irq)
|
|
|
|
{
|
|
|
|
irq_setmask_8259A(irq_mask_8259A & ~(1<<irq));
|
|
|
|
}
|
|
|
|
|
2006-09-06 19:50:20 +02:00
|
|
|
// Initialize the 8259A interrupt controllers.
|
2006-06-16 22:29:25 +02:00
|
|
|
void
|
|
|
|
pic_init(void)
|
|
|
|
{
|
2006-07-05 22:00:14 +02:00
|
|
|
// mask all interrupts
|
|
|
|
outb(IO_PIC1+1, 0xFF);
|
|
|
|
outb(IO_PIC2+1, 0xFF);
|
|
|
|
|
|
|
|
// Set up master (8259A-1)
|
|
|
|
|
|
|
|
// ICW1: 0001g0hi
|
|
|
|
// g: 0 = edge triggering, 1 = level triggering
|
|
|
|
// h: 0 = cascaded PICs, 1 = master only
|
|
|
|
// i: 0 = no ICW4, 1 = ICW4 required
|
|
|
|
outb(IO_PIC1, 0x11);
|
|
|
|
|
|
|
|
// ICW2: Vector offset
|
|
|
|
outb(IO_PIC1+1, IRQ_OFFSET);
|
|
|
|
|
2006-09-06 21:08:14 +02:00
|
|
|
// ICW3: (master PIC) bit mask of IR lines connected to slaves
|
|
|
|
// (slave PIC) 3-bit # of slave's connection to master
|
2006-07-05 22:00:14 +02:00
|
|
|
outb(IO_PIC1+1, 1<<IRQ_SLAVE);
|
|
|
|
|
|
|
|
// ICW4: 000nbmap
|
|
|
|
// n: 1 = special fully nested mode
|
|
|
|
// b: 1 = buffered mode
|
|
|
|
// m: 0 = slave PIC, 1 = master PIC
|
2006-09-06 19:04:06 +02:00
|
|
|
// (ignored when b is 0, as the master/slave role
|
|
|
|
// can be hardwired).
|
2006-07-05 22:00:14 +02:00
|
|
|
// a: 1 = Automatic EOI mode
|
|
|
|
// p: 0 = MCS-80/85 mode, 1 = intel x86 mode
|
|
|
|
outb(IO_PIC1+1, 0x3);
|
|
|
|
|
|
|
|
// Set up slave (8259A-2)
|
2006-09-06 19:04:06 +02:00
|
|
|
outb(IO_PIC2, 0x11); // ICW1
|
|
|
|
outb(IO_PIC2+1, IRQ_OFFSET + 8); // ICW2
|
|
|
|
outb(IO_PIC2+1, IRQ_SLAVE); // ICW3
|
2006-07-05 22:00:14 +02:00
|
|
|
// NB Automatic EOI mode doesn't tend to work on the slave.
|
|
|
|
// Linux source code says it's "to be investigated".
|
2006-09-06 19:04:06 +02:00
|
|
|
outb(IO_PIC2+1, 0x3); // ICW4
|
2006-07-05 22:00:14 +02:00
|
|
|
|
|
|
|
// OCW3: 0ef01prs
|
|
|
|
// ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask
|
|
|
|
// p: 0 = no polling, 1 = polling mode
|
|
|
|
// rs: 0x = NOP, 10 = read IRR, 11 = read ISR
|
2006-09-06 19:50:20 +02:00
|
|
|
outb(IO_PIC1, 0x68); // clear specific mask
|
|
|
|
outb(IO_PIC1, 0x0a); // read IRR by default
|
2006-07-05 22:00:14 +02:00
|
|
|
|
2006-09-06 19:50:20 +02:00
|
|
|
outb(IO_PIC2, 0x68); // OCW3
|
|
|
|
outb(IO_PIC2, 0x0a); // OCW3
|
2006-07-05 22:00:14 +02:00
|
|
|
|
2006-09-06 19:27:19 +02:00
|
|
|
if(irq_mask_8259A != 0xFFFF)
|
2006-07-05 22:00:14 +02:00
|
|
|
irq_setmask_8259A(irq_mask_8259A);
|
2006-06-16 22:29:25 +02:00
|
|
|
}
|