cmos.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2011-2018 K. Lange
  5. *
  6. * CMOS Driver
  7. *
  8. */
  9. #include <kernel/system.h>
  10. /* CMOS values are stored like so:
  11. * Say it's 8:42 AM, then the values are stored as:
  12. * 0x08, 0x42... why this was a good idea, I have no
  13. * clue, but that's how it usually is.
  14. *
  15. * This function will convert between this "BCD" format
  16. * and regular decimal integers. */
  17. #define from_bcd(val) ((val / 16) * 10 + (val & 0xf))
  18. #define CMOS_ADDRESS 0x70
  19. #define CMOS_DATA 0x71
  20. enum
  21. {
  22. CMOS_SECOND = 0,
  23. CMOS_MINUTE = 2,
  24. CMOS_HOUR = 4,
  25. CMOS_DAY = 7,
  26. CMOS_MONTH = 8,
  27. CMOS_YEAR = 9
  28. };
  29. void
  30. cmos_dump(
  31. uint16_t * values
  32. ) {
  33. uint16_t index;
  34. for (index = 0; index < 128; ++index) {
  35. outportb(CMOS_ADDRESS, index);
  36. values[index] = inportb(CMOS_DATA);
  37. }
  38. }
  39. int is_update_in_progress(void)
  40. {
  41. outportb(CMOS_ADDRESS, 0x0a);
  42. return inportb(CMOS_DATA) & 0x80;
  43. }
  44. /**
  45. * Get the current month and day.
  46. *
  47. * @param month Pointer to a short to store the month
  48. * @param day Pointer to a short to store the day
  49. */
  50. void
  51. get_date(
  52. uint16_t * month,
  53. uint16_t * day
  54. ) {
  55. uint16_t values[128]; /* CMOS dump */
  56. cmos_dump(values);
  57. *month = from_bcd(values[CMOS_MONTH]);
  58. *day = from_bcd(values[CMOS_DAY]);
  59. }
  60. /**
  61. * Get the current time.
  62. *
  63. * @param hours Pointer to a short to store the current hour (/24)
  64. * @param minutes Pointer to a short to store the current minute
  65. * @param seconds Pointer to a short to store the current second
  66. */
  67. void
  68. get_time(
  69. uint16_t * hours,
  70. uint16_t * minutes,
  71. uint16_t * seconds
  72. ) {
  73. uint16_t values[128]; /* CMOS dump */
  74. cmos_dump(values);
  75. *hours = from_bcd(values[CMOS_HOUR]);
  76. *minutes = from_bcd(values[CMOS_MINUTE]);
  77. *seconds = from_bcd(values[CMOS_SECOND]);
  78. }
  79. uint32_t secs_of_years(int years) {
  80. uint32_t days = 0;
  81. years += 2000;
  82. while (years > 1969) {
  83. days += 365;
  84. if (years % 4 == 0) {
  85. if (years % 100 == 0) {
  86. if (years % 400 == 0) {
  87. days++;
  88. }
  89. } else {
  90. days++;
  91. }
  92. }
  93. years--;
  94. }
  95. return days * 86400;
  96. }
  97. uint32_t secs_of_month(int months, int year) {
  98. year += 2000;
  99. uint32_t days = 0;
  100. switch(months) {
  101. case 11:
  102. days += 30;
  103. case 10:
  104. days += 31;
  105. case 9:
  106. days += 30;
  107. case 8:
  108. days += 31;
  109. case 7:
  110. days += 31;
  111. case 6:
  112. days += 30;
  113. case 5:
  114. days += 31;
  115. case 4:
  116. days += 30;
  117. case 3:
  118. days += 31;
  119. case 2:
  120. days += 28;
  121. if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) {
  122. days++;
  123. }
  124. case 1:
  125. days += 31;
  126. default:
  127. break;
  128. }
  129. return days * 86400;
  130. }
  131. uint32_t boot_time = 0;
  132. uint32_t read_cmos(void) {
  133. uint16_t values[128];
  134. uint16_t old_values[128];
  135. while (is_update_in_progress())
  136. ;
  137. cmos_dump(values);
  138. do
  139. {
  140. memcpy(old_values, values, 128);
  141. while (is_update_in_progress())
  142. ;
  143. cmos_dump(values);
  144. } while ((old_values[CMOS_SECOND] != values[CMOS_SECOND]) ||
  145. (old_values[CMOS_MINUTE] != values[CMOS_MINUTE]) ||
  146. (old_values[CMOS_HOUR] != values[CMOS_HOUR]) ||
  147. (old_values[CMOS_DAY] != values[CMOS_DAY]) ||
  148. (old_values[CMOS_MONTH] != values[CMOS_MONTH]) ||
  149. (old_values[CMOS_YEAR] != values[CMOS_YEAR]));
  150. /* Math Time */
  151. uint32_t time =
  152. secs_of_years(from_bcd(values[CMOS_YEAR]) - 1) +
  153. secs_of_month(from_bcd(values[CMOS_MONTH]) - 1,
  154. from_bcd(values[CMOS_YEAR])) +
  155. (from_bcd(values[CMOS_DAY]) - 1) * 86400 +
  156. (from_bcd(values[CMOS_HOUR])) * 3600 +
  157. (from_bcd(values[CMOS_MINUTE])) * 60 +
  158. from_bcd(values[CMOS_SECOND]) + 0;
  159. return time;
  160. }
  161. int gettimeofday(struct timeval * t, void *z) {
  162. t->tv_sec = boot_time + timer_ticks + timer_drift;
  163. t->tv_usec = timer_subticks * 1000;
  164. return 0;
  165. }
  166. uint32_t now(void) {
  167. struct timeval t;
  168. gettimeofday(&t, NULL);
  169. return t.tv_sec;
  170. }