/*
* Copyright (c) 2012-2014 Richard Braun.
*
* 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
/*
* I/O ports.
*/
#define PIC_MASTER_CMD 0x20
#define PIC_MASTER_IMR 0x21
#define PIC_SLAVE_CMD 0xa0
#define PIC_SLAVE_IMR 0xa1
/*
* Register bits.
*/
#define PIC_ICW1_IC4 0x01
#define PIC_ICW1_INIT 0x10
#define PIC_ICW4_8086 0x01
#define PIC_OCW3_ISR 0x0b
#define PIC_EOI 0x20
/*
* Special interrupts.
*/
#define PIC_SLAVE_INTR 2
#define PIC_SPURIOUS_INTR 7
#define PIC_NR_INTRS 8
void __init
pic_setup(void)
{
/* ICW 1 - State that ICW 4 will be sent */
io_write_byte(PIC_MASTER_CMD, PIC_ICW1_INIT | PIC_ICW1_IC4);
io_write_byte(PIC_SLAVE_CMD, PIC_ICW1_INIT | PIC_ICW1_IC4);
/* ICW 2 */
io_write_byte(PIC_MASTER_IMR, TRAP_PIC_BASE);
io_write_byte(PIC_SLAVE_IMR, TRAP_PIC_BASE + PIC_NR_INTRS);
/* ICW 3 - Set up cascading */
io_write_byte(PIC_MASTER_IMR, 1 << PIC_SLAVE_INTR);
io_write_byte(PIC_SLAVE_IMR, PIC_SLAVE_INTR);
/* ICW 4 - Set 8086 mode */
io_write_byte(PIC_MASTER_IMR, PIC_ICW4_8086);
io_write_byte(PIC_SLAVE_IMR, PIC_ICW4_8086);
/* OCW 1 - Mask all interrupts */
io_write_byte(PIC_MASTER_IMR, 0xff);
io_write_byte(PIC_SLAVE_IMR, 0xff);
}
static void
pic_eoi(unsigned long intr)
{
if (intr >= PIC_NR_INTRS) {
io_write_byte(PIC_SLAVE_CMD, PIC_EOI);
}
io_write_byte(PIC_MASTER_CMD, PIC_EOI);
}
static uint8_t
pic_read_isr(uint16_t port)
{
io_write_byte(port, PIC_OCW3_ISR);
return io_read_byte(port);
}
void
pic_spurious_intr(struct trap_frame *frame)
{
unsigned long intr;
uint8_t isr;
intr = frame->vector - TRAP_PIC_BASE;
assert((intr == PIC_SPURIOUS_INTR)
|| (intr == (PIC_NR_INTRS + PIC_SPURIOUS_INTR)));
if (intr == PIC_SPURIOUS_INTR) {
isr = pic_read_isr(PIC_MASTER_CMD);
if (isr & (1 << PIC_SPURIOUS_INTR)) {
panic("pic: real interrupt %lu", intr);
}
} else {
isr = pic_read_isr(PIC_SLAVE_CMD);
if (isr & (1 << PIC_SPURIOUS_INTR)) {
panic("pic: real interrupt %lu", intr);
}
pic_eoi(PIC_SLAVE_INTR);
}
}