1 use crate::{
2     arch::interrupt::{cli, sti},
3     include::bindings::bindings::{io_in8, io_out8},
4     syscall::SystemError,
5 };
6 
7 pub struct RtcTime {
8     pub second: i32,
9     pub minute: i32,
10     pub hour: i32,
11     pub day: i32,
12     pub month: i32,
13     pub year: i32,
14 }
15 
16 impl Default for RtcTime {
default() -> Self17     fn default() -> Self {
18         Self {
19             second: (0),
20             minute: (0),
21             hour: (0),
22             day: (0),
23             month: (0),
24             year: (0),
25         }
26     }
27 }
28 
29 impl RtcTime {
30     ///@brief 从主板cmos中获取时间
31     ///
32     ///@param self time结构体
33     ///@return int 成功则为0
get(&mut self) -> Result<i32, SystemError>34     pub fn get(&mut self) -> Result<i32, SystemError> {
35         // 为防止中断请求打断该过程,需要先关中断
36         cli();
37         //0x0B
38         let status_register_b: u8 = read_cmos(0x0B); // 读取状态寄存器B
39         let is_24h: bool = if (status_register_b & 0x02) != 0 {
40             true
41         } else {
42             false
43         }; // 判断是否启用24小时模式
44 
45         let is_binary: bool = if (status_register_b & 0x04) != 0 {
46             true
47         } else {
48             false
49         }; // 判断是否为二进制码
50 
51         loop {
52             self.year = read_cmos(CMOSTimeSelector::Year as u8) as i32;
53             self.month = read_cmos(CMOSTimeSelector::Month as u8) as i32;
54             self.day = read_cmos(CMOSTimeSelector::Day as u8) as i32;
55             self.hour = read_cmos(CMOSTimeSelector::Hour as u8) as i32;
56             self.minute = read_cmos(CMOSTimeSelector::Minute as u8) as i32;
57             self.second = read_cmos(CMOSTimeSelector::Second as u8) as i32;
58 
59             if self.second == read_cmos(CMOSTimeSelector::Second as u8) as i32 {
60                 break;
61             } // 若读取时间过程中时间发生跳变则重新读取
62         }
63 
64         unsafe {
65             io_out8(0x70, 0x00);
66         }
67 
68         if !is_binary
69         // 把BCD转为二进制
70         {
71             self.second = (self.second & 0xf) + (self.second >> 4) * 10;
72             self.minute = (self.minute & 0xf) + (self.minute >> 4) * 10;
73             self.hour = ((self.hour & 0xf) + ((self.hour & 0x70) >> 4) * 10) | (self.hour & 0x80);
74             self.day = (self.day & 0xf) + ((self.day / 16) * 10);
75             self.month = (self.month & 0xf) + (self.month >> 4) * 10;
76             self.year = (self.year & 0xf) + (self.year >> 4) * 10;
77         }
78         self.year += 2000;
79 
80         if (!is_24h) && (self.hour & 0x80) != 0 {
81             self.hour = ((self.hour & 0x7f) + 12) % 24;
82         } // 将十二小时制转为24小时
83 
84         sti();
85 
86         return Ok(0);
87     }
88 }
89 
90 ///置位0x70的第7位,禁止不可屏蔽中断
91 #[inline]
read_cmos(addr: u8) -> u892 fn read_cmos(addr: u8) -> u8 {
93     unsafe {
94         io_out8(0x70, 0x80 | addr);
95         return io_in8(0x71);
96     }
97 }
98 
99 /// used in the form of u8
100 #[repr(u8)]
101 enum CMOSTimeSelector {
102     Second = 0x00,
103     Minute = 0x02,
104     Hour = 0x04,
105     Day = 0x07,
106     Month = 0x08,
107     Year = 0x09,
108 }
109