RTC.cpp 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #include "RTC.h"
  2. #include "CMOS.h"
  3. #include <AK/Assertions.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. switch (month) {
  29. case 11: return 30;
  30. case 10: return 31;
  31. case 9: return 30;
  32. case 8: return 31;
  33. case 7: return 31;
  34. case 6: return 30;
  35. case 5: return 31;
  36. case 4: return 30;
  37. case 3: return 31;
  38. case 2:
  39. if (is_leap_year(year))
  40. return 29;
  41. return 28;
  42. case 1: return 31;
  43. default: return 0;
  44. }
  45. }
  46. static unsigned days_in_years_since_epoch(unsigned year)
  47. {
  48. unsigned days = 0;
  49. while (year > 1969) {
  50. days += 365;
  51. if (is_leap_year(year))
  52. ++days;
  53. --year;
  54. }
  55. return days;
  56. }
  57. void read_registers(unsigned& year, unsigned& month, unsigned& day, unsigned& hour, unsigned& minute, unsigned& second)
  58. {
  59. while (update_in_progress())
  60. ;
  61. year = (CMOS::read(0x32) * 100) + CMOS::read(0x09);
  62. month = CMOS::read(0x08);
  63. day = CMOS::read(0x07);
  64. hour = CMOS::read(0x04);
  65. minute = CMOS::read(0x02);
  66. second = CMOS::read(0x00);
  67. }
  68. time_t now()
  69. {
  70. // FIXME: We should probably do something more robust here.
  71. // Perhaps read all the values twice and verify that they were identical.
  72. // We don't want to be caught in the middle of an RTC register update.
  73. while (update_in_progress())
  74. ;
  75. unsigned year, month, day, hour, minute, second;
  76. read_registers(year, month, day, hour, minute, second);
  77. ASSERT(year >= 2018);
  78. return days_in_years_since_epoch(year - 1) * 86400
  79. + days_in_months_since_start_of_year(month - 1, year) * 86400
  80. + day * 86400
  81. + hour * 3600
  82. + minute * 60
  83. + second;
  84. }
  85. }