X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=bootcensus;a=blobdiff_plain;f=src%2Frtc.c;fp=src%2Frtc.c;h=40eca9adfe5640a16d0b3070a72f9a6a5a316352;hp=0000000000000000000000000000000000000000;hb=78e3e75fc7b5838d0261c876d00e1b8c3e0bcfe0;hpb=7b6f6de2124e28ae7da5599a7cdaf2c171c4f15e diff --git a/src/rtc.c b/src/rtc.c new file mode 100644 index 0000000..40eca9a --- /dev/null +++ b/src/rtc.c @@ -0,0 +1,123 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018-2019 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include +#include +#include "rtc.h" + +/* CMOS I/O ports */ +#define PORT_CTL 0x70 +#define PORT_DATA 0x71 + +/* CMOS RTC registers */ +#define REG_SEC 0 +#define REG_ALARM_SEC 1 +#define REG_MIN 2 +#define REG_ALARM_MIN 3 +#define REG_HOUR 4 +#define REG_ALARM_HOUR 5 +#define REG_WEEKDAY 6 +#define REG_DAY 7 +#define REG_MONTH 8 +#define REG_YEAR 9 +#define REG_STATA 10 +#define REG_STATB 11 +#define REG_STATC 12 +#define REG_STATD 13 + +#define STATA_BUSY (1 << 7) +#define STATB_24HR (1 << 1) +#define STATB_BIN (1 << 2) + +#define HOUR_PM_BIT (1 << 7) + +#define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf)) + +static void read_rtc(struct tm *tm); +static int read_reg(int reg); + + +void init_rtc(void) +{ + struct tm tm; + + read_rtc(&tm); + start_time = mktime(&tm); + + printf("System real-time clock: %s", asctime(&tm)); +} + + +static void read_rtc(struct tm *tm) +{ + int statb, pm; + + /* wait for any clock updates to finish */ + while(read_reg(REG_STATA) & STATA_BUSY); + + tm->tm_sec = read_reg(REG_SEC); + tm->tm_min = read_reg(REG_MIN); + tm->tm_hour = read_reg(REG_HOUR); + tm->tm_mday = read_reg(REG_DAY); + tm->tm_mon = read_reg(REG_MONTH); + tm->tm_year = read_reg(REG_YEAR); + + /* in 12hour mode, bit 7 means post-meridiem */ + pm = tm->tm_hour & HOUR_PM_BIT; + tm->tm_hour &= ~HOUR_PM_BIT; + + /* convert to binary if needed */ + statb = read_reg(REG_STATB); + if(!(statb & STATB_BIN)) { + tm->tm_sec = BCD_TO_BIN(tm->tm_sec); + tm->tm_min = BCD_TO_BIN(tm->tm_min); + tm->tm_hour = BCD_TO_BIN(tm->tm_hour); + tm->tm_mday = BCD_TO_BIN(tm->tm_mday); + tm->tm_mon = BCD_TO_BIN(tm->tm_mon); + tm->tm_year = BCD_TO_BIN(tm->tm_year); + } + + /* make the year an offset from 1900 */ + if(tm->tm_year < 100) { + tm->tm_year += 100; + } else { + tm->tm_year -= 1900; + } + + /* if tm_hour is in 12h mode, convert to 24h */ + if(!(statb & STATB_24HR)) { + if(tm->tm_hour == 12) { + tm->tm_hour = 0; + } + if(pm) { + tm->tm_hour += 12; + } + } + + tm->tm_mon -= 1; /* we want months to start from 0 */ +} + +static int read_reg(int reg) +{ + unsigned char val; + outb(reg, PORT_CTL); + iodelay(); + val = inb(PORT_DATA); + iodelay(); + return val; +}