#include "time.h" #include #include #include #include #define CMOS_WRITE_PORT 0x70 #define CMOS_READ_PORT 0x71 #define CMOS_REG_SEC 0x00 #define CMOS_REG_MIN 0x02 #define CMOS_REG_HOUR 0x04 #define CMOS_REG_WDAY 0x06 #define CMOS_REG_MDAY 0x07 #define CMOS_REG_MON 0x08 #define CMOS_REG_YEAR 0x09 #define CMOS_REG_CEN 0x32 // Live buffers to work on data static struct Time time; static struct Time localtime; // Front buffers so interupts dont request data that is half done static struct Time cur_time; static struct Time cur_localtime; // Current set Time Zone static enum Timezone last_timezone = UTC; static uint8_t cmos_read(uint8_t reg) { uint8_t hex, ret; outb(CMOS_WRITE_PORT, reg); hex = inb(CMOS_READ_PORT); ret = hex & 0x0F; ret += (hex & 0xF0) / 16 * 10; return ret; } static int mday_offset[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; static int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static void update_localtime(void) { int change, max; // set localtime localtime = time; // if tz is UTC, we dont need to do anythin if (last_timezone == UTC) return; localtime.hour += last_timezone; // check if day rolled over change = localtime.hour < 0 ? -1 : localtime.hour >= 24 ? 1 : 0; if (!change) return; // roll over day localtime.hour = (localtime.hour + 24) % 24; localtime.wday = (localtime.wday + change + 7) % 7; localtime.mday += change; localtime.yday += change; // check if month rolled over max = month_days[localtime.mon]; if (localtime.leap && localtime.mon == 1) max++; change = localtime.mday < 0 ? -1 : localtime.mday >= max ? 1 : 0; if (!change) return; // roll over month localtime.mon = (localtime.mon + change + 12) % 12; // check if year rolled over max = localtime.leap ? 366 : 365; change = localtime.yday < 0 ? -1 : localtime.yday >= max ? 1 : 0; if (!change) return; // roll over year localtime.yn += change; // check if cen rolled over change = localtime.yn < 0 ? -1 : localtime.yn >= 100 ? 1 : 0; if (!change) goto year; // roll over cen localtime.cen += change; year: localtime.year = localtime.yn + localtime.cen * 100; localtime.leap = localtime.year % 4 == 0 && localtime.year % 100 != 0; if (localtime.leap && localtime.yday == -1) localtime.yday = 365; else if (localtime.yday == -1) localtime.yday = 364; else localtime.yday = 0; localtime.year -= 1900; } void rtc_update(void) { time.sec = cmos_read(CMOS_REG_SEC); time.min = cmos_read(CMOS_REG_MIN); time.hour = cmos_read(CMOS_REG_HOUR); time.wday = cmos_read(CMOS_REG_WDAY) - 1; time.mday = cmos_read(CMOS_REG_MDAY); time.mon = cmos_read(CMOS_REG_MON) - 1; time.yn = cmos_read(CMOS_REG_YEAR); time.cen = 20; time.year = time.yn + time.cen * 100; time.leap = time.year % 4 == 0 && time.year % 100 != 0; time.yday = mday_offset[time.mon] + time.mday; if (time.leap && time.mon > 2) time.yday++; time.year -= 1900; update_localtime(); cur_time = time; cur_localtime = localtime; } struct Time rtc_utctime(void) { return cur_time; } struct Time rtc_localtime(enum Timezone tz) { if (tz != last_timezone) { last_timezone = tz; update_localtime(); cur_localtime = localtime; } return cur_localtime; }