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
|
#include "pic.h"
#include "io.h"
void disable_irqs()
{
asm volatile("cli");
}
void enable_irqs()
{
asm volatile("sti");
}
void ack_irq(u8 lane)
{
if (lane >= 8)
outb(IO_PIC2_CTRL, 1 << 5);
outb(IO_PIC1_CTRL, 1 << 5);
}
void wait_irq()
{
asm volatile("hlt");
}
void unmask_irq(u8 lane)
{
u8 port = IO_PIC1_DATA;
if (lane >= 8) {
port = IO_PIC2_DATA;
lane -= 8;
}
outb(port, inb(port) & ~(1 << lane));
}
void pic_init()
{
typedef struct {
bool ic4 : 1;
bool single : 1;
bool addr_interval : 1;
bool level_triggered : 1;
bool init : 1;
unsigned int zeros : 3;
} __attribute__((packed)) pic_icw1;
u8 icw1 = BITCAST(((pic_icw1) {
.ic4 = true,
.single = false,
.addr_interval = false,
.level_triggered = false,
.init = true,
.zeros = 0,
}), pic_icw1, u8);
outb(IO_PIC1_CTRL, icw1);
outb(IO_PIC2_CTRL, icw1);
// map IRQs 0-15 to 0x20-0x2F
// 0x1F is the highest reserved interrupt
outb(IO_PIC1_DATA, 0x20);
outb(IO_PIC2_DATA, 0x28);
// pic2 is connected to IRQ2
outb(IO_PIC1_DATA, 1 << 2);
outb(IO_PIC2_DATA, 2);
typedef struct {
bool x86 : 1;
bool auto_eoi : 1;
bool primary_buffered : 1;
bool buffered : 1;
bool fully_nested : 1;
unsigned int zeros : 3;
} __attribute__((packed)) pic_icw4;
u8 icw4 = BITCAST(((pic_icw4) {
.x86 = true,
.auto_eoi = false,
.primary_buffered = false,
.buffered = false,
.fully_nested = false,
.zeros = 0,
}), pic_icw4, u8);
outb(IO_PIC1_DATA, icw4);
outb(IO_PIC2_DATA, icw4);
// mask all interrupts
outb(IO_PIC1_DATA, 0xff);
outb(IO_PIC2_DATA, 0xff);
disable_irqs();
}
|