1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! Hardware Timer
//!
//! Timer drivers for components that act as timers/clocks
//! This includes the High Precision Event Timer (HPET) and Programmable Interval Timer (PIT).

use alloc::sync::Arc;
use hpet::Hpet;
use pit::Pit;
use tracing::warn;

use crate::{acpi, cmdline, sync::spin::mutex::Mutex};

use super::ClockDevice;

mod hpet;
mod pit;

pub enum HardwareTimer {
    Hpet(Arc<Mutex<Hpet>>),
    Pit(Arc<Pit>),
}
impl HardwareTimer {
    pub fn init(hpet_table: Option<&acpi::tables::Hpet>) -> Arc<dyn ClockDevice> {
        Arc::new(match hpet_table {
            Some(hpet_table) if cmdline::cmdline().allow_hpet => {
                HardwareTimer::Hpet(hpet::init(hpet_table))
            }
            Some(_) => HardwareTimer::Pit(pit::init()),
            None => {
                warn!("HPET clock not found, falling back to PIT");
                HardwareTimer::Pit(pit::init())
            }
        })
    }
}

impl ClockDevice for HardwareTimer {
    fn name(&self) -> &'static str {
        match self {
            HardwareTimer::Hpet(t) => t.name(),
            HardwareTimer::Pit(t) => t.name(),
        }
    }

    fn get_time(&self) -> super::ClockTime {
        match self {
            HardwareTimer::Hpet(t) => t.get_time(),
            HardwareTimer::Pit(t) => t.get_time(),
        }
    }

    fn granularity(&self) -> u64 {
        match self {
            HardwareTimer::Hpet(t) => t.granularity(),
            HardwareTimer::Pit(t) => t.granularity(),
        }
    }

    fn require_calibration(&self) -> bool {
        match self {
            HardwareTimer::Hpet(t) => t.require_calibration(),
            HardwareTimer::Pit(t) => t.require_calibration(),
        }
    }

    fn rating(&self) -> u64 {
        match self {
            HardwareTimer::Hpet(t) => t.rating(),
            HardwareTimer::Pit(t) => t.rating(),
        }
    }
}