/*
Copyright (C) 2015-2019 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file LICENSE for details.
*/

#include "ioports.h"
#include "kernel/types.h"
#include "console.h"

#define PIC_ICW1 0x11
#define PIC_ICW4_MASTER 0x01
#define PIC_ICW4_SLAVE  0x05
#define PIC_ACK_SPECIFIC 0x60

static uint8_t pic_control[2] = { 0x20, 0xa0 };
static uint8_t pic_data[2] = { 0x21, 0xa1 };

void pic_init(int pic0base, int pic1base)
{
	outb(PIC_ICW1, pic_control[0]);
	outb(pic0base, pic_data[0]);
	outb(1 << 2, pic_data[0]);
	outb(PIC_ICW4_MASTER, pic_data[0]);
	outb(~(1 << 2), pic_data[0]);

	outb(PIC_ICW1, pic_control[1]);
	outb(pic1base, pic_data[1]);
	outb(2, pic_data[1]);
	outb(PIC_ICW4_SLAVE, pic_data[1]);
	outb(~0, pic_data[1]);

	printf("pic: ready\n");
}

void pic_enable(uint8_t irq)
{
	uint8_t mask;
	if(irq < 8) {
		mask = inb(pic_data[0]);
		mask = mask & ~(1 << irq);
		outb(mask, pic_data[0]);
	} else {
		irq -= 8;
		mask = inb(pic_data[1]);
		mask = mask & ~(1 << irq);
		outb(mask, pic_data[1]);
		pic_enable(2);
	}
}

void pic_disable(uint8_t irq)
{
	uint8_t mask;
	if(irq < 8) {
		mask = inb(pic_data[0]);
		mask = mask | (1 << irq);
		outb(mask, pic_data[0]);
	} else {
		irq -= 8;
		mask = inb(pic_data[1]);
		mask = mask | (1 << irq);
		outb(mask, pic_data[1]);
	}
}

void pic_acknowledge(uint8_t irq)
{
	if(irq >= 8) {
		outb(PIC_ACK_SPECIFIC + (irq - 8), pic_control[1]);
		outb(PIC_ACK_SPECIFIC + (2), pic_control[0]);
	} else {
		outb(PIC_ACK_SPECIFIC + irq, pic_control[0]);
	}
}
