diff options
Diffstat (limited to 'sys/i386/isa/clock.c')
-rw-r--r-- | sys/i386/isa/clock.c | 206 |
1 files changed, 136 insertions, 70 deletions
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index 3e25aa5e7782..1835e22700e9 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -34,7 +34,14 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.18 1994/09/18 20:39:42 wollman Exp $ + * $Id: clock.c,v 1.19 1994/09/18 23:08:55 bde Exp $ + */ + + /* + * inittodr, settodr and support routines written + * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at> + * + * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94 */ /* @@ -55,6 +62,7 @@ * can use a simple formula for leap years. */ #define LEAPYEAR(y) ((u_int)(y) % 4 == 0) +#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) /* X-tals being what they are, it's nice to be able to fudge this one... */ /* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */ @@ -73,6 +81,7 @@ static void (*timer_func)() = hardclock; static void (*new_function)(); static u_int new_rate; static u_int hardclock_divisor; +static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; #ifdef I586_CPU int pentium_mhz = 0; @@ -345,6 +354,35 @@ sysbeep(int pitch, int period) } +/* + * RTC support routines + */ +static int +bcd2int(int bcd) +{ + return(bcd/16 * 10 + bcd%16); +} + +static int +int2bcd(int dez) +{ + return(dez/10 * 16 + dez%10); +} + +static void +writertc(int port, int val) +{ + outb(IO_RTC, port); + outb(IO_RTC+1, val); +} + +static int +readrtc(int port) +{ + return(bcd2int(rtcin(port))); +} + + void startrtclock() { @@ -367,88 +405,116 @@ startrtclock() outb (IO_RTC, RTC_DIAG); if (s = inb (IO_RTC+1)) printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); + writertc(RTC_DIAG, 0); } -/* convert 2 digit BCD number */ -int -bcd(int i) -{ - return ((i/16)*10 + (i%16)); -} - - -/* convert years to seconds (from 1970) */ -unsigned long -ytos(int y) +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +void +inittodr(base) +time_t base; { - int i; - unsigned long ret; + unsigned long sec, days; + int yd; + int year, month; + int y, m, s; + + s = splclock(); + time.tv_sec = base; + time.tv_usec = 0; + splx(s); + + /* Look if we have a RTC present and the time is valid */ + if (rtcin(RTC_STATUSD) != RTCSD_PWR) + goto wrong_time; + + /* wait for time update to complete */ + /* If RTCSA_TUP is zero, we have at least 244us before next update */ + while (rtcin(RTC_STATUSA) & RTCSA_TUP); + + days = 0; + year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100; + if (year < 1970) + goto wrong_time; + month = readrtc(RTC_MONTH); + for (m = 1; m < month; m++) + days += daysinmonth[m-1]; + if ((month > 2) && LEAPYEAR(year)) + days ++; + days += readrtc(RTC_DAY) - 1; + yd = days; + for (y = 1970; y < year; y++) + days += DAYSPERYEAR + LEAPYEAR(y); + sec = ((( days * 24 + + readrtc(RTC_HRS)) * 60 + + readrtc(RTC_MIN)) * 60 + + readrtc(RTC_SEC)); + /* sec now contains the number of seconds, since Jan 1 1970, + in the local time zone */ - ret = 0; - for(i = 1970; i < y; i++) { - if (i % 4) ret += 365*24*60*60; - else ret += 366*24*60*60; - } - return ret; -} + sec += tz.tz_minuteswest * 60; + s = splclock(); + time.tv_sec = sec; + splx(s); + return; -/* convert months to seconds */ -unsigned long -mtos(int m, int leap) -{ - int i; - unsigned long ret; - - ret = 0; - for(i=1; i<m; i++) { - switch(i){ - case 1: case 3: case 5: case 7: case 8: case 10: case 12: - ret += 31*24*60*60; break; - case 4: case 6: case 9: case 11: - ret += 30*24*60*60; break; - case 2: - if (leap) ret += 29*24*60*60; - else ret += 28*24*60*60; - } - } - return ret; +wrong_time: + printf("Invalid time in real time clock.\n"); + printf("Check and reset the date immediately!\n"); } /* - * Initialize the time of day register, based on the time base which is, e.g. - * from a filesystem. + * Write system time back to RTC */ -void -inittodr(time_t base) +void resettodr() { - unsigned long sec; - int leap, day_week, t, yd; - int sa,s; - - /* do we have a realtime clock present? (otherwise we loop below) */ - sa = rtcin(RTC_STATUSA); - if (sa == 0xff || sa == 0) return; - - /* ready for a read? */ - while ((sa&RTCSA_TUP) == RTCSA_TUP) - sa = rtcin(RTC_STATUSA); - - sec = bcd(rtcin(RTC_YEAR)) + 1900; - if (sec < 1970) - sec += 100; - - leap = LEAPYEAR(sec); sec = ytos(sec); /* year */ - yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */ - t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */ - day_week = rtcin(RTC_WDAY); /* day */ - sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ - sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ - sec += bcd(rtcin(RTC_SEC)); /* seconds */ - sec += tz.tz_minuteswest * 60; - time.tv_sec = sec; + unsigned long tm; + int y, m, fd, r, s; + + s = splclock(); + tm = time.tv_sec; + splx(s); + +/* First, disable clock updates */ + writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); + + /* Calculate local time to put in CMOS */ + + tm -= tz.tz_minuteswest * 60 + adjkerntz; + + writertc(RTC_SEC, int2bcd(tm%60)); tm /= 60; /* Write back Seconds */ + writertc(RTC_MIN, int2bcd(tm%60)); tm /= 60; /* Write back Minutes */ + writertc(RTC_HRS, int2bcd(tm%24)); tm /= 24; /* Write back Hours */ + + /* We have now the days since 01-01-1970 in tm */ + writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */ + for (y=1970;; y++) + if ((tm - DAYSPERYEAR - LEAPYEAR(y)) > tm) + break; + else + tm -= DAYSPERYEAR + LEAPYEAR(y); + + /* Now we have the years in y and the day-of-the-year in tm */ + writertc(RTC_YEAR, int2bcd(y%100)); /* Write back Year */ + writertc(RTC_CENTURY, int2bcd(y/100)); /* ... and Century */ + if (LEAPYEAR(y) && (tm >= 31+29)) + tm--; /* Subtract Feb-29 */ + for (m=1;; m++) + if (tm - daysinmonth[m-1] > tm) + break; + else + tm -= daysinmonth[m-1]; + + writertc(RTC_MONTH, int2bcd(m)); /* Write back Month */ + writertc(RTC_DAY, int2bcd(tm+1)); /* Write back Day */ + + /* enable time updates */ + writertc(RTC_STATUSB, RTCSB_24HR); } |