aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAndrey A. Chernov <ache@FreeBSD.org>1994-09-20 00:31:07 +0000
committerAndrey A. Chernov <ache@FreeBSD.org>1994-09-20 00:31:07 +0000
commit7b915aa63189e6fc7bd9d37889f064c85c17150d (patch)
treef6cb5cf468b4233a662fca5b6446ef05eb04cdee /sys
parent736c101eaf3b4e0f80632f8a20d0a4ed0665f0d8 (diff)
downloadsrc-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.c206
-rw-r--r--sys/amd64/isa/clock.c206
-rw-r--r--sys/i386/i386/tsc.c206
-rw-r--r--sys/i386/isa/clock.c206
-rw-r--r--sys/i386/isa/rtc.h13
-rw-r--r--sys/isa/atrtc.c206
-rw-r--r--sys/isa/rtc.h13
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_ */