-
Notifications
You must be signed in to change notification settings - Fork 13
/
picirq.c
124 lines (102 loc) · 2.96 KB
/
picirq.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Intel 8259A programmable interrupt controllers.
#include "types.h"
#include "defs.h"
#include "mips.h"
#include "traps.h"
// I/O Addresses of the two programmable interrupt controllers
#define IO_PIC1 0x20 // Master (IRQs 0-7)
#define IO_PIC2 0xA0 // Slave (IRQs 8-15)
#define IRQ_SLAVE 2 // IRQ at which slave connects to master
// Current IRQ mask.
// Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
static ushort irqmask = 0xFFFF & ~(1<<IRQ_SLAVE);
static void
picsetmask(ushort mask)
{
irqmask = mask;
outb(IO_PIC1+1, mask);
outb(IO_PIC2+1, mask >> 8);
}
void
picenable(int irq)
{
picsetmask(irqmask & ~(1<<irq));
}
void
picdisable(int irq)
{
picsetmask(irqmask | (1<<irq));
}
// Initialize the 8259A interrupt controllers.
void
picinit(void)
{
// 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, T_IRQ0);
// ICW3: (master PIC) bit mask of IR lines connected to slaves
// (slave PIC) 3-bit # of slave's connection to master
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
// (ignored when b is 0, as the master/slave role
// can be hardwired).
// a: 1 = Automatic EOI mode
// p: 0 = MCS-80/85 mode, 1 = intel x86 mode
outb(IO_PIC1+1, 0x1);
// Set up slave (8259A-2)
outb(IO_PIC2, 0x11); // ICW1
outb(IO_PIC2+1, T_IRQ0 + 8); // ICW2
outb(IO_PIC2+1, IRQ_SLAVE); // ICW3
// NB Automatic EOI mode doesn't tend to work on the slave.
// Linux source code says it's "to be investigated".
outb(IO_PIC2+1, 0x1); // ICW4
// 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
outb(IO_PIC1, 0x68); // clear specific mask
outb(IO_PIC1, 0x0a); // read IRR by default
outb(IO_PIC2, 0x68); // OCW3
outb(IO_PIC2, 0x0a); // OCW3
if(irqmask != 0xFFFF)
picsetmask(irqmask);
}
// Read the IRQ number from the 8259A interrupt controllers.
int
picgetirq(void)
{
int irq;
outb(IO_PIC1, 0x0c); // polling
irq = inb(IO_PIC1)&7;
if(irq == IRQ_CASCADE){
outb(IO_PIC2, 0x0c);
irq = (inb(IO_PIC2)&7) + 8;
outb(IO_PIC2, 0x0a); // restore polling mode
}
outb(IO_PIC1, 0x0a); // restore polling mode
return irq;
}
void
picsendeoi(int irq)
{
if(irq == IRQ_SPURIOUS_MS)
return;
if(irq <= 7){
outb(IO_PIC1, 0x60 + irq);
} else {
if(irq != IRQ_SPURIOUS_SL)
outb(IO_PIC2, 0x60 + irq - 8);
outb(IO_PIC1, 0x60 + IRQ_CASCADE);
}
}