You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

46 lines
1.2 KiB

use log::*;
use once::*;
use x86_64::instructions::port::Port;
pub fn init() {
assert_has_not_been_called!("pit::init must be called only once");
Pit::new(0x40).init(100);
info!("pit: init end");
}
struct Pit {
chan0: Port<u8>,
chan1: Port<u8>,
chan2: Port<u8>,
command: Port<u8>,
}
impl Pit {
const fn new(port: u16) -> Self {
Pit {
chan0: Port::new(port),
chan1: Port::new(port + 1),
chan2: Port::new(port + 2),
command: Port::new(port + 3),
}
}
pub fn init(&mut self, freq: u32) {
unsafe {
self.command.write(TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
let div = Pit::divisor(freq);
self.chan0.write((div & 0xFF) as u8);
self.chan0.write((div >> 8) as u8);
}
}
fn divisor(freq: u32) -> u16 {
let div = (TIMER_FREQ + freq / 2) / freq;
assert!(div < 0x10000);
div as u16
}
}
const TIMER_FREQ: u32 = 1193182;
const TIMER_SEL0: u8 = 0x00; // select counter 0
const TIMER_RATEGEN: u8 = 0x04; // mode 2, rate generator
const TIMER_16BIT: u8 = 0x30; // r/w counter 16 bits, LSB first