diff options
author | Andrey A. Chernov <ache@FreeBSD.org> | 1994-09-20 00:31:07 +0000 |
---|---|---|
committer | Andrey A. Chernov <ache@FreeBSD.org> | 1994-09-20 00:31:07 +0000 |
commit | 7b915aa63189e6fc7bd9d37889f064c85c17150d (patch) | |
tree | f6cb5cf468b4233a662fca5b6446ef05eb04cdee /sys | |
parent | 736c101eaf3b4e0f80632f8a20d0a4ed0665f0d8 (diff) | |
download | src-7b915aa63189e6fc7bd9d37889f064c85c17150d.tar.gz src-7b915aa63189e6fc7bd9d37889f064c85c17150d.zip |
resettodr() implemented, inittodr() fixed
Submitted by: me & chris@gnome.co.uk
Notes
Notes:
svn path=/head/; revision=2913
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/tsc.c | 206 | ||||
-rw-r--r-- | sys/amd64/isa/clock.c | 206 | ||||
-rw-r--r-- | sys/i386/i386/tsc.c | 206 | ||||
-rw-r--r-- | sys/i386/isa/clock.c | 206 | ||||
-rw-r--r-- | sys/i386/isa/rtc.h | 13 | ||||
-rw-r--r-- | sys/isa/atrtc.c | 206 | ||||
-rw-r--r-- | sys/isa/rtc.h | 13 |
7 files changed, 698 insertions, 358 deletions
diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c index 3e25aa5e7782..1835e22700e9 100644 --- a/sys/amd64/amd64/tsc.c +++ b/sys/amd64/amd64/tsc.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); } diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index 3e25aa5e7782..1835e22700e9 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/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); } diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c index 3e25aa5e7782..1835e22700e9 100644 --- a/sys/i386/i386/tsc.c +++ b/sys/i386/i386/tsc.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); } 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); } diff --git a/sys/i386/isa/rtc.h b/sys/i386/isa/rtc.h index 9c0f501e6175..d374a823d7c2 100644 --- a/sys/i386/isa/rtc.h +++ b/sys/i386/isa/rtc.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91 - * $Id: rtc.h,v 1.4 1993/12/18 01:12:47 ache Exp $ + * $Id: rtc.h,v 1.5 1994/08/15 03:15:20 wollman Exp $ */ #ifndef _I386_ISA_RTC_H_ @@ -73,9 +73,14 @@ #define RTCSA_32 0x0b #define RTC_STATUSB 0x0b /* status register B */ +#define RTCSB_DST 0x01 /* Daylight Savings Time enable */ +#define RTCSB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */ +#define RTCSB_BCD 0x04 /* 0 = BCD, 1 = Binary coded time */ +#define RTCSB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */ +#define RTCSB_UINTR 0x10 /* 1 = enable update-ended interrupt */ +#define RTCSB_AINTR 0x20 /* 1 = enable alarm interrupt */ +#define RTCSB_PINTR 0x40 /* 1 = enable periodic clock interrupt */ #define RTCSB_HALT 0x80 /* stop clock updates */ -#define RTCSB_PINTR 0x40 /* periodic clock interrupt */ -#define RTCSB_24HR 0x02 /* 24-hour mode */ #define RTC_INTR 0x0c /* status register C (R) interrupt source */ #define RTCIR_UPDATE 0x10 /* update intr */ @@ -105,5 +110,5 @@ #define RTC_EXTLO 0x17 /* low byte of extended mem size */ #define RTC_EXTHI 0x18 /* low byte of extended mem size */ -#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/ +#define RTC_CENTURY 0x32 /* current century */ #endif /* _I386_ISA_RTC_H_ */ diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c index 3e25aa5e7782..1835e22700e9 100644 --- a/sys/isa/atrtc.c +++ b/sys/isa/atrtc.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); } diff --git a/sys/isa/rtc.h b/sys/isa/rtc.h index 9c0f501e6175..d374a823d7c2 100644 --- a/sys/isa/rtc.h +++ b/sys/isa/rtc.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91 - * $Id: rtc.h,v 1.4 1993/12/18 01:12:47 ache Exp $ + * $Id: rtc.h,v 1.5 1994/08/15 03:15:20 wollman Exp $ */ #ifndef _I386_ISA_RTC_H_ @@ -73,9 +73,14 @@ #define RTCSA_32 0x0b #define RTC_STATUSB 0x0b /* status register B */ +#define RTCSB_DST 0x01 /* Daylight Savings Time enable */ +#define RTCSB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */ +#define RTCSB_BCD 0x04 /* 0 = BCD, 1 = Binary coded time */ +#define RTCSB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */ +#define RTCSB_UINTR 0x10 /* 1 = enable update-ended interrupt */ +#define RTCSB_AINTR 0x20 /* 1 = enable alarm interrupt */ +#define RTCSB_PINTR 0x40 /* 1 = enable periodic clock interrupt */ #define RTCSB_HALT 0x80 /* stop clock updates */ -#define RTCSB_PINTR 0x40 /* periodic clock interrupt */ -#define RTCSB_24HR 0x02 /* 24-hour mode */ #define RTC_INTR 0x0c /* status register C (R) interrupt source */ #define RTCIR_UPDATE 0x10 /* update intr */ @@ -105,5 +110,5 @@ #define RTC_EXTLO 0x17 /* low byte of extended mem size */ #define RTC_EXTHI 0x18 /* low byte of extended mem size */ -#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/ +#define RTC_CENTURY 0x32 /* current century */ #endif /* _I386_ISA_RTC_H_ */ |