#include "os.h"
#include "task.h"

/* Own ISR pointing to individual IRQ handler instead of the regular 'fault_handler' function */
extern void irq0();  extern void irq1();  extern void irq2();  extern void irq3();
extern void irq4();  extern void irq5();  extern void irq6();  extern void irq7();
extern void irq8();  extern void irq9();  extern void irq10(); extern void irq11();
extern void irq12(); extern void irq13(); extern void irq14(); extern void irq15();

/* Array of function pointers handling custom IRQ handlers for a given IRQ */
//void* irq_routines[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
void* irq_routines[128];

/* Implement a custom IRQ handler for the given IRQ */
void irq_install_handler(int irq, void (*handler)(struct regs* r)) {irq_routines[irq] = handler;}

/* Clear the custom IRQ handler */
void irq_uninstall_handler(int irq) {irq_routines[irq] = 0;}

/* Remap: IRQ0 to IRQ15 have to be remapped to IDT entries 32 to 47 */
void irq_remap()
{
    // starts the initialization sequence
    outportb(0x20, 0x11); outportb(0xA0, 0x11);

    // define the PIC vectors
    outportb(0x21, 0x20); // Set offset of Master PIC to 0x20 (32): Entry 32-39
    outportb(0xA1, 0x28); // Set offset of Slave  PIC to 0x28 (40): Entry 40-47

    // continue initialization sequence
    outportb(0x21, 0x04); outportb(0xA1, 0x02);
    outportb(0x21, 0x01); outportb(0xA1, 0x01);
    outportb(0x21, 0x00); outportb(0xA1, 0x00);
}

/* After remap of the interrupt controllers the appropriate ISRs are connected to the correct entries in the IDT. */
void irq_install()
{
    irq_remap();
    idt_set_gate(32, (unsigned) irq0,  0x08, 0x8E);   idt_set_gate(33, (unsigned) irq1,  0x08, 0x8E);
    idt_set_gate(34, (unsigned) irq2,  0x08, 0x8E);   idt_set_gate(35, (unsigned) irq3,  0x08, 0x8E);
    idt_set_gate(36, (unsigned) irq4,  0x08, 0x8E);   idt_set_gate(37, (unsigned) irq5,  0x08, 0x8E);
    idt_set_gate(38, (unsigned) irq6,  0x08, 0x8E);   idt_set_gate(39, (unsigned) irq7,  0x08, 0x8E);
    idt_set_gate(40, (unsigned) irq8,  0x08, 0x8E);   idt_set_gate(41, (unsigned) irq9,  0x08, 0x8E);
    idt_set_gate(42, (unsigned) irq10, 0x08, 0x8E);   idt_set_gate(43, (unsigned) irq11, 0x08, 0x8E);
    idt_set_gate(44, (unsigned) irq12, 0x08, 0x8E);   idt_set_gate(45, (unsigned) irq13, 0x08, 0x8E);
    idt_set_gate(46, (unsigned) irq14, 0x08, 0x8E);   idt_set_gate(47, (unsigned) irq15, 0x08, 0x8E);
}

ULONG irq_handler(ULONG esp)
{
    ULONG retVal;
    struct regs* r = (struct regs*)esp;

    if(!pODA->ts_flag)
        retVal = esp;
    else
        retVal = task_switch(esp); //new task's esp

    void (*handler)(struct regs* r);
    handler = irq_routines[r->int_no - 32];
    if(handler) { handler(r); }

    if(r->int_no >= 40) { outportb(0xA0, 0x20); }
    outportb(0x20, 0x20);

    return retVal;
}
