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