rtc.c 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #include "rtc.h"
  2. #include <common/kprint.h>
  3. /*置位0x70的第7位,禁止不可屏蔽中断*/
  4. /*
  5. #define read_cmos(addr) ({ \
  6. io_out8(0x70, 0x80 | addr); \
  7. io_in8(0x71); \
  8. })
  9. */
  10. enum CMOSTimeSelector
  11. {
  12. T_SECOND = 0x0,
  13. T_MINUTE = 0x2,
  14. T_HOUR = 0x4,
  15. T_DAY = 0x7,
  16. T_MONTH = 0x8,
  17. T_YEAR = 0x9,
  18. };
  19. int read_cmos(uint8_t addr)
  20. {
  21. io_out8(0x70, 0x80 | addr);
  22. io_mfence();
  23. return (uint8_t)(io_in8(0x71) & 0xff);
  24. }
  25. int rtc_get_cmos_time(struct time *t)
  26. {
  27. // 为防止中断请求打断该过程,需要先关中断
  28. cli();
  29. uint8_t status_register_B = read_cmos(0x0B); // 读取状态寄存器B
  30. bool is_24h = ((status_register_B & 0x02) ? true : false); // 判断是否启用24小时模式
  31. bool is_binary = ((status_register_B & 0x04) ? true : false); // 判断是否为二进制码
  32. do
  33. {
  34. t->year = read_cmos(0x09);
  35. t->month = read_cmos(0x08);
  36. t->day = read_cmos(0x07);
  37. t->hour = read_cmos(0x04);
  38. t->minute = read_cmos(0x02);
  39. t->second = read_cmos(0x00);
  40. } while (t->second != read_cmos(0x00)); // 若读取时间过程中时间发生跳变则重新读取
  41. // 使能NMI中断
  42. io_out8(0x70, 0x00);
  43. if (!is_binary) // 把BCD转为二进制
  44. {
  45. t->second = (t->second & 0xf) + (t->second >> 4) * 10;
  46. t->minute = (t->minute & 0xf) + (t->minute >> 4) * 10;
  47. t->hour = ((t->hour & 0xf) + ((t->hour & 0x70) >> 4) * 10) | (t->hour & 0x80);
  48. t->month = (t->month & 0xf) + (t->month >> 4) * 10;
  49. t->year = (t->year & 0xf) + (t->year >> 4) * 10;
  50. }
  51. t->year += 2000;
  52. if ((!is_24h) && t->hour & 0x80) // 将十二小时制转为24小时
  53. t->hour = ((t->hour & 0x7f) + 12) % 24;
  54. sti();
  55. return 0;
  56. }