mod apic;
mod hpet;
pub(crate) mod pit;
use core::sync::atomic::Ordering;
use spin::Once;
use self::apic::APIC_TIMER_CALLBACK;
use crate::{
arch::x86::kernel,
timer::INTERRUPT_CALLBACKS,
trap::{self, IrqLine, TrapFrame},
};
pub const TIMER_FREQ: u64 = 1000;
static TIMER_IRQ: Once<IrqLine> = Once::new();
pub(super) fn init() {
const PIT_MODE_TIMER_IRQ_NUM: u8 = 32;
let mut timer_irq = if kernel::apic::exists() {
apic::init()
} else {
pit::init(pit::OperatingMode::SquareWaveGenerator);
IrqLine::alloc_specific(PIT_MODE_TIMER_IRQ_NUM).unwrap()
};
timer_irq.on_active(timer_callback);
TIMER_IRQ.call_once(|| timer_irq);
}
fn timer_callback(_: &TrapFrame) {
crate::timer::jiffies::ELAPSED.fetch_add(1, Ordering::SeqCst);
let irq_guard = trap::disable_local();
let callbacks_guard = INTERRUPT_CALLBACKS.get_with(&irq_guard);
for callback in callbacks_guard.borrow().iter() {
(callback)();
}
drop(callbacks_guard);
if APIC_TIMER_CALLBACK.is_completed() {
APIC_TIMER_CALLBACK.get().unwrap().call(());
}
}