#include "pic.h"
#include "io.h"
#include "logger.h"

#define PIC1_COMMAND 0x20
#define PIC1_DATA    0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA    0xA1

#define ICW1_INIT    0x10 // Инициализация
#define ICW1_IC4     0x01 // Будет ICW4
#define ICW4_8086    0x01 // Режим 8086/8186

void pic_remap(uint8_t master_offset, uint8_t slave_offset) {
    log_info(LOG_DETAIL, "Remapping PIC...");

    // Сохраняем текущие маски прерываний (какое железо сейчас отключено)
    uint8_t a1 = inb(PIC1_DATA);
    uint8_t a2 = inb(PIC2_DATA);

    // Свисток к началу инициализации (ICW1)
    outb(PIC1_COMMAND, ICW1_INIT | ICW1_IC4);
    io_wait();
    outb(PIC2_COMMAND, ICW1_INIT | ICW1_IC4);
    io_wait();

    // Задаем новые смещения векторов (ICW2)
    outb(PIC1_DATA, master_offset); // Master IRQ 0-7 -> вешаем на master_offset (32)
    io_wait();
    outb(PIC2_DATA, slave_offset);  // Slave IRQ 8-15 -> вешаем на slave_offset (40)
    io_wait();

    // Связываем Master и Slave между собой (ICW3)
    outb(PIC1_DATA, 4); // Сообщаем Master, что Slave сидит на IRQ2 (00000100б = 4)
    io_wait();
    outb(PIC2_DATA, 2); // Сообщаем Slave его каскадный ID (2)
    io_wait();

    // Включаем режим 8086 (ICW4)
    outb(PIC1_DATA, ICW4_8086);
    io_wait();
    outb(PIC2_DATA, ICW4_8086);
    io_wait();

    // Восстанавливаем сохраненные маски
    outb(PIC1_DATA, a1);
    outb(PIC2_DATA, a2);
    
    log_info(LOG_DETAIL, "PIC remapped");
}

// Запретить прерывание от конкретного IRQ
void pic_set_mask(uint8_t irq_line) {
    uint16_t port;
    if (irq_line < 8) {
        port = PIC1_DATA;
    } else {
        port = PIC2_DATA;
        irq_line -= 8;
    }
    uint8_t value = inb(port) | (1 << irq_line);
    outb(port, value);
}

// Разрешить прерывание от конкретного IRQ
void pic_clear_mask(uint8_t irq_line) {
    uint16_t port;
    if (irq_line < 8) {
        port = PIC1_DATA;
    } else {
        port = PIC2_DATA;
        irq_line -= 8;
    }
    uint8_t value = inb(port) & ~(1 << irq_line);
    outb(port, value);
}
