summaryrefslogtreecommitdiff
path: root/src/arch/amd64/pic.c
blob: ebf6b4022f749162384d648fc08400c9dae08252 (plain)
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
#include "bindings.h"
#include "pic.h"

#define PIC1_COMMAND_PORT 0x20
#define PIC1_DATA_PORT 0x21
#define PIC2_COMMAND_PORT 0xA0
#define PIC2_DATA_PORT 0xA1

void pic_remap(void) {
	char a1 = inb(PIC1_DATA_PORT);
	char a2 = inb(PIC2_DATA_PORT);
	// control word 1
	// 0x11: initialize, enable ICW4
	outb(PIC1_COMMAND_PORT, 0x11);
	io_wait();
	outb(PIC2_COMMAND_PORT, 0x11);
	io_wait();
	// control word 2
	// interrupt offset
	outb(PIC1_DATA_PORT, PIC_REMAP_OFFSET);
	io_wait();
	outb(PIC2_DATA_PORT, PIC_REMAP_OFFSET + 8);
	io_wait();
	// control word 3
	// primary pic: set which pin secondary is connected to
	// (pin 2)
	outb(PIC1_DATA_PORT, 0x04);
	io_wait();
	outb(PIC2_DATA_PORT, 2);
	io_wait();
	// control word 3
	// 0x01: enable 8086 mode
	outb(PIC1_DATA_PORT, 0x01);
	io_wait();
	outb(PIC2_DATA_PORT, 0x01);
	io_wait();
	// clear data registers
	outb(PIC1_DATA_PORT, a1);
	outb(PIC2_DATA_PORT, a2);
}

void pic_mask(int irq) {
	uint8_t port;
	if(irq < 8) {
		port = PIC1_DATA_PORT;
	} else {
		irq -= 8;
		port = PIC2_DATA_PORT;
	}
	uint8_t mask = inb(port);
	outb(port, mask | (1 << irq));
}

void pic_unmask(int irq) {
	uint8_t port;
	if(irq < 8) {
		port = PIC1_DATA_PORT;
	} else {
		irq -= 8;
		port = PIC2_DATA_PORT;
	}
	uint8_t mask = inb(port);
	outb(port, mask & ~(1 << irq));
}

void pic_disable(void) {
	outb(PIC1_DATA_PORT, 0xff);
	io_wait();
	outb(PIC2_DATA_PORT, 0xff);
	io_wait();
}

void pic_eoi(int irq) {
	if(irq >= 8) {
		outb(PIC2_COMMAND_PORT, 0x20);
	}
	outb(PIC1_COMMAND_PORT, 0x20);
}