153 lines
4.6 KiB
C
153 lines
4.6 KiB
C
#define CURRENT_YEAR 2021 // Change this each year!
|
|
|
|
int century_register = 0x00; // Set by ACPI table parsing code if possible
|
|
|
|
unsigned char second;
|
|
unsigned char minute;
|
|
unsigned char hour;
|
|
unsigned char day;
|
|
unsigned char month;
|
|
unsigned int year;
|
|
|
|
|
|
|
|
enum {
|
|
cmos_address = 0x70,
|
|
cmos_data = 0x71
|
|
};
|
|
|
|
int get_update_in_progress_flag() {
|
|
outb(cmos_address, 0x0A);
|
|
return (inb(cmos_data) & 0x80);
|
|
}
|
|
|
|
unsigned char get_RTC_register(int reg) {
|
|
outb(cmos_address, reg);
|
|
return inb(cmos_data);
|
|
}
|
|
|
|
void read_rtc() {
|
|
unsigned char century;
|
|
unsigned char last_second;
|
|
unsigned char last_minute;
|
|
unsigned char last_hour;
|
|
unsigned char last_day;
|
|
unsigned char last_month;
|
|
unsigned char last_year;
|
|
unsigned char last_century;
|
|
unsigned char registerB;
|
|
|
|
// Note: This uses the "read registers until you get the same values twice in a row" technique
|
|
// to avoid getting dodgy/inconsistent values due to RTC updates
|
|
|
|
while (get_update_in_progress_flag()); // Make sure an update isn't in progress
|
|
second = get_RTC_register(0x00);
|
|
minute = get_RTC_register(0x02);
|
|
hour = get_RTC_register(0x04);
|
|
day = get_RTC_register(0x07);
|
|
month = get_RTC_register(0x08);
|
|
year = get_RTC_register(0x09);
|
|
if(century_register != 0) {
|
|
century = get_RTC_register(century_register);
|
|
} else {
|
|
century = 21;
|
|
}
|
|
|
|
do {
|
|
last_second = second;
|
|
last_minute = minute;
|
|
last_hour = hour;
|
|
last_day = day;
|
|
last_month = month;
|
|
last_year = year;
|
|
last_century = century;
|
|
|
|
while (get_update_in_progress_flag()); // Make sure an update isn't in progress
|
|
second = get_RTC_register(0x00);
|
|
minute = get_RTC_register(0x02);
|
|
hour = get_RTC_register(0x04);
|
|
day = get_RTC_register(0x07);
|
|
month = get_RTC_register(0x08);
|
|
year = get_RTC_register(0x09);
|
|
if(century_register != 0) {
|
|
century = get_RTC_register(century_register);
|
|
}
|
|
} while( (last_second != second) || (last_minute != minute) || (last_hour != hour) ||
|
|
(last_day != day) || (last_month != month) || (last_year != year) ||
|
|
(last_century != century) );
|
|
|
|
registerB = get_RTC_register(0x0B);
|
|
|
|
// Convert BCD to binary values if necessary
|
|
|
|
if (!(registerB & 0x04)) {
|
|
second = (second & 0x0F) + ((second / 16) * 10);
|
|
minute = (minute & 0x0F) + ((minute / 16) * 10);
|
|
hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80);
|
|
day = (day & 0x0F) + ((day / 16) * 10);
|
|
month = (month & 0x0F) + ((month / 16) * 10);
|
|
year = (year & 0x0F) + ((year / 16) * 10);
|
|
if(century_register != 0) {
|
|
century = (century & 0x0F) + ((century / 16) * 10);
|
|
}
|
|
}
|
|
|
|
// Convert 12 hour clock to 24 hour clock if necessary
|
|
|
|
if (!(registerB & 0x02) && (hour & 0x80)) {
|
|
hour = ((hour & 0x7F) + 12) % 24;
|
|
}
|
|
|
|
// Calculate the full (4-digit) year
|
|
|
|
if(century_register != 0) {
|
|
year += century * 100;
|
|
} else {
|
|
year += (CURRENT_YEAR / 100) * 100;
|
|
if(year < CURRENT_YEAR) year += 100;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
void ReadFromCMOS(unsigned char array[])
|
|
{
|
|
unsigned char tvalue, index;
|
|
|
|
for (index = 0; index < 128; index++)
|
|
{
|
|
asm(
|
|
"cli\n\t" // Disable interrupts
|
|
"mov al, index\n\t" // Move index address
|
|
// since the 0x80 bit of al is not set, NMI is active
|
|
"out 0x70,al\n\t" // Copy address to CMOS register
|
|
// some kind of real delay here is probably best
|
|
"in al,0x71\n\t" // Fetch 1 byte to al
|
|
"sti\n\t" // Enable interrupts
|
|
"mov tvalue,al\n\t");
|
|
|
|
array[index] = tvalue;
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
void WriteTOCMOS(unsigned char array[])
|
|
{
|
|
unsigned char index;
|
|
|
|
for(index = 0; index < 128; index++)
|
|
{
|
|
unsigned char tvalue = array[index];
|
|
|
|
asm("cli\n\t" // Clear interrupts
|
|
"mov al,index\n\t" // move index address
|
|
"out 0x70,al\n\t" // copy address to CMOS register
|
|
// some kind of real delay here is probably best
|
|
"mov al,tvalue\n\t" // move value to al
|
|
"out 0x71,al\n\t" // write 1 byte to CMOS
|
|
"sti\n\\t" ); // Enable interrupts
|
|
|
|
}
|
|
}
|
|
*/ |