kern

view src/rtc.c @ 37:2c401f69128e

finished with the klibc/time.c stuff
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 10 Jun 2011 19:54:47 +0300
parents e70b1ab9613e
children 710739e33da8
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);
62 tm->tm_wday = read_reg(REG_WEEKDAY);
64 /* in 12hour mode, bit 7 means post-meridiem */
65 pm = tm->tm_hour & HOUR_PM_BIT;
66 tm->tm_hour &= ~HOUR_PM_BIT;
68 /* convert to binary if needed */
69 statb = read_reg(REG_STATB);
70 if(!(statb & STATB_BIN)) {
71 tm->tm_sec = BCD_TO_BIN(tm->tm_sec);
72 tm->tm_min = BCD_TO_BIN(tm->tm_min);
73 tm->tm_hour = BCD_TO_BIN(tm->tm_hour);
74 tm->tm_mday = BCD_TO_BIN(tm->tm_mday);
75 tm->tm_mon = BCD_TO_BIN(tm->tm_mon);
76 tm->tm_year = BCD_TO_BIN(tm->tm_year);
77 tm->tm_wday = BCD_TO_BIN(tm->tm_wday);
78 }
80 /* make the year an offset from 1900 */
81 if(tm->tm_year < 100) {
82 tm->tm_year += 100;
83 } else {
84 tm->tm_year -= 1900;
85 }
87 /* if tm_hour is in 12h mode, convert to 24h */
88 if(!(statb & STATB_24HR)) {
89 if(tm->tm_hour == 12) {
90 tm->tm_hour = 0;
91 }
92 if(pm) {
93 tm->tm_hour += 12;
94 }
95 }
97 tm->tm_mon -= 1; /* we want months to start from 0 */
98 tm->tm_wday -= 1; /* we want weekdays to start from 0 */
99 tm->tm_yday = day_of_year(tm->tm_year + 1900, tm->tm_mon, tm->tm_mday - 1);
100 }
102 static int read_reg(int reg)
103 {
104 unsigned char val;
105 outb(reg, PORT_CTL);
106 iodelay();
107 inb(val, PORT_DATA);
108 iodelay();
109 return val;
110 }