RTC.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #include <AK/Assertions.h>
  2. #include <Kernel/CMOS.h>
  3. #include <Kernel/RTC.h>
  4. namespace RTC {
  5. static time_t s_boot_time;
  6. void initialize()
  7. {
  8. byte cmos_mode = CMOS::read(0x0b);
  9. cmos_mode |= 2; // 24 hour mode
  10. cmos_mode |= 4; // No BCD mode
  11. CMOS::write(0x0b, cmos_mode);
  12. s_boot_time = now();
  13. }
  14. time_t boot_time()
  15. {
  16. return s_boot_time;
  17. }
  18. static bool update_in_progress()
  19. {
  20. return CMOS::read(0x0a) & 0x80;
  21. }
  22. inline bool is_leap_year(unsigned year)
  23. {
  24. return ((year % 4 == 0) && ((year % 100 != 0) || (year % 400) == 0));
  25. }
  26. static unsigned days_in_months_since_start_of_year(unsigned month, unsigned year)
  27. {
  28. ASSERT(month <= 11);
  29. unsigned days = 0;
  30. switch (month) {
  31. case 11:
  32. days += 30;
  33. [[fallthrough]];
  34. case 10:
  35. days += 31;
  36. [[fallthrough]];
  37. case 9:
  38. days += 30;
  39. [[fallthrough]];
  40. case 8:
  41. days += 31;
  42. [[fallthrough]];
  43. case 7:
  44. days += 31;
  45. [[fallthrough]];
  46. case 6:
  47. days += 30;
  48. [[fallthrough]];
  49. case 5:
  50. days += 31;
  51. [[fallthrough]];
  52. case 4:
  53. days += 30;
  54. [[fallthrough]];
  55. case 3:
  56. days += 31;
  57. [[fallthrough]];
  58. case 2:
  59. if (is_leap_year(year))
  60. days += 29;
  61. else
  62. days += 28;
  63. [[fallthrough]];
  64. case 1:
  65. days += 31;
  66. }
  67. return days;
  68. }
  69. static unsigned days_in_years_since_epoch(unsigned year)
  70. {
  71. unsigned days = 0;
  72. while (year > 1969) {
  73. days += 365;
  74. if (is_leap_year(year))
  75. ++days;
  76. --year;
  77. }
  78. return days;
  79. }
  80. void read_registers(unsigned& year, unsigned& month, unsigned& day, unsigned& hour, unsigned& minute, unsigned& second)
  81. {
  82. while (update_in_progress())
  83. ;
  84. year = (CMOS::read(0x32) * 100) + CMOS::read(0x09);
  85. month = CMOS::read(0x08);
  86. day = CMOS::read(0x07);
  87. hour = CMOS::read(0x04);
  88. minute = CMOS::read(0x02);
  89. second = CMOS::read(0x00);
  90. }
  91. time_t now()
  92. {
  93. // FIXME: We should probably do something more robust here.
  94. // Perhaps read all the values twice and verify that they were identical.
  95. // We don't want to be caught in the middle of an RTC register update.
  96. while (update_in_progress())
  97. ;
  98. unsigned year, month, day, hour, minute, second;
  99. read_registers(year, month, day, hour, minute, second);
  100. kprintf("year: %d, month: %d, day: %d\n", year, month, day);
  101. ASSERT(year >= 2018);
  102. return days_in_years_since_epoch(year - 1) * 86400
  103. + days_in_months_since_start_of_year(month - 1, year) * 86400
  104. + (day - 1) * 86400
  105. + hour * 3600
  106. + minute * 60
  107. + second;
  108. }
  109. }