summaryrefslogtreecommitdiff
path: root/Kernel/PIC.cpp
blob: 868cf5a97b8b8b6c0f16d42bc7304885caa426a9 (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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "types.h"
#include "i386.h"
#include "IO.h"
#include "VGA.h"
#include "PIC.h"
#include "Assertions.h"

// The slave 8259 is connected to the master's IRQ2 line.
// This is really only to enhance clarity.
#define SLAVE_INDEX     2

#define PIC0_CTL        0x20
#define PIC0_CMD        0x21
#define PIC1_CTL        0xA0
#define PIC1_CMD        0xA1

#ifdef DEBUG_PIC
static bool initialized;
#endif

namespace PIC {

void disable(BYTE irq)
{
    BYTE imr;
    if (irq & 8) {
        imr = IO::in8(PIC1_CMD);
        imr |= 1 << (irq - 8);
        IO::out8(PIC1_CMD, imr);
    } else {
        imr = IO::in8(PIC0_CMD);
        imr |= 1 << irq;
        IO::out8(PIC0_CMD, imr);
    }
}

void enable(BYTE irq)
{
    BYTE imr;
    if (irq & 8) {
        imr = IO::in8(PIC1_CMD);
        imr &= ~(1 << (irq - 8));
        IO::out8(PIC1_CMD, imr);
    } else {
        imr = IO::in8(PIC0_CMD);
        imr &= ~(1 << irq);
        IO::out8(PIC0_CMD, imr);
    }
}

void eoi(BYTE irq)
{
    if (irq & 8)
        IO::out8(PIC1_CTL, 0x20);
    IO::out8(PIC0_CTL, 0x20);
}

void initialize()
{
#ifdef DEBUG_PIC
    ASSERT(!initialized);
#endif

    /* ICW1 (edge triggered mode, cascading controllers, expect ICW4) */
    IO::out8(PIC0_CTL, 0x11);
    IO::out8(PIC1_CTL, 0x11);

    /* ICW2 (upper 5 bits specify ISR indices, lower 3 idunno) */
    IO::out8(PIC0_CMD, IRQ_VECTOR_BASE);
    IO::out8(PIC1_CMD, IRQ_VECTOR_BASE + 0x08);

    /* ICW3 (configure master/slave relationship) */
    IO::out8(PIC0_CMD, 1 << SLAVE_INDEX);
    IO::out8(PIC1_CMD, SLAVE_INDEX);

    /* ICW4 (set x86 mode) */
    IO::out8(PIC0_CMD, 0x01);
    IO::out8(PIC1_CMD, 0x01 );

    // Mask -- enable all interrupts on both PICs.
    // Not really what I want here, but I'm unsure how to
    // selectively enable secondary PIC IRQs...
    IO::out8(PIC0_CMD, 0x00);
    IO::out8(PIC1_CMD, 0x00);

    // HACK: Disable busmouse IRQ for now.
    disable(5);

    kprintf("PIC(i8259): cascading mode, vectors 0x%b-0x%b\n", IRQ_VECTOR_BASE, IRQ_VECTOR_BASE + 0x08);

#ifdef DEBUG_PIC
    initialized = true;
#endif
}

}