kernel/src/pit.rs

55 lines
1.8 KiB
Rust

use crate::{
interrupts::{self, EoiGuard},
println, TASKING,
};
use spin::Mutex;
use x86_64::instructions::port::{Port, PortWriteOnly};
static DATA: Mutex<Port<u8>> = Mutex::new(Port::new(0x40));
static CMD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x43));
const MAX_FREQ: u32 = 1_193_180;
pub fn init(mut freq: u32) {
assert_ne!(freq, 0);
#[expect(
clippy::unwrap_used,
reason = "register_handler requires the interrupt number to be less than 16, which it is."
)]
interrupts::register_handler(0, handler).unwrap();
#[expect(clippy::arithmetic_side_effects, reason = "freq has been checked to not be 0")]
let mut div = MAX_FREQ / freq;
if div > 65535 {
println!("[PIT] Frequency of {}Hz too slow, min freq is 18 Hz", freq);
div = 65535;
freq = 18;
} else if div == 0 {
println!("[PIT] Frequency of {}Hz too fast, max freq is {} Hz", freq, MAX_FREQ);
div = 1;
freq = MAX_FREQ;
}
#[expect(
clippy::unwrap_used,
reason = "div has been checked to be in u16 range above, so this cannot panic"
)]
let div_bytes = u16::try_from(div).unwrap().to_le_bytes();
println!("[PIT] Setting PIT to {}Hz with divisor of {}", freq, div);
// Command breakdown (MSB to LSB):
// 00 - Channel 0
// 11 - lobyte/hibyte access mode - set both bytes in one command
// 011 - Mode 3, sqaure wave generator at frequency MAX_FREQ/div, generates interrupts at that
// frequency
// 0 - binary mode, always used
unsafe { CMD.lock().write(0b0011_0110_u8) };
unsafe { DATA.lock().write(div_bytes[0]) };
unsafe { DATA.lock().write(div_bytes[1]) };
}
fn handler(_irq: u8, eoi_guard: EoiGuard) {
drop(eoi_guard);
if TASKING.ok_to_yield() {
TASKING.task_yield();
}
}