+#include <stdint.h>
+
+#include "kernel.h"
+
+#include "ioport.h"
+
+#include "pic.h"
+#include "interrupt.h"
+
+/* ioports */
+#define MCMD 0x20
+#define SCMD 0xA0
+#define MDATA 0x21
+#define SDATA 0xA1
+
+#define IRR 0x0A
+#define ISR 0x0B
+
+#define EOI 0x20
+#define ICW1_ICW4 0x01
+#define CMD_INIT 0x10
+#define MODE_8086 0x01
+
+static uint16_t readregister(uint8_t ocw3) {
+ outport8(MCMD, ocw3);
+ outport8(SCMD, ocw3);
+ return inport8(MCMD) | inport8(SCMD) << 8;
+}
+
+static uint16_t readirr() {
+ return readregister(IRR);
+}
+
+static uint16_t readisr() {
+ return readregister(ISR);
+}
+
+static void reprogram() {
+ outport8(MCMD, CMD_INIT | ICW1_ICW4);
+ outport8(SCMD, CMD_INIT | ICW1_ICW4);
+ outport8(MDATA, IRQ0);
+ outport8(SDATA, IRQ8);
+ outport8(MDATA, 0x04); /* Slave PIC at IRQ2 */
+ outport8(SDATA, 0x02); /* Cascade Identity */
+ outport8(MDATA, MODE_8086);
+ outport8(SDATA, MODE_8086);
+ /* masks */
+ outport8(MDATA, 0);
+ outport8(SDATA, 0);
+}
+
+static void deprogram() {
+ outport8(MCMD, CMD_INIT | ICW1_ICW4);
+ outport8(SCMD, CMD_INIT | ICW1_ICW4);
+ outport8(MDATA, 0x08);
+ outport8(SDATA, 0x70);
+ outport8(MDATA, 0x04); /* Slave PIC at IRQ2 */
+ outport8(SDATA, 0x02); /* Cascade Identity */
+ outport8(MDATA, MODE_8086);
+ outport8(SDATA, MODE_8086);
+ outport8(MDATA, 0);
+ outport8(SDATA, 0);
+}
+
+static void sendmastereoi() {
+ outport8(MCMD, EOI);
+}
+
+static void sendslaveeoi() {
+ outport8(SCMD, EOI);
+}
+
+static void sendeoi(unsigned int irq) {
+ if (irq >= 8) {
+ sendslaveeoi();
+ }
+ sendmastereoi();
+}
+
+struct pic pic;
+
+void pic_init() {
+ pic.eoi = sendeoi;
+ pic.mastereoi = sendmastereoi;
+ pic.readirr = readirr;
+ pic.readisr = readisr;
+ pic.reprogram = reprogram;
+ pic.deprogram = deprogram;
+}