/* Copyright (C) 2021,2022 fef . All rights reserved. */ /* * Most of the PIC management stuff is taken directly from the OSDev wiki: * */ #include #include #include #include #define ICW1_ICW4 0x01 /* ICW4 (not) needed */ #define ICW1_SINGLE 0x02 /* Single (cascade) mode */ #define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ #define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ #define ICW1_INIT 0x10 /* Initialization - required! */ #define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ #define ICW4_AUTO 0x02 /* Auto (normal) EOI */ #define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ #define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ #define ICW4_SFNM 0x10 /* Special fully nested (not) */ void arch_irq_init(void) { x86_set_intr_gate(X86_VECT_IRQ(0), _x86_isr_irq0); x86_set_intr_gate(X86_VECT_IRQ(1), _x86_isr_irq1); x86_set_intr_gate(X86_VECT_IRQ(3), _x86_isr_irq3); x86_set_intr_gate(X86_VECT_IRQ(4), _x86_isr_irq4); x86_set_intr_gate(X86_VECT_IRQ(5), _x86_isr_irq5); x86_set_intr_gate(X86_VECT_IRQ(6), _x86_isr_irq6); x86_set_intr_gate(X86_VECT_IRQ(7), _x86_isr_irq7); x86_set_intr_gate(X86_VECT_IRQ(8), _x86_isr_irq8); x86_set_intr_gate(X86_VECT_IRQ(9), _x86_isr_irq9); x86_set_intr_gate(X86_VECT_IRQ(10), _x86_isr_irq10); x86_set_intr_gate(X86_VECT_IRQ(11), _x86_isr_irq11); x86_set_intr_gate(X86_VECT_IRQ(12), _x86_isr_irq12); x86_set_intr_gate(X86_VECT_IRQ(13), _x86_isr_irq13); x86_set_intr_gate(X86_VECT_IRQ(14), _x86_isr_irq14); x86_set_intr_gate(X86_VECT_IRQ(15), _x86_isr_irq15); /* * disable interrupts to prevent IRQs from being fired * immediately after the initialization sequence is complete * (we need time to mask all IRQs again first) */ disable_intr(); /* begin initialization sequence in cascade mode */ x86_outb_wait(X86_PORT_PIC1_CMD, ICW1_INIT | ICW1_ICW4); x86_outb_wait(X86_PORT_PIC2_CMD, ICW1_INIT | ICW1_ICW4); /* tell PIC1 its offset into the vector table */ x86_outb_wait(X86_PORT_PIC1_DATA, X86_VECT_IRQ_BASE); /* tell PIC2 its offset into the vector table */ x86_outb_wait(X86_PORT_PIC2_DATA, X86_VECT_IRQ_BASE + 8); /* tell PIC1 that PIC2 is cascading into it on IRQ 2 */ x86_outb_wait(X86_PORT_PIC1_DATA, 1 << 2); /* tell PIC2 that it is the second controller in the cascade chain */ x86_outb_wait(X86_PORT_PIC2_DATA, 2); /* don't ask me what the fuck this does */ x86_outb_wait(X86_PORT_PIC1_DATA, ICW4_8086); x86_outb_wait(X86_PORT_PIC2_DATA, ICW4_8086); /* * The initialization sequence is finished now, meaning all IRQ masks * have been cleared (they are all enabled). Disable them again. */ x86_outb_wait(X86_PORT_PIC1_DATA, 0xff); x86_outb_wait(X86_PORT_PIC2_DATA, 0xff); /* it's safe to turn interrupts back on now */ enable_intr(); } void arch_irq_enable(unsigned int number) { u16 port; if (number >= 8) { port = X86_PORT_PIC2_DATA; number -= 8; } else { port = X86_PORT_PIC1_DATA; } u8 mask = x86_inb(port); mask &= ~(1 << number); x86_outb(port, mask); } void arch_irq_disable(unsigned int number) { u16 port; if (number >= 8) { port = X86_PORT_PIC2_DATA; number -= 8; } else { port = X86_PORT_PIC1_DATA; } u8 mask = x86_inb(port); mask |= (1 << number); x86_outb(port, mask); } void x86_irq_ack(unsigned int number) { if (number >= 8) x86_outb(X86_PORT_PIC2_CMD, 0x20); x86_outb(X86_PORT_PIC1_CMD, 0x20); }