aboutsummaryrefslogtreecommitdiff
path: root/src/utils/pic.c
blob: 4459f0dff6fa48f4410875a3112815b5b1253abc (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
#include "pic.h"
#include "asm.h"
#include "mem.h"

struct IDT_REGISTER IDTR={
    100*8,
    0x0
};

/// Bridge between IDT and functions call
asm (
"PIC_IRQ_DEFAULT:"
    "movb $0x20, %al      \n\t"
    "outb %al, $0x20      \n\t"
    "iret                 \n\t"
"PIC_IRQ_PRINT:           \n\t"
    "call _8042_keypress  \n\t"
    "movb $0x20, %al      \n\t"
    "outb %al, $0x20      \n\t"
    "iret                 \n\t"
);

extern u32 PIC_IRQ_DEFAULT,PIC_IRQ_PRINT;

void pic_enable_interrupt(){
    // Map first default 32 entries 
    for(int i=0;i<100;i++){
        pic_add_idt_entry((IDT_ENTRY){0x08,(u32)&PIC_IRQ_DEFAULT,IDT_TYPE_1},i);
        if(i==32)
            pic_add_idt_entry((IDT_ENTRY){0x08,(u32)&PIC_IRQ_PRINT,IDT_TYPE_1},i);
    }

    // Now configure 8952A

    // ICW1: Initialisation
    outbj(0x20,0x11); // Master
    outbj(0xA0,0x11); // Slave

    // ICW2: Map IRQ index to entry into the IDT
    outbj(0x21,0x20); // Start interrupt at offset 0x20 in IDT (index 32)
    outbj(0xA1,0x70); // Start interrupt at offset 0x50 in IDT (index 80)

    // ICW3: Indicate the connection between master and slave
    outbj(0x21,0x02); // Slave connected to pin 2
    outbj(0xA1,0x01); // Indicate pin id to the slave (2-1)

    // ICW4: Operating mode
    outbj(0x21,0x01); // Default operating mode
    outbj(0xA1,0x01); // Default operating mode

    asm("lidtl (IDTR)");
    asm("sti");
}

void pic_add_idt_entry(IDT_ENTRY entry, int id){
    int descriptor[2];
    descriptor[0]=entry.offset & 0xFFFF | entry.segment << 16;
    descriptor[1]=entry.type & 0xFFFF | entry.offset & 0xFFFF0000;

    memcpy((void*)descriptor, (void *)(IDTR.base+(id*8)),8);
}