mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 11:53:24 +00:00
119 lines
3.1 KiB
Rust
119 lines
3.1 KiB
Rust
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
#![expect(dead_code)]
|
|
|
|
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering::Relaxed};
|
|
|
|
use log::info;
|
|
|
|
use crate::{
|
|
arch::device::io_port::WriteOnlyAccess,
|
|
io::{sensitive_io_port, IoPort},
|
|
trap::IrqLine,
|
|
};
|
|
|
|
sensitive_io_port! {
|
|
unsafe{
|
|
static MASTER_CMD: IoPort<u8, WriteOnlyAccess> = IoPort::new(0x20);
|
|
static MASTER_DATA: IoPort<u8, WriteOnlyAccess> = IoPort::new(0x21);
|
|
static SLAVE_CMD: IoPort<u8, WriteOnlyAccess> = IoPort::new(0xA0);
|
|
static SLAVE_DATA: IoPort<u8, WriteOnlyAccess> = IoPort::new(0xA1);
|
|
}
|
|
}
|
|
|
|
const IRQ_OFFSET: u8 = 0x20;
|
|
|
|
static MASK_MASTER: AtomicU8 = AtomicU8::new(0x00);
|
|
static MASK_SLAVE: AtomicU8 = AtomicU8::new(0x00);
|
|
static CHANGE_LOCK: AtomicBool = AtomicBool::new(false);
|
|
|
|
/// Initializes the PIC device
|
|
pub fn init() {
|
|
if CHANGE_LOCK.load(Relaxed) {
|
|
return;
|
|
}
|
|
let master_mask = !(MASK_MASTER.load(Relaxed));
|
|
let slave_mask = !(MASK_SLAVE.load(Relaxed));
|
|
info!(
|
|
"PIC init, master mask:{:x} slave_mask:{:x}",
|
|
master_mask, slave_mask
|
|
);
|
|
set_mask(master_mask, slave_mask);
|
|
}
|
|
|
|
/// Allocates irq, for example, if timer need IRQ0, it will return IrqAllocateHandle with irq num: IRQ_OFFSET+0
|
|
pub fn allocate_irq(index: u8) -> Option<IrqLine> {
|
|
if index >= 16 {
|
|
return None;
|
|
}
|
|
if let Ok(irq) = IrqLine::alloc_specific(IRQ_OFFSET + index) {
|
|
if index >= 8 {
|
|
MASK_SLAVE.fetch_or(1 << (index - 8), Relaxed);
|
|
} else {
|
|
MASK_MASTER.fetch_or(1 << (index), Relaxed);
|
|
}
|
|
Some(irq)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Enables the PIC device, this function will permanent enable all the interrupts
|
|
#[inline]
|
|
pub fn enable() {
|
|
CHANGE_LOCK.store(true, Relaxed);
|
|
set_mask(0, 0);
|
|
}
|
|
|
|
/// Disables the PIC device, this function will permanent disable all the interrupts
|
|
/// the interrupts mask may not exists after calling init function
|
|
#[inline]
|
|
pub fn disable() {
|
|
CHANGE_LOCK.store(true, Relaxed);
|
|
set_mask(0xFF, 0xFF);
|
|
}
|
|
|
|
/// Enables the PIC device, this function will allow all the interrupts
|
|
/// the interrupts mask may not exists after calling init function
|
|
#[inline]
|
|
pub fn enable_temp() {
|
|
set_mask(0, 0);
|
|
}
|
|
|
|
/// Disables the PIC device, this function will disable all the interrupts
|
|
/// the interrupts mask may not exists after calling init function
|
|
#[inline]
|
|
pub fn disable_temp() {
|
|
set_mask(0xFF, 0xFF);
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_mask(master_mask: u8, slave_mask: u8) {
|
|
// Start initialization
|
|
MASTER_CMD.write(0x11);
|
|
SLAVE_CMD.write(0x11);
|
|
|
|
// Set offsets
|
|
// map master PIC vector 0x00~0x07 to 0x20~0x27 IRQ number
|
|
MASTER_DATA.write(IRQ_OFFSET);
|
|
// map slave PIC vector 0x00~0x07 to 0x28~0x2f IRQ number
|
|
SLAVE_DATA.write(IRQ_OFFSET + 0x08);
|
|
|
|
// Set up cascade, there is slave at IRQ2
|
|
MASTER_DATA.write(4);
|
|
SLAVE_DATA.write(2);
|
|
|
|
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
|
|
MASTER_DATA.write(1);
|
|
SLAVE_DATA.write(1);
|
|
|
|
// mask interrupts
|
|
MASTER_DATA.write(master_mask);
|
|
SLAVE_DATA.write(slave_mask);
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn ack() {
|
|
MASTER_CMD.write(0x20);
|
|
}
|