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 | ␊ |
15 | static int century_register = 0x00; // Set by ACPI table parsing code if possible(... in FADT table)␊ |
16 | ␊ |
17 | enum {␊ |
18 | cmos_address = 0x70,␊ |
19 | cmos_data = 0x71␊ |
20 | };␊ |
21 | ␊ |
22 | ␊ |
23 | static int get_update_in_progress_flag() {␊ |
24 | outb(cmos_address, 0x0A);␊ |
25 | return (inb(cmos_data) & 0x80);␊ |
26 | }␊ |
27 | ␊ |
28 | ␊ |
29 | static unsigned char get_RTC_register(int reg) {␊ |
30 | outb(cmos_address, reg);␊ |
31 | return inb(cmos_data);␊ |
32 | }␊ |
33 | ␊ |
34 | void 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 | |