mirror of
https://github.com/tailix/libkernaux.git
synced 2025-03-17 17:14:00 -04:00
Add a driver for Intel 8259-compatible PIC (#92)
This commit is contained in:
parent
c331e6dafd
commit
a71618b258
2 changed files with 181 additions and 2 deletions
|
@ -1,3 +1,15 @@
|
|||
/**
|
||||
* @brief A driver for Intel 8259-compatible programmable interrupt controller
|
||||
*
|
||||
* @details
|
||||
* This is not a driver for a random Intel 8259-compatible PIC, but only for a
|
||||
* typical configuration of it that can be found in most PCs.
|
||||
*
|
||||
* @see https://en.wikipedia.org/wiki/Intel_8259
|
||||
* @see https://wiki.osdev.org/8259_PIC
|
||||
* @see https://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf
|
||||
*/
|
||||
|
||||
#ifndef KERNAUX_INCLUDED_DRIVERS_INTEL_8259_PIC
|
||||
#define KERNAUX_INCLUDED_DRIVERS_INTEL_8259_PIC
|
||||
|
||||
|
@ -5,6 +17,39 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable PIC
|
||||
*/
|
||||
void kernaux_drivers_intel_8259_pic_enable_all();
|
||||
|
||||
/**
|
||||
* @brief Disable PIC
|
||||
*/
|
||||
void kernaux_drivers_intel_8259_pic_disable_all();
|
||||
|
||||
/**
|
||||
* @brief Enable single IRQ line
|
||||
*/
|
||||
void kernaux_drivers_intel_8259_pic_enable(unsigned char number);
|
||||
|
||||
/**
|
||||
* @brief Disable single IRQ line
|
||||
*/
|
||||
void kernaux_drivers_intel_8259_pic_disable(unsigned char number);
|
||||
|
||||
/**
|
||||
* @brief Remap PIC
|
||||
*/
|
||||
void kernaux_drivers_intel_8259_pic_remap(
|
||||
unsigned char new_master_start,
|
||||
unsigned char new_slave_start
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Signal end of interrupt
|
||||
*/
|
||||
void kernaux_drivers_intel_8259_pic_eoi(unsigned char number);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,141 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <kernaux/assert.h>
|
||||
#include <kernaux/drivers/intel_8259_pic.h>
|
||||
|
||||
__attribute__((unused))
|
||||
static const int foobar = 0;
|
||||
#ifdef ASM_I386
|
||||
#include <kernaux/asm/i386.h>
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define MASTER_COMMAND_PORT 0x20
|
||||
#define SLAVE_COMMAND_PORT 0xA0
|
||||
|
||||
#define MASTER_DATA_PORT 0x21
|
||||
#define SLAVE_DATA_PORT 0xA1
|
||||
|
||||
#define IRQS_COUNT 8
|
||||
#define IRQS_TOTAL 16
|
||||
|
||||
#undef AVAILABLE
|
||||
#define NOT_AVAILABLE_MSG "Intel 8259-compatible PIC is not available"
|
||||
#ifdef ASM_I386
|
||||
# define AVAILABLE
|
||||
# define inportb kernaux_asm_i386_inportb
|
||||
# define outportb kernaux_asm_i386_outportb
|
||||
#endif
|
||||
|
||||
static unsigned char master_start = 0;
|
||||
static unsigned char slave_start = 8;
|
||||
|
||||
void kernaux_drivers_intel_8259_pic_enable_all()
|
||||
{
|
||||
#ifndef AVAILABLE
|
||||
KERNAUX_PANIC(NOT_AVAILABLE_MSG);
|
||||
#else
|
||||
outportb(MASTER_DATA_PORT, 0);
|
||||
outportb(SLAVE_DATA_PORT, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void kernaux_drivers_intel_8259_pic_disable_all()
|
||||
{
|
||||
#ifndef AVAILABLE
|
||||
KERNAUX_PANIC(NOT_AVAILABLE_MSG);
|
||||
#else
|
||||
outportb(MASTER_DATA_PORT, 0xFF);
|
||||
outportb(SLAVE_DATA_PORT, 0xFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
void kernaux_drivers_intel_8259_pic_enable(const unsigned char number)
|
||||
{
|
||||
#ifndef AVAILABLE
|
||||
(void)number;
|
||||
KERNAUX_PANIC(NOT_AVAILABLE_MSG);
|
||||
#else
|
||||
KERNAUX_ASSERT(number < IRQS_TOTAL);
|
||||
|
||||
if (number < IRQS_COUNT) {
|
||||
const uint8_t mask = inportb(MASTER_DATA_PORT);
|
||||
outportb(MASTER_DATA_PORT, mask & ~(1 << number));
|
||||
} else {
|
||||
const uint8_t mask = inportb(SLAVE_DATA_PORT);
|
||||
outportb(SLAVE_DATA_PORT, mask & ~(1 << (number - IRQS_COUNT)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void kernaux_drivers_intel_8259_pic_disable(const unsigned char number)
|
||||
{
|
||||
#ifndef AVAILABLE
|
||||
(void)number;
|
||||
KERNAUX_PANIC(NOT_AVAILABLE_MSG);
|
||||
#else
|
||||
KERNAUX_ASSERT(number < IRQS_TOTAL);
|
||||
|
||||
if (number < IRQS_COUNT) {
|
||||
const uint8_t mask = inportb(MASTER_DATA_PORT);
|
||||
outportb(MASTER_DATA_PORT, mask | (1 << number));
|
||||
} else {
|
||||
const uint8_t mask = inportb(SLAVE_DATA_PORT);
|
||||
outportb(SLAVE_DATA_PORT, mask | (1 << (number - IRQS_COUNT)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void kernaux_drivers_intel_8259_pic_remap(
|
||||
const unsigned char new_master_start,
|
||||
const unsigned char new_slave_start
|
||||
) {
|
||||
#ifndef AVAILABLE
|
||||
KERNAUX_PANIC(NOT_AVAILABLE_MSG);
|
||||
#else
|
||||
master_start = new_master_start;
|
||||
slave_start = new_slave_start;
|
||||
|
||||
// Save masks
|
||||
const uint8_t master_mask = inportb(MASTER_DATA_PORT);
|
||||
const uint8_t slave_mask = inportb(SLAVE_DATA_PORT);
|
||||
|
||||
// Start the initialization sequence
|
||||
outportb(MASTER_COMMAND_PORT, 0x11);
|
||||
outportb(SLAVE_COMMAND_PORT, 0x11);
|
||||
|
||||
// Set IRQ vectors
|
||||
outportb(MASTER_DATA_PORT, new_master_start);
|
||||
outportb(SLAVE_DATA_PORT, new_slave_start);
|
||||
|
||||
// Connect master and slave with each other
|
||||
outportb(MASTER_DATA_PORT, 0x04);
|
||||
outportb(SLAVE_DATA_PORT, 0x02);
|
||||
|
||||
// 8086/88 (MCS-80/85) mode
|
||||
outportb(MASTER_DATA_PORT, 0x01);
|
||||
outportb(SLAVE_DATA_PORT, 0x01);
|
||||
|
||||
// Restore masks
|
||||
outportb(MASTER_DATA_PORT, master_mask);
|
||||
outportb(SLAVE_DATA_PORT, slave_mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
void kernaux_drivers_intel_8259_pic_eoi(const unsigned char number)
|
||||
{
|
||||
#ifndef AVAILABLE
|
||||
KERNAUX_PANIC(NOT_AVAILABLE_MSG);
|
||||
#else
|
||||
KERNAUX_ASSERT(number < IRQS_TOTAL);
|
||||
|
||||
const bool to_slave =
|
||||
number >= slave_start && number < slave_start + IRQS_COUNT;
|
||||
const bool to_master = to_slave ||
|
||||
(number >= master_start && number < master_start + IRQS_COUNT);
|
||||
|
||||
if (to_slave) outportb(SLAVE_COMMAND_PORT, 0x20);
|
||||
if (to_master) outportb(MASTER_COMMAND_PORT, 0x20);
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue