rtc.rs 3.1 KB

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