123 lines
2.9 KiB
C++
123 lines
2.9 KiB
C++
|
|
#include "drivers/pic.hpp"
|
|
|
|
namespace
|
|
{
|
|
inline constexpr std::uint8_t PIC_CMD_INIT = 0x10;
|
|
inline constexpr std::uint8_t PIC_CMD_READ_IRR = 0x0a;
|
|
inline constexpr std::uint8_t PIC_CMD_READ_ISR = 0x0b;
|
|
inline constexpr std::uint8_t PIC_INIT_WITH_ICW4 = 0x01;
|
|
inline constexpr std::uint8_t PIC_CFG_8086 = 0x01;
|
|
|
|
void picWriteCmd(std::uint16_t port, std::uint8_t command) noexcept
|
|
{
|
|
writePort8(port, command);
|
|
}
|
|
|
|
[[nodiscard]] std::uint8_t picReadResponse(std::uint8_t port) noexcept
|
|
{
|
|
return readPort8(port);
|
|
}
|
|
|
|
void picWriteData(std::uint16_t port, std::uint8_t data) noexcept
|
|
{
|
|
writePort8(port + 1, data);
|
|
}
|
|
|
|
[[nodiscard]] std::uint8_t picReadData(std::uint16_t port) noexcept
|
|
{
|
|
return readPort8(port + 1);
|
|
}
|
|
|
|
[[nodiscard]] std::uint16_t readPICIRQRegisters(std::uint8_t readCommand) noexcept
|
|
{
|
|
picWriteCmd(PORT_PIC1, readCommand);
|
|
picWriteCmd(PORT_PIC2, readCommand);
|
|
return (picReadResponse(PORT_PIC1) << 8) | picReadResponse(PORT_PIC2);
|
|
}
|
|
}
|
|
|
|
bool initPICs(std::uint8_t masterOffset, std::uint8_t slaveOffset) noexcept
|
|
{
|
|
if (!isValidPICOffset(masterOffset) || !isValidPICOffset(slaveOffset))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const uint8_t mask1 = picReadData(PORT_PIC1);
|
|
const uint8_t mask2 = picReadData(PORT_PIC2);
|
|
|
|
// ICW1 - init command
|
|
picWriteCmd(PORT_PIC1, PIC_CMD_INIT | PIC_INIT_WITH_ICW4);
|
|
ioWait();
|
|
picWriteCmd(PORT_PIC2, PIC_CMD_INIT | PIC_INIT_WITH_ICW4);
|
|
ioWait();
|
|
|
|
// ICW2 - offset
|
|
picWriteData(PORT_PIC1, masterOffset);
|
|
ioWait();
|
|
picWriteData(PORT_PIC2, slaveOffset);
|
|
ioWait();
|
|
|
|
// ICW3 - master/slave config
|
|
picWriteData(PORT_PIC1, (1 << 2)); // there is a slave at IRQ2
|
|
ioWait();
|
|
picWriteData(PORT_PIC2, 2); // you are slave no. 2
|
|
ioWait();
|
|
|
|
// ICW3 - additional config
|
|
picWriteData(PORT_PIC1, PIC_CFG_8086);
|
|
ioWait();
|
|
picWriteData(PORT_PIC2, PIC_CFG_8086);
|
|
ioWait();
|
|
|
|
// restore masks
|
|
picWriteData(PORT_PIC1, mask1);
|
|
picWriteData(PORT_PIC2, mask2);
|
|
|
|
return true;
|
|
}
|
|
|
|
__attribute__((no_caller_saved_registers))
|
|
void sendEndOfInterrupt(std::uint8_t irq) noexcept
|
|
{
|
|
if (irq >= 8) {
|
|
writePort8(PORT_PIC2, PIC_CMD_EOI);
|
|
}
|
|
writePort8(PORT_PIC1, PIC_CMD_EOI);
|
|
}
|
|
|
|
void maskIRQ(std::uint8_t irq) noexcept
|
|
{
|
|
std::uint16_t port = PORT_PIC1;
|
|
if (irq >= 8)
|
|
{
|
|
port = PORT_PIC2;
|
|
irq -= 8;
|
|
}
|
|
const std::uint8_t currentMask = picReadData(port);
|
|
picWriteData(port, currentMask | (1 << irq));
|
|
}
|
|
|
|
void unmaskIRQ(std::uint8_t irq) noexcept
|
|
{
|
|
std::uint16_t port = PORT_PIC1;
|
|
if (irq >= 8)
|
|
{
|
|
port = PORT_PIC2;
|
|
irq -= 8;
|
|
}
|
|
const std::uint8_t currentMask = picReadData(port);
|
|
picWriteData(port, currentMask & ~(1 << irq));
|
|
}
|
|
|
|
std::uint16_t readPICIRR() noexcept
|
|
{
|
|
return readPICIRQRegisters(PIC_CMD_READ_IRR);
|
|
}
|
|
|
|
std::uint16_t readPICISR() noexcept
|
|
{
|
|
return readPICIRQRegisters(PIC_CMD_READ_ISR);
|
|
}
|