kern

view src/rtc.c @ 36:e70b1ab9613e

- added cmos rtc code - added time/date functions in klibc - implemented an iowait macro with output to 0x80
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 10 Jun 2011 05:33:38 +0300
parents
children 2c401f69128e
line source
1 #include <stdio.h>
2 #include <time.h>
3 #include <asmops.h>
5 /* CMOS I/O ports */
6 #define PORT_CTL 0x70
7 #define PORT_DATA 0x71
9 /* CMOS RTC registers */
10 #define REG_SEC 0
11 #define REG_ALARM_SEC 1
12 #define REG_MIN 2
13 #define REG_ALARM_MIN 3
14 #define REG_HOUR 4
15 #define REG_ALARM_HOUR 5
16 #define REG_WEEKDAY 6
17 #define REG_DAY 7
18 #define REG_MONTH 8
19 #define REG_YEAR 9
20 #define REG_STATA 10
21 #define REG_STATB 11
22 #define REG_STATC 12
23 #define REG_STATD 13
25 #define STATA_BUSY (1 << 7)
26 #define STATB_24HR (1 << 1)
27 #define STATB_BIN (1 << 2)
29 #define HOUR_PM_BIT (1 << 7)
31 #define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf))
33 static void read_rtc(struct tm *tm);
34 static int read_reg(int reg);
36 static unsigned long start_time;
39 void init_rtc(void)
40 {
41 struct tm tm;
43 read_rtc(&tm);
44 printf("System real-time clock: %s", asctime(&tm));
45 printf("time_t: %ld\n", mktime(&tm));
46 }
48 static void read_rtc(struct tm *tm)
49 {
50 int statb, pm;
52 /* wait for any clock updates to finish */
53 while(read_reg(REG_STATA) & STATA_BUSY);
55 tm->tm_sec = read_reg(REG_SEC);
56 tm->tm_min = read_reg(REG_MIN);
57 tm->tm_hour = read_reg(REG_HOUR);
58 tm->tm_mday = read_reg(REG_DAY);
59 tm->tm_mon = read_reg(REG_MONTH);
60 tm->tm_year = read_reg(REG_YEAR);
61 tm->tm_wday = read_reg(REG_WEEKDAY);
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 tm->tm_wday = BCD_TO_BIN(tm->tm_wday);
77 }
79 /* make the year an offset from 1900 */
80 if(tm->tm_year < 100) {
81 tm->tm_year += 100;
82 } else {
83 tm->tm_year -= 1900;
84 }
86 /* if tm_hour is in 12h mode, convert to 24h */
87 if(!(statb & STATB_24HR)) {
88 if(tm->tm_hour == 12) {
89 tm->tm_hour = 0;
90 }
91 if(pm) {
92 tm->tm_hour += 12;
93 }
94 }
96 tm->tm_mon -= 1; /* we want months to start from 0 */
97 tm->tm_wday -= 1; /* we want weekdays to start from 0 */
98 tm->tm_yday = day_of_year(tm->tm_year + 1900, tm->tm_mon, tm->tm_mday - 1);
99 }
101 static int read_reg(int reg)
102 {
103 unsigned char val;
104 outb(reg, PORT_CTL);
105 iodelay();
106 inb(val, PORT_DATA);
107 iodelay();
108 return val;
109 }