diff --git a/headers/private/kernel/real_time_clock.h b/headers/private/kernel/real_time_clock.h index 039745d900..c70bf89ff0 100644 --- a/headers/private/kernel/real_time_clock.h +++ b/headers/private/kernel/real_time_clock.h @@ -8,6 +8,10 @@ #include +#include + + +#define RTC_EPOCHE_BASE_YEAR 1970 #ifdef __cplusplus extern "C" { @@ -26,6 +30,11 @@ typedef struct rtc_info { status_t get_rtc_info(rtc_info *info); +// Both functions use the passed struct tm only partially +// (no tm_wday, tm_yday, tm_isdst). +uint32 rtc_tm_to_secs(const struct tm *t); +void rtc_secs_to_tm(uint32 seconds, struct tm *t); + bigtime_t _user_system_time(void); status_t _user_set_real_time_clock(uint32 time); status_t _user_set_timezone(int32 timezoneOffset, bool daylightSavingTime); diff --git a/src/system/kernel/arch/x86/arch_real_time_clock.c b/src/system/kernel/arch/x86/arch_real_time_clock.c index 601c20513b..f49acb80e0 100644 --- a/src/system/kernel/arch/x86/arch_real_time_clock.c +++ b/src/system/kernel/arch/x86/arch_real_time_clock.c @@ -9,16 +9,12 @@ #include #include +#include #include #define CMOS_ADDR_PORT 0x70 #define CMOS_DATA_PORT 0x71 -#define BASE_YEAR 1970 -#define SECONDS_31 2678400 -#define SECONDS_30 2592000 -#define SECONDS_28 2419200 -#define SECONDS_DAY 86400 typedef struct { uint8 second; @@ -30,10 +26,6 @@ typedef struct { uint8 century; } cmos_time; -static uint32 sSecsPerMonth[12] = {SECONDS_31, SECONDS_28, SECONDS_31, SECONDS_30, - SECONDS_31, SECONDS_30, SECONDS_31, SECONDS_31, SECONDS_30, SECONDS_31, SECONDS_30, - SECONDS_31}; - static uint32 bcd_to_int(uint8 bcd) @@ -64,22 +56,6 @@ int_to_bcd(uint32 number) } -static bool -leap_year(uint32 year) -{ - if (year % 400 == 0) - return true; - - if (year % 100 == 0) - return false; - - if (year % 4 == 0) - return true; - - return false; -} - - static int same_time(const cmos_time *time1, const cmos_time *time2) { @@ -160,105 +136,39 @@ write_cmos_clock(cmos_time *cmos) } -static inline uint32 -secs_this_year(uint32 year) -{ - if (leap_year(year)) - return 31622400; - - return 31536000; -} - - static uint32 cmos_to_secs(const cmos_time *cmos) { - uint32 wholeYear; - uint32 time = 0; - uint32 i; + struct tm t; + t.tm_year = bcd_to_int(cmos->century) * 100 + bcd_to_int(cmos->year) + - RTC_EPOCHE_BASE_YEAR; + t.tm_mon = bcd_to_int(cmos->month) - 1; + t.tm_mday = bcd_to_int(cmos->day); + t.tm_hour = bcd_to_int(cmos->hour); + t.tm_min = bcd_to_int(cmos->minute); + t.tm_sec = bcd_to_int(cmos->second); - wholeYear = bcd_to_int(cmos->century) * 100 + bcd_to_int(cmos->year); - - // ToDo: get rid of these loops and compute the correct value - // i.e. days = (long)(year > 0) + year*365 + --year/4 - year/100 + year/400; - // let sSecsPerMonth[] have the values already added up - - // Add up the seconds from all years since 1970 that have elapsed. - for (i = BASE_YEAR; i < wholeYear; ++i) { - time += secs_this_year(i); - } - - // Add up the seconds from all months passed this year. - for (i = 0; i < bcd_to_int(cmos->month) - 1 && i < 12; ++i) - time += sSecsPerMonth[i]; - - // Add up the seconds from all days passed this month. - if (leap_year(wholeYear) && bcd_to_int(cmos->month) > 2) - time += SECONDS_DAY; - - time += (bcd_to_int(cmos->day) - 1) * SECONDS_DAY; - time += bcd_to_int(cmos->hour) * 3600; - time += bcd_to_int(cmos->minute) * 60; - time += bcd_to_int(cmos->second); - - return time; + return rtc_tm_to_secs(&t); } static void secs_to_cmos(uint32 seconds, cmos_time *cmos) { - uint32 wholeYear = BASE_YEAR; - uint32 secsThisYear; - bool keepLooping; - bool isLeapYear; - int temp; - int month; + int wholeYear; - keepLooping = 1; + struct tm t; + rtc_secs_to_tm(seconds, &t); - // Determine the current year by starting at 1970 and incrementing whole_year as long as - // we can keep subtracting secs_this_year from seconds. - while (keepLooping) { - secsThisYear = secs_this_year(wholeYear); - - if (seconds >= secsThisYear) { - seconds -= secsThisYear; - ++wholeYear; - } else - keepLooping = false; - } + wholeYear = t.tm_year + RTC_EPOCHE_BASE_YEAR; cmos->century = int_to_bcd(wholeYear / 100); cmos->year = int_to_bcd(wholeYear % 100); - - // Determine the current month - month = 1; - isLeapYear = leap_year(wholeYear); - do { - temp = seconds - sSecsPerMonth[month - 1]; - - if (isLeapYear && month == 2) - temp -= SECONDS_DAY; - - if (temp >= 0) { - seconds = temp; - ++month; - } - } while (temp >= 0 && month < 13); - - cmos->month = int_to_bcd(month); - - cmos->day = int_to_bcd(seconds / SECONDS_DAY + 1); - seconds = seconds % SECONDS_DAY; - - cmos->hour = int_to_bcd(seconds / 3600); - seconds = seconds % 3600; - - cmos->minute = int_to_bcd(seconds / 60); - seconds = seconds % 60; - - cmos->second = int_to_bcd(seconds); + cmos->month = int_to_bcd(t.tm_mon + 1); + cmos->day = int_to_bcd(t.tm_mday); + cmos->hour = int_to_bcd(t.tm_hour); + cmos->minute = int_to_bcd(t.tm_min); + cmos->second = int_to_bcd(t.tm_sec); } diff --git a/src/system/kernel/real_time_clock.c b/src/system/kernel/real_time_clock.c index d7ced8bd34..8093d886d7 100644 --- a/src/system/kernel/real_time_clock.c +++ b/src/system/kernel/real_time_clock.c @@ -155,6 +155,136 @@ get_rtc_info(rtc_info *info) } +// #pragma mark - + + +#define SECONDS_31 2678400 +#define SECONDS_30 2592000 +#define SECONDS_28 2419200 +#define SECONDS_DAY 86400 + +static uint32 sSecsPerMonth[12] = {SECONDS_31, SECONDS_28, SECONDS_31, SECONDS_30, + SECONDS_31, SECONDS_30, SECONDS_31, SECONDS_31, SECONDS_30, SECONDS_31, SECONDS_30, + SECONDS_31}; + + +static bool +leap_year(uint32 year) +{ + if (year % 400 == 0) + return true; + + if (year % 100 == 0) + return false; + + if (year % 4 == 0) + return true; + + return false; +} + + +static inline uint32 +secs_this_year(uint32 year) +{ + if (leap_year(year)) + return 31622400; + + return 31536000; +} + + +uint32 +rtc_tm_to_secs(const struct tm *t) +{ + uint32 wholeYear; + uint32 time = 0; + uint32 i; + + wholeYear = 1900 + t->tm_year; + + // ToDo: get rid of these loops and compute the correct value + // i.e. days = (long)(year > 0) + year*365 + --year/4 - year/100 + year/400; + // let sSecsPerMonth[] have the values already added up + + // Add up the seconds from all years since 1970 that have elapsed. + for (i = RTC_EPOCHE_BASE_YEAR; i < wholeYear; ++i) { + time += secs_this_year(i); + } + + // Add up the seconds from all months passed this year. + for (i = 0; i < t->tm_mon && i < 12; ++i) + time += sSecsPerMonth[i]; + + // Add up the seconds from all days passed this month. + if (leap_year(wholeYear) && t->tm_mon >= 2) + time += SECONDS_DAY; + + time += (t->tm_mday - 1) * SECONDS_DAY; + time += t->tm_hour * 3600; + time += t->tm_min * 60; + time += t->tm_sec; + + return time; +} + + +void +rtc_secs_to_tm(uint32 seconds, struct tm *t) +{ + uint32 wholeYear = RTC_EPOCHE_BASE_YEAR; + uint32 secsThisYear; + bool keepLooping; + bool isLeapYear; + int temp; + int month; + + keepLooping = 1; + + // Determine the current year by starting at 1970 and incrementing whole_year as long as + // we can keep subtracting secs_this_year from seconds. + while (keepLooping) { + secsThisYear = secs_this_year(wholeYear); + + if (seconds >= secsThisYear) { + seconds -= secsThisYear; + ++wholeYear; + } else + keepLooping = false; + } + + t->tm_year = wholeYear - RTC_EPOCHE_BASE_YEAR; + + // Determine the current month + month = 0; + isLeapYear = leap_year(wholeYear); + do { + temp = seconds - sSecsPerMonth[month]; + + if (isLeapYear && month == 1) + temp -= SECONDS_DAY; + + if (temp >= 0) { + seconds = temp; + ++month; + } + } while (temp >= 0 && month < 12); + + t->tm_mon = month; + + t->tm_mday = seconds / SECONDS_DAY + 1; + seconds = seconds % SECONDS_DAY; + + t->tm_hour = seconds / 3600; + seconds = seconds % 3600; + + t->tm_min = seconds / 60; + seconds = seconds % 60; + + t->tm_sec = seconds; +} + + // #pragma mark - // public userland API