kern

view src/rtc.c @ 40:710739e33da8

- now read_rtc doesn't try to read weekday as it's probably wrong anyway, and doesn't set yearday either - mktime now fixes yearday and weekday - moved init_timer and init_rtc just before enabling the interrupts in main
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 12 Jun 2011 15:45:21 +0300
parents 2c401f69128e
children
line source
1 #include <stdio.h>
2 #include <time.h>
3 #include <asmops.h>
4 #include "rtc.h"
6 /* CMOS I/O ports */
7 #define PORT_CTL 0x70
8 #define PORT_DATA 0x71
10 /* CMOS RTC registers */
11 #define REG_SEC 0
12 #define REG_ALARM_SEC 1
13 #define REG_MIN 2
14 #define REG_ALARM_MIN 3
15 #define REG_HOUR 4
16 #define REG_ALARM_HOUR 5
17 #define REG_WEEKDAY 6
18 #define REG_DAY 7
19 #define REG_MONTH 8
20 #define REG_YEAR 9
21 #define REG_STATA 10
22 #define REG_STATB 11
23 #define REG_STATC 12
24 #define REG_STATD 13
26 #define STATA_BUSY (1 << 7)
27 #define STATB_24HR (1 << 1)
28 #define STATB_BIN (1 << 2)
30 #define HOUR_PM_BIT (1 << 7)
32 #define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf))
34 static void read_rtc(struct tm *tm);
35 static int read_reg(int reg);
38 void init_rtc(void)
39 {
40 struct tm tm;
42 read_rtc(&tm);
43 start_time = mktime(&tm);
45 printf("System real-time clock: %s", asctime(&tm));
46 }
49 static void read_rtc(struct tm *tm)
50 {
51 int statb, pm;
53 /* wait for any clock updates to finish */
54 while(read_reg(REG_STATA) & STATA_BUSY);
56 tm->tm_sec = read_reg(REG_SEC);
57 tm->tm_min = read_reg(REG_MIN);
58 tm->tm_hour = read_reg(REG_HOUR);
59 tm->tm_mday = read_reg(REG_DAY);
60 tm->tm_mon = read_reg(REG_MONTH);
61 tm->tm_year = read_reg(REG_YEAR);
63 /* in 12hour mode, bit 7 means post-meridiem */
64 pm = tm->tm_hour & HOUR_PM_BIT;
65 tm->tm_hour &= ~HOUR_PM_BIT;
67 /* convert to binary if needed */
68 statb = read_reg(REG_STATB);
69 if(!(statb & STATB_BIN)) {
70 tm->tm_sec = BCD_TO_BIN(tm->tm_sec);
71 tm->tm_min = BCD_TO_BIN(tm->tm_min);
72 tm->tm_hour = BCD_TO_BIN(tm->tm_hour);
73 tm->tm_mday = BCD_TO_BIN(tm->tm_mday);
74 tm->tm_mon = BCD_TO_BIN(tm->tm_mon);
75 tm->tm_year = BCD_TO_BIN(tm->tm_year);
76 }
78 /* make the year an offset from 1900 */
79 if(tm->tm_year < 100) {
80 tm->tm_year += 100;
81 } else {
82 tm->tm_year -= 1900;
83 }
85 /* if tm_hour is in 12h mode, convert to 24h */
86 if(!(statb & STATB_24HR)) {
87 if(tm->tm_hour == 12) {
88 tm->tm_hour = 0;
89 }
90 if(pm) {
91 tm->tm_hour += 12;
92 }
93 }
95 tm->tm_mon -= 1; /* we want months to start from 0 */
96 }
98 static int read_reg(int reg)
99 {
100 unsigned char val;
101 outb(reg, PORT_CTL);
102 iodelay();
103 inb(val, PORT_DATA);
104 iodelay();
105 return val;
106 }