Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/libsaio/rtc.c

1/*
2 * http://wiki.osdev.org/OSDev_Wiki:General_disclaimer
3 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
9 * THE SOFTWARE.
10 */
11#include "libsaio.h"
12
13#define CURRENT_YEAR 2012 // Change this each year!
14
15static int century_register = 0x00; // Set by ACPI table parsing code if possible(... in FADT table)
16
17enum {
18 cmos_address = 0x70,
19 cmos_data = 0x71
20};
21
22
23static int get_update_in_progress_flag() {
24 outb(cmos_address, 0x0A);
25 return (inb(cmos_data) & 0x80);
26}
27
28
29static unsigned char get_RTC_register(int reg) {
30 outb(cmos_address, reg);
31 return inb(cmos_data);
32}
33
34void rtc_read_clock(struct tm *time) {
35 unsigned char century = 0;
36 unsigned char last_second;
37 unsigned char last_minute;
38 unsigned char last_hour;
39 unsigned char last_day;
40 unsigned char last_month;
41 unsigned char last_year;
42 unsigned char last_century;
43 unsigned char registerB;
44
45 unsigned char second;
46 unsigned char minute;
47 unsigned char hour;
48 unsigned char day;
49 unsigned char month;
50 unsigned int year;
51 // Note: This uses the "read registers until you get the same values twice in a row" technique
52 // to avoid getting dodgy/inconsistent values due to RTC updates
53
54 while (get_update_in_progress_flag()); // Make sure an update isn't in progress
55 second = get_RTC_register(0x00);
56 minute = get_RTC_register(0x02);
57 hour = get_RTC_register(0x04);
58 day = get_RTC_register(0x07);
59 month = get_RTC_register(0x08);
60 year = get_RTC_register(0x09);
61 if(century_register != 0) {
62 century = get_RTC_register(century_register);
63 }
64
65 do {
66 last_second = second;
67 last_minute = minute;
68 last_hour = hour;
69 last_day = day;
70 last_month = month;
71 last_year = year;
72 last_century = century;
73
74 while (get_update_in_progress_flag()); // Make sure an update isn't in progress
75 second = get_RTC_register(0x00);
76 minute = get_RTC_register(0x02);
77 hour = get_RTC_register(0x04);
78 day = get_RTC_register(0x07);
79 month = get_RTC_register(0x08);
80 year = get_RTC_register(0x09);
81 if(century_register != 0) {
82 century = get_RTC_register(century_register);
83 }
84 } while( (last_second == second) && (last_minute == minute) && (last_hour == hour) &&
85 (last_day == day) && (last_month == month) && (last_year == year) &&
86 (last_century == century) );
87
88 registerB = get_RTC_register(0x0B);
89
90 // Convert BCD to binary values if necessary
91
92 if (!(registerB & 0x04)) {
93 second = (second & 0x0F) + ((second / 16) * 10);
94 minute = (minute & 0x0F) + ((minute / 16) * 10);
95 hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80);
96 day = (day & 0x0F) + ((day / 16) * 10);
97 month = (month & 0x0F) + ((month / 16) * 10);
98 year = (year & 0x0F) + ((year / 16) * 10);
99 if(century_register != 0) {
100 century = (century & 0x0F) + ((century / 16) * 10);
101 }
102 }
103
104 // Calculate the full (4-digit) year
105
106 if(century_register != 0) {
107 year += century * 100;
108 } else {
109 //year += (CURRENT_YEAR / 100) * 100;
110 //if(year < CURRENT_YEAR) year += 100;
111
112 if ((year += 1900) < 1970)
113 year += 100;
114 }
115
116 time->tm_sec = second;
117 time->tm_min = minute;
118 time->tm_hour = hour;
119 time->tm_mday = day;
120 time->tm_mon = month;
121 time->tm_year = year;
122}
123

Archive Download this file

Revision: 2006