use crate::{ interrupts::{self, EoiGuard}, println, TASKING, }; use spin::Mutex; use x86_64::instructions::port::{Port, PortWriteOnly}; static DATA: Mutex> = Mutex::new(Port::new(0x40)); static CMD: Mutex> = 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(); } }