#![allow(dead_code)]
use crate::{
arch::{
kernel::IO_APIC,
timer::TIMER_FREQ,
x86::device::io_port::{IoPort, WriteOnlyAccess},
},
trap::IrqLine,
};
#[repr(u8)]
pub enum OperatingMode {
InterruptOnTerminalCount = 0b000,
OneShotHardwareRetriggerable = 0b001,
RateGenerator = 0b010,
SquareWaveGenerator = 0b011,
SoftwareTriggeredStrobe = 0b100,
HardwareTriggeredStrobe = 0b101,
}
#[repr(u8)]
enum AccessMode {
LatchCountValueCommand = 0b00,
LowByteOnly = 0b01,
HighByteOnly = 0b10,
LowAndHighByte = 0b11,
}
#[repr(u8)]
enum Channel {
Channel0 = 0b00,
Channel1 = 0b01,
Channel2 = 0b10,
ReadBackCommand = 0b11,
}
static CHANNEL0_PORT: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x40) };
#[allow(unused)]
static CHANNEL1_PORT: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x41) };
#[allow(unused)]
static CHANNEL2_PORT: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x42) };
static MODE_COMMAND_PORT: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x43) };
const TIMER_RATE: u32 = 1193182;
pub(crate) fn init(operating_mode: OperatingMode) {
MODE_COMMAND_PORT.write(
((operating_mode as u8) << 1)
| (AccessMode::LowAndHighByte as u8) << 4
| (Channel::Channel0 as u8) << 6,
);
const CYCLE: u32 = TIMER_RATE / TIMER_FREQ as u32;
CHANNEL0_PORT.write((CYCLE & 0xFF) as _);
CHANNEL0_PORT.write((CYCLE >> 8) as _);
}
pub(crate) fn enable_ioapic_line(irq: IrqLine) {
let mut io_apic = IO_APIC.get().unwrap().first().unwrap().lock();
debug_assert_eq!(io_apic.interrupt_base(), 0);
io_apic.enable(2, irq.clone()).unwrap();
}
pub(crate) fn disable_ioapic_line() {
let mut io_apic = IO_APIC.get().unwrap().first().unwrap().lock();
debug_assert_eq!(io_apic.interrupt_base(), 0);
io_apic.disable(2).unwrap();
}