forked from derekalyne/small-linux-kernel-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathi8259.c
81 lines (67 loc) · 2.34 KB
/
i8259.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
/* i8259.c - Functions to interact with the 8259 interrupt controller
* vim:ts=4 noexpandtab
*/
#include "i8259.h"
/* Interrupt masks to determine which interrupts are enabled and disabled */
uint8_t master_mask = FULL_MASK; /* IRQs 0-7 */
uint8_t slave_mask = FULL_MASK; /* IRQs 8-15 */
/* Initialize the 8259 PIC */
void i8259_init(void) {
// mask out everything
outb(master_mask, MASTER_8259_PORT_DATA);
outb(slave_mask, SLAVE_8259_PORT_DATA);
// send init icw to both pics
outb(ICW1, MASTER_8259_PORT_CMD);
outb(ICW1, SLAVE_8259_PORT_CMD);
// specify offsets for both pics
outb(ICW2_MASTER, MASTER_8259_PORT_DATA);
outb(ICW2_SLAVE, SLAVE_8259_PORT_DATA);
// specify master/slave config
outb(ICW3_MASTER, MASTER_8259_PORT_DATA);
outb(ICW3_SLAVE, SLAVE_8259_PORT_DATA);
// send icw4 to both pics
outb(ICW4, MASTER_8259_PORT_DATA);
outb(ICW4, SLAVE_8259_PORT_DATA);
// enable slave PIC
enable_irq(SLAVE_IRQ);
}
/* Enable (unmask) the specified IRQ */
void enable_irq(uint32_t irq_num) {
if(irq_num < NUM_IRQS) {
// set bit at index irq_num
master_mask &= ~(1 << irq_num);
outb(master_mask, MASTER_8259_PORT_DATA);
} else {
// set irq num to start at 0
irq_num -= NUM_IRQS;
// set bit at index irq_num
slave_mask &= ~(1 << irq_num);
outb(slave_mask, SLAVE_8259_PORT_DATA);
}
}
/* Disable (mask) the specified IRQ */
void disable_irq(uint32_t irq_num) {
if(irq_num < NUM_IRQS) {
// clear bit at index irq_num
master_mask |= (1 << irq_num);
outb(master_mask, MASTER_8259_PORT_DATA);
} else {
// set irq num to start at 0
irq_num -= NUM_IRQS;
// clear bit at index irq_num
slave_mask |= (1 << irq_num);
outb(slave_mask, SLAVE_8259_PORT_DATA);
}
}
/* Send end-of-interrupt signal for the specified IRQ */
void send_eoi(uint32_t irq_num) {
if(irq_num >= NUM_IRQS) {
// OR EOI with irq, -8 to offset slave to index 0
outb((EOI | (irq_num - NUM_IRQS)), SLAVE_8259_PORT_CMD);
// send EOI to master PIC
outb((EOI | SLAVE_IRQ), MASTER_8259_PORT_CMD);
} else {
// OR EOI with irq
outb((EOI | irq_num), MASTER_8259_PORT_CMD);
}
}