/* * http://wiki.osdev.org/OSDev_Wiki:General_disclaimer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "libsaio.h" #define CURRENT_YEAR 2012 // Change this each year! static int century_register = 0x00; // Set by ACPI table parsing code if possible(... in FADT table) enum { cmos_address = 0x70, cmos_data = 0x71 }; static int get_update_in_progress_flag() { outb(cmos_address, 0x0A); return (inb(cmos_data) & 0x80); } static unsigned char get_RTC_register(int reg) { outb(cmos_address, reg); return inb(cmos_data); } void rtc_read_clock(struct tm *time) { unsigned char century = 0; 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; unsigned char second; unsigned char minute; unsigned char hour; unsigned char day; unsigned char month; unsigned int year; // 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); } 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); } } // 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; if ((year += 1900) < 1970) year += 100; } time->tm_sec = second; time->tm_min = minute; time->tm_hour = hour; time->tm_mday = day; time->tm_mon = month; time->tm_year = year; }