+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
#include <stdio.h>
#include "intr.h"
#include "desc.h"
#define OCW2_EOI (1 << 5)
-static void init_pic(int offset);
+void init_pic(void);
static void gate_desc(desc_t *desc, uint16_t sel, uint32_t addr, int dpl, int type);
/* defined in intr_asm.S */
void set_idt(uint32_t addr, uint16_t limit);
void intr_entry_default(void);
+void irq7_entry_check_spurious(void);
+void irq15_entry_check_spurious(void);
/* the IDT (interrupt descriptor table) */
static desc_t idt[256] __attribute__((aligned(8)));
*/
#include "intrtab.h"
+ /* change irq7 and irq15 to special entry points which first
+ * make sure we didn't get a spurious interrupt before proceeding
+ */
+ set_intr_entry(IRQ_TO_INTR(7), irq7_entry_check_spurious);
+ set_intr_entry(IRQ_TO_INTR(15), irq15_entry_check_spurious);
+
/* initialize the programmable interrupt controller
* setting up the maping of IRQs [0, 15] to interrupts [32, 47]
*/
- init_pic(IRQ_OFFSET);
+ init_pic();
eoi_pending = 0;
}
/* set an interrupt handler function for a particular interrupt */
void interrupt(int intr_num, intr_func_t func)
{
+ int iflag = get_intr_flag();
+ disable_intr();
intr_func[intr_num] = func;
+ set_intr_flag(iflag);
}
/* this function is called from all interrupt entry points
}
}
-static void init_pic(int offset)
+void init_pic(void)
{
/* send ICW1 saying we'll follow with ICW4 later on */
outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC1_CMD);
outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC2_CMD);
/* send ICW2 with IRQ remapping */
- outb(offset, PIC1_DATA);
- outb(offset + 8, PIC2_DATA);
+ outb(IRQ_OFFSET, PIC1_DATA);
+ outb(IRQ_OFFSET + 8, PIC2_DATA);
/* send ICW3 to setup the master/slave relationship */
/* ... set bit3 = 3rd interrupt input has a slave */
outb(4, PIC1_DATA);
gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, dpl, type);
}
+void set_pic_mask(int pic, unsigned char mask)
+{
+ outb(mask, pic > 0 ? PIC2_DATA : PIC1_DATA);
+}
+
+unsigned char get_pic_mask(int pic)
+{
+ return inb(pic > 0 ? PIC2_DATA : PIC1_DATA);
+}
+
+void mask_irq(int irq)
+{
+ int port;
+ unsigned char mask;
+
+ if(irq < 8) {
+ port = PIC1_DATA;
+ } else {
+ port = PIC2_DATA;
+ irq -= 8;
+ }
+
+ mask = inb(port) | (1 << irq);
+ outb(mask, port);
+}
+
+void unmask_irq(int irq)
+{
+ int port;
+ unsigned char mask;
+
+ if(irq < 8) {
+ port = PIC1_DATA;
+ } else {
+ port = PIC2_DATA;
+ irq -= 8;
+ }
+
+ mask = inb(port) & ~(1 << irq);
+ outb(mask, port);
+}
+
+
void end_of_irq(int irq)
{
int intr_state = get_intr_flag();