diff --git a/arch/i386/cmos.c b/arch/i386/cmos.c new file mode 100644 index 0000000..0217d85 --- /dev/null +++ b/arch/i386/cmos.c @@ -0,0 +1,68 @@ +#include + +int _check_update_in_progress(void) { + unsigned char ret_val = 0; + __asm__ volatile("mov $0x0A, %%al\n\t" "outb %%al, $0x70\n\t" "inb $0x71, %%al\n\t" "mov %%al, %0":"=b" (ret_val)::"%al"); + return ret_val; +} + +unsigned char _get_rtc_reg(unsigned char reg) { + unsigned char ret_val = 0; + __asm__ volatile("mov %1, %%al\n\t" "outb %%al, $0x70\n\t" "inb $0x71, %%al\n\t" "mov %%al, %0":"=b" (ret_val):"c" (reg):"%al"); + return ret_val; +} + +unsigned long int read_rtc() { + unsigned char regb; + unsigned long int ret_val; + + /* I might need to add this check back in, but it's fine for now. */ + /* while(_check_update_in_progress()); */ + + cur_time.second = _get_rtc_reg(0x00); + cur_time.minute = _get_rtc_reg(0x02); + cur_time.hour = _get_rtc_reg(0x04); + cur_time.day = _get_rtc_reg(0x07); + cur_time.month = _get_rtc_reg(0x08); + cur_time.year = _get_rtc_reg(0x09); + + regb = _get_rtc_reg(0x0B); + + /* Convert bcd to binary if needed */ + if(!(regb & 0x04)) { + cur_time.second = (cur_time.second & 0x0F) + ((cur_time.second / 16) * 10); + cur_time.minute = (cur_time.minute & 0x0F) + ((cur_time.minute / 16) * 10); + cur_time.hour = ((cur_time.hour & 0x0F) + (((cur_time.hour & 0x70) / 16) * 10)) | (cur_time.hour & 0x80); + cur_time.day = (cur_time.day & 0x0F) + ((cur_time.day / 16) * 10); + cur_time.month = (cur_time.month & 0x0F) + ((cur_time.month / 16) * 10); + cur_time.year = (cur_time.year & 0x0F) + ((cur_time.year / 16) * 10); + } + + /* Convert to 24H time if needed */ + if(!(regb & 0x02) && (cur_time.hour & 0x80)) { + cur_time.hour = ((cur_time.hour & 0x7F) + 12) % 24; + } + + /* Get year. TODO: Use century register for this. */ + cur_time.year += (RELEASE_YEAR / 100) * 100; /* Add century of release year */ + if(cur_time.year < RELEASE_YEAR) cur_time.year += 100; + + ret_val = cur_time.second; + ret_val += cur_time.minute * 60; + ret_val += cur_time.hour * 3600; + unsigned int tot_days = cur_time.day; + unsigned char month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + for(unsigned int i = 1970; i < cur_time.year; i++) { + if(i % 400 == 0 || (i % 100 != 0 && i % 4 == 0)) { + tot_days += 366; + } + else { + tot_days += 365; + } + } + for(int i = 0; i < (cur_time.month - 1); i++) { + tot_days += month_days[i]; + } + ret_val += tot_days * 86400; + return ret_val; +} diff --git a/include/kernel/cmos.h b/include/kernel/cmos.h new file mode 100644 index 0000000..cecc2d0 --- /dev/null +++ b/include/kernel/cmos.h @@ -0,0 +1,27 @@ +#ifndef _KERNEL_CMOS +#define _KERNEL_CMOS + +/* This is kinda important, and has to be changed each year. */ +#define RELEASE_YEAR 2020 + +struct _rtc_val { + unsigned char second; + unsigned char minute; + unsigned char hour; + unsigned char day; + unsigned char month; + unsigned int year; +}; + +static struct _rtc_val cur_time; + +enum { + cmos_address = 0x70, + cmos_data = 0x71 +}; + +int _check_update_in_progress(void); +unsigned char _get_rtc_reg(unsigned char reg); +unsigned long int read_rtc(); + +#endif