proka_kernel/libs/time/
pit.rs1use lazy_static::lazy_static;
2use spin::Mutex;
3use x86_64::instructions::port::Port;
4
5const PIT_BASE_FREQ: u64 = 1_193_182;
6
7lazy_static! {
8 pub static ref PIT: Mutex<Pit> = Mutex::new(Pit::new());
9}
10
11pub struct Pit {
12 _channel0: Port<u8>,
13 _channel1: Port<u8>,
14 channel2: Port<u8>,
15 command: Port<u8>,
16 speaker_port: Port<u8>,
17}
18
19impl Pit {
20 const fn new() -> Self {
21 Pit {
22 _channel0: Port::new(0x40),
23 _channel1: Port::new(0x41),
24 channel2: Port::new(0x42),
25 command: Port::new(0x43),
26 speaker_port: Port::new(0x61),
27 }
28 }
29 pub fn sleep_blocking(&mut self, us: u64) {
30 let ticks = (us * PIT_BASE_FREQ) / 1_000_000;
34
35 let mut remaining_ticks = ticks;
36
37 while remaining_ticks > 0 {
38 let current_ticks = if remaining_ticks > 0xFFFF {
39 0xFFFF
40 } else {
41 remaining_ticks as u16
42 };
43
44 self.wait_ch2_ticks(current_ticks);
45 remaining_ticks -= current_ticks as u64;
46 }
47 }
48
49 pub fn read_count(&mut self) -> u16 {
51 unsafe {
52 self.command.write(0x80);
59
60 let low = self.channel2.read();
62 let high = self.channel2.read();
63
64 u16::from_le_bytes([low, high])
65 }
66 }
67
68 pub fn start_one_shot(&mut self, ticks: u16) {
71 unsafe {
72 let mut port61_val = self.speaker_port.read();
74 port61_val = (port61_val | 1) & !2;
77 self.speaker_port.write(port61_val);
78
79 self.command.write(0xB0);
86
87 self.channel2.write((ticks & 0xFF) as u8);
89 self.channel2.write((ticks >> 8) as u8);
90 }
91 }
92
93 fn wait_ch2_ticks(&mut self, ticks: u16) {
94 self.start_one_shot(ticks);
95
96 unsafe {
98 loop {
99 let status = self.speaker_port.read();
100 if (status & 0x20) != 0 {
101 break;
102 }
103 core::hint::spin_loop();
104 }
105 }
106 }
107}