Files
MentOS/mentos/src/hardware/pic8259.c
T
2023-01-19 10:09:52 -05:00

165 lines
4.6 KiB
C

/// @file pic8259.c
/// @brief pic8259 definitions.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
// Setup the logging for this file (do this before any other include).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[PIC ]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#include "hardware/pic8259.h"
#include "io/port_io.h"
#include "stddef.h"
/// End-of-interrupt command code.
#define EOI 0x20
/// IO base address for master PIC.
#define MASTER_PORT_COMMAND 0x20
/// I/O address for data to master.
#define MASTER_PORT_DATA (MASTER_PORT_COMMAND + 1)
/// IO base address for slave PIC.
#define SLAVE_PORT_COMMAND 0xA0
/// I/O address for data to slave.
#define SLAVE_PORT_DATA (SLAVE_PORT_COMMAND + 1)
/// ICW4 (not) needed.
#define ICW1_ICW4 0x01
/// Single (cascade) mode.
#define ICW1_SINGLE 0x02
/// Call address interval 4 (8).
#define ICW1_INTERVAL4 0x04
/// Level triggered (edge) mode.
#define ICW1_LEVEL 0x08
/// Initialization - required.
#define ICW1_INIT 0x10
/// 8086/88 (MCS-80/85) mode
#define ICW4_8086 0x01
/// Auto (normal) EOI.
#define ICW4_AUTO 0x02
/// Buffered mode/slave.
#define ICW4_BUF_SLAVE 0x08
/// Buffered mode/master.
#define ICW4_BUF_MASTER 0x0C
/// Special fully nested (not).
#define ICW4_SFNM 0x10
/// OCW3 irq ready next CMD read.
#define PIC_READ_IRR 0x0A
/// OCW3 irq service next CMD read.
#define PIC_READ_ISR 0x0B
/// The current mask of the master.
static byte_t master_cur_mask;
/// The current mask of the slave.
static byte_t slave_cur_mask;
void pic8259_init_irq()
{
// Set the masks for the master and slave.
master_cur_mask = 0xFF;
slave_cur_mask = 0xFF;
// Starts the initialization sequence (in cascade mode).
outportb(MASTER_PORT_COMMAND, ICW1_INIT + ICW1_ICW4);
outportb(SLAVE_PORT_COMMAND, ICW1_INIT + ICW1_ICW4);
// ICW2: Master PIC vector offset.
outportb(MASTER_PORT_DATA, 0x20);
// ICW2: Slave PIC vector offset.
outportb(SLAVE_PORT_DATA, 0x28);
// ICW3: Tell Master PIC that there is a slave PIC at IRQ2 (0000 0100).
outportb(MASTER_PORT_DATA, 4);
// ICW3: Tell Slave PIC its cascade identity (0000 0010).
outportb(SLAVE_PORT_DATA, 2);
outportb(MASTER_PORT_DATA, ICW4_8086);
outportb(SLAVE_PORT_DATA, ICW4_8086);
// Restore saved masks.
outportb(MASTER_PORT_DATA, master_cur_mask);
outportb(SLAVE_PORT_DATA, slave_cur_mask);
pic8259_irq_enable(IRQ_TO_SLAVE_PIC);
outportb(0xFF, MASTER_PORT_DATA);
outportb(0xFF, SLAVE_PORT_DATA);
}
int pic8259_irq_enable(uint32_t irq)
{
if (irq >= IRQ_NUM) {
return -1;
}
byte_t cur_mask;
byte_t new_mask;
if (irq < 8) {
new_mask = ~(1 << irq);
cur_mask = inportb(MASTER_PORT_DATA);
outportb(MASTER_PORT_DATA, (new_mask & cur_mask));
master_cur_mask = (new_mask & cur_mask);
} else {
irq -= 8;
new_mask = ~(1 << irq);
cur_mask = inportb(SLAVE_PORT_DATA);
outportb(SLAVE_PORT_DATA, (new_mask & cur_mask));
slave_cur_mask = (new_mask & cur_mask);
}
return 0;
}
int pic8259_irq_disable(uint32_t irq)
{
if (irq >= IRQ_NUM) {
return -1;
}
uint8_t cur_mask;
if (irq < 8) {
cur_mask = inportb(MASTER_PORT_DATA);
cur_mask |= (1 << irq);
outportb(MASTER_PORT_DATA, cur_mask & 0xFF);
} else {
irq = irq - 8;
cur_mask = inportb(SLAVE_PORT_DATA);
cur_mask |= (1 << irq);
outportb(SLAVE_PORT_DATA, cur_mask & 0xFF);
}
return 0;
}
void pic8259_send_eoi(uint32_t irq)
{
// Perhaps the most common command issued to the PIC chips is the end of
// interrupt (EOI) command (code 0x20). This is issued to the PIC chips
// at the end of an IRQ-based interrupt routine. If the IRQ came from the
// Master PIC, it is sufficient to issue this command only to the Master
// PIC; however if the IRQ came from the Slave PIC, it is necessary to
// issue the command to both PIC chips.
if (irq >= 8) {
outportb(SLAVE_PORT_COMMAND, EOI);
}
outportb(MASTER_PORT_COMMAND, EOI);
}
/*
* int pic8259_irq_get_current()
* {
* outportb(MASTER_PORT_COMMAND, PIC_READ_ISR);
* uint8_t cur_irq = inportb(MASTER_PORT_COMMAND);
*
* if (cur_irq == 4)
* {
* outportb(SLAVE_PORT_COMMAND, PIC_READ_ISR);
* cur_irq = inportb(SLAVE_PORT_COMMAND);
*
* return 8 + find_first_bit(cur_irq);
* }
*
* return find_first_bit(cur_irq);
* }
*/