Module Name: src
Committed By: bouyer
Date: Tue Jun 16 21:05:35 UTC 2009
Modified Files:
src/sys/arch/amd64/conf: files.amd64
src/sys/arch/i386/conf: files.i386
src/sys/arch/x86/isa: clock.c
src/sys/arch/xen/conf: files.xen
src/sys/arch/xen/xen: clock.c
Added Files:
src/sys/arch/x86/include: rtc.h
src/sys/arch/x86/isa: rtc.c
Log Message:
Split mc146818-related functions from clock.c into rtc.c.
Call rtc_set_ymdhms() from xen/xen/clock.c:xen_rtc_set() for xen3 dom0
kernels as the Xen3 hypervisor doesn't write the new date/time to the CMOS
by itself.
Now a XEN3_DOM0 kernel properly updates the CMOS time.
To generate a diff of this commit:
cvs rdiff -u -r1.67 -r1.68 src/sys/arch/amd64/conf/files.amd64
cvs rdiff -u -r1.349 -r1.350 src/sys/arch/i386/conf/files.i386
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/include/rtc.h
cvs rdiff -u -r1.32 -r1.33 src/sys/arch/x86/isa/clock.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/isa/rtc.c
cvs rdiff -u -r1.99 -r1.100 src/sys/arch/xen/conf/files.xen
cvs rdiff -u -r1.49 -r1.50 src/sys/arch/xen/xen/clock.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/amd64/conf/files.amd64
diff -u src/sys/arch/amd64/conf/files.amd64:1.67 src/sys/arch/amd64/conf/files.amd64:1.68
--- src/sys/arch/amd64/conf/files.amd64:1.67 Tue Apr 21 03:00:29 2009
+++ src/sys/arch/amd64/conf/files.amd64 Tue Jun 16 21:05:33 2009
@@ -1,4 +1,4 @@
-# $NetBSD: files.amd64,v 1.67 2009/04/21 03:00:29 nonaka Exp $
+# $NetBSD: files.amd64,v 1.68 2009/06/16 21:05:33 bouyer Exp $
#
# new style config file for amd64 architecture
#
@@ -107,6 +107,7 @@
# PC clock
file arch/x86/isa/clock.c isa
+file arch/x86/isa/rtc.c isa
# TSC timecounter support
file arch/x86/x86/tsc.c
Index: src/sys/arch/i386/conf/files.i386
diff -u src/sys/arch/i386/conf/files.i386:1.349 src/sys/arch/i386/conf/files.i386:1.350
--- src/sys/arch/i386/conf/files.i386:1.349 Tue Apr 21 03:00:29 2009
+++ src/sys/arch/i386/conf/files.i386 Tue Jun 16 21:05:33 2009
@@ -1,4 +1,4 @@
-# $NetBSD: files.i386,v 1.349 2009/04/21 03:00:29 nonaka Exp $
+# $NetBSD: files.i386,v 1.350 2009/06/16 21:05:33 bouyer Exp $
#
# new style config file for i386 architecture
#
@@ -243,6 +243,7 @@
# PC clock
file arch/x86/isa/clock.c isa
+file arch/x86/isa/rtc.c isa
# TSC support
file arch/x86/x86/tsc.c
Index: src/sys/arch/x86/isa/clock.c
diff -u src/sys/arch/x86/isa/clock.c:1.32 src/sys/arch/x86/isa/clock.c:1.33
--- src/sys/arch/x86/isa/clock.c:1.32 Tue Apr 7 17:51:46 2009
+++ src/sys/arch/x86/isa/clock.c Tue Jun 16 21:05:34 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: clock.c,v 1.32 2009/04/07 17:51:46 dyoung Exp $ */
+/* $NetBSD: clock.c,v 1.33 2009/06/16 21:05:34 bouyer Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@@ -121,7 +121,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.32 2009/04/07 17:51:46 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.33 2009/06/16 21:05:34 bouyer Exp $");
/* #define CLOCKDEBUG */
/* #define CLOCK_PARANOIA */
@@ -150,8 +150,8 @@
#include <i386/isa/nvram.h>
#include <x86/x86/tsc.h>
#include <x86/lock.h>
-#include <dev/clock_subr.h>
#include <machine/specialreg.h>
+#include <x86/rtc.h>
#ifndef __x86_64__
#include "mca.h"
@@ -189,13 +189,7 @@
static void tickle_tc(void);
static int clockintr(void *, struct intrframe *);
-static void rtcinit(void);
-static int rtcget(mc_todregs *);
-static void rtcput(mc_todregs *);
-static int cmoscheck(void);
-
-static int clock_expandyear(int);
int sysbeepdetach(device_t, int);
static unsigned int gettick_broken_latch(void);
@@ -207,11 +201,7 @@
/* to protect TC timer variables */
static __cpu_simple_lock_t tmr_lock = __SIMPLELOCK_UNLOCKED;
-inline u_int mc146818_read(void *, u_int);
-inline void mc146818_write(void *, u_int, u_int);
-
u_int i8254_get_timecount(struct timecounter *);
-static void rtc_register(void);
static struct timecounter i8254_timecounter = {
i8254_get_timecount, /* get_timecount */
@@ -224,24 +214,6 @@
NULL, /* next */
};
-/* XXX use sc? */
-inline u_int
-mc146818_read(void *sc, u_int reg)
-{
-
- outb(IO_RTC, reg);
- return (inb(IO_RTC+1));
-}
-
-/* XXX use sc? */
-inline void
-mc146818_write(void *sc, u_int reg, u_int datum)
-{
-
- outb(IO_RTC, reg);
- outb(IO_RTC+1, datum);
-}
-
u_long rtclock_tval; /* i8254 reload value for countdown */
int rtclock_init = 0;
@@ -585,214 +557,6 @@
(int (*)(void *))clockintr, 0);
}
-static void
-rtcinit(void)
-{
- static int first_rtcopen_ever = 1;
-
- if (!first_rtcopen_ever)
- return;
- first_rtcopen_ever = 0;
-
- mc146818_write(NULL, MC_REGA, /* XXX softc */
- MC_BASE_32_KHz | MC_RATE_1024_Hz);
- mc146818_write(NULL, MC_REGB, MC_REGB_24HR); /* XXX softc */
-}
-
-static int
-rtcget(mc_todregs *regs)
-{
-
- rtcinit();
- if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
- return (-1);
- MC146818_GETTOD(NULL, regs); /* XXX softc */
- return (0);
-}
-
-static void
-rtcput(mc_todregs *regs)
-{
-
- rtcinit();
- MC146818_PUTTOD(NULL, regs); /* XXX softc */
-}
-
-/*
- * check whether the CMOS layout is "standard"-like (ie, not PS/2-like),
- * to be called at splclock()
- */
-static int
-cmoscheck(void)
-{
- int i;
- unsigned short cksum = 0;
-
- for (i = 0x10; i <= 0x2d; i++)
- cksum += mc146818_read(NULL, i); /* XXX softc */
-
- return (cksum == (mc146818_read(NULL, 0x2e) << 8)
- + mc146818_read(NULL, 0x2f));
-}
-
-#if NMCA > 0
-/*
- * Check whether the CMOS layout is PS/2 like, to be called at splclock().
- */
-static int cmoscheckps2(void);
-static int
-cmoscheckps2(void)
-{
-#if 0
- /* Disabled until I find out the CRC checksum algorithm IBM uses */
- int i;
- unsigned short cksum = 0;
-
- for (i = 0x10; i <= 0x31; i++)
- cksum += mc146818_read(NULL, i); /* XXX softc */
-
- return (cksum == (mc146818_read(NULL, 0x32) << 8)
- + mc146818_read(NULL, 0x33));
-#else
- /* Check 'incorrect checksum' bit of IBM PS/2 Diagnostic Status Byte */
- return ((mc146818_read(NULL, NVRAM_DIAG) & (1<<6)) == 0);
-#endif
-}
-#endif /* NMCA > 0 */
-
-/*
- * patchable to control century byte handling:
- * 1: always update
- * -1: never touch
- * 0: try to figure out itself
- */
-int rtc_update_century = 0;
-
-/*
- * Expand a two-digit year as read from the clock chip
- * into full width.
- * Being here, deal with the CMOS century byte.
- */
-static int centb = NVRAM_CENTURY;
-static int
-clock_expandyear(int clockyear)
-{
- int s, clockcentury, cmoscentury;
-
- clockcentury = (clockyear < 70) ? 20 : 19;
- clockyear += 100 * clockcentury;
-
- if (rtc_update_century < 0)
- return (clockyear);
-
- s = splclock();
- if (cmoscheck())
- cmoscentury = mc146818_read(NULL, NVRAM_CENTURY);
-#if NMCA > 0
- else if (MCA_system && cmoscheckps2())
- cmoscentury = mc146818_read(NULL, (centb = 0x37));
-#endif
- else
- cmoscentury = 0;
- splx(s);
- if (!cmoscentury) {
-#ifdef DIAGNOSTIC
- printf("clock: unknown CMOS layout\n");
-#endif
- return (clockyear);
- }
- cmoscentury = bcdtobin(cmoscentury);
-
- if (cmoscentury != clockcentury) {
- /* XXX note: saying "century is 20" might confuse the naive. */
- printf("WARNING: NVRAM century is %d but RTC year is %d\n",
- cmoscentury, clockyear);
-
- /* Kludge to roll over century. */
- if ((rtc_update_century > 0) ||
- ((cmoscentury == 19) && (clockcentury == 20) &&
- (clockyear == 2000))) {
- printf("WARNING: Setting NVRAM century to %d\n",
- clockcentury);
- s = splclock();
- mc146818_write(NULL, centb, bintobcd(clockcentury));
- splx(s);
- }
- } else if (cmoscentury == 19 && rtc_update_century == 0)
- rtc_update_century = 1; /* will update later in resettodr() */
-
- return (clockyear);
-}
-
-static int
-rtc_get_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
-{
- int s;
- mc_todregs rtclk;
-
- s = splclock();
- if (rtcget(&rtclk)) {
- splx(s);
- return -1;
- }
- splx(s);
-
- dt->dt_sec = bcdtobin(rtclk[MC_SEC]);
- dt->dt_min = bcdtobin(rtclk[MC_MIN]);
- dt->dt_hour = bcdtobin(rtclk[MC_HOUR]);
- dt->dt_day = bcdtobin(rtclk[MC_DOM]);
- dt->dt_mon = bcdtobin(rtclk[MC_MONTH]);
- dt->dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR]));
-
- return 0;
-}
-
-static int
-rtc_set_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
-{
- mc_todregs rtclk;
- int century;
- int s;
-
- s = splclock();
- if (rtcget(&rtclk))
- memset(&rtclk, 0, sizeof(rtclk));
- splx(s);
-
- rtclk[MC_SEC] = bintobcd(dt->dt_sec);
- rtclk[MC_MIN] = bintobcd(dt->dt_min);
- rtclk[MC_HOUR] = bintobcd(dt->dt_hour);
- rtclk[MC_DOW] = dt->dt_wday + 1;
- rtclk[MC_YEAR] = bintobcd(dt->dt_year % 100);
- rtclk[MC_MONTH] = bintobcd(dt->dt_mon);
- rtclk[MC_DOM] = bintobcd(dt->dt_day);
-
-#ifdef DEBUG_CLOCK
- printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH],
- rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]);
-#endif
- s = splclock();
- rtcput(&rtclk);
- if (rtc_update_century > 0) {
- century = bintobcd(dt->dt_year / 100);
- mc146818_write(NULL, centb, century); /* XXX softc */
- }
- splx(s);
- return 0;
-
-}
-
-static void
-rtc_register(void)
-{
- static struct todr_chip_handle tch;
- tch.todr_gettime_ymdhms = rtc_get_ymdhms;
- tch.todr_settime_ymdhms = rtc_set_ymdhms;
- tch.todr_setwen = NULL;
-
- todr_attach(&tch);
-}
-
void
setstatclockrate(int arg)
{
Index: src/sys/arch/xen/conf/files.xen
diff -u src/sys/arch/xen/conf/files.xen:1.99 src/sys/arch/xen/conf/files.xen:1.100
--- src/sys/arch/xen/conf/files.xen:1.99 Thu Apr 30 04:38:01 2009
+++ src/sys/arch/xen/conf/files.xen Tue Jun 16 21:05:34 2009
@@ -1,4 +1,4 @@
-# $NetBSD: files.xen,v 1.99 2009/04/30 04:38:01 pgoyette Exp $
+# $NetBSD: files.xen,v 1.100 2009/06/16 21:05:34 bouyer Exp $
# NetBSD: files.x86,v 1.10 2003/10/08 17:30:00 bouyer Exp
# NetBSD: files.i386,v 1.254 2004/03/25 23:32:10 jmc Exp
@@ -94,6 +94,7 @@
file arch/xen/xen/xen_debug.c
file arch/xen/xen/clock.c
+file arch/x86/isa/rtc.c xen3 & dom0ops
file arch/xen/xen/evtchn.c
file arch/xen/xen/ctrl_if.c !xen3
Index: src/sys/arch/xen/xen/clock.c
diff -u src/sys/arch/xen/xen/clock.c:1.49 src/sys/arch/xen/xen/clock.c:1.50
--- src/sys/arch/xen/xen/clock.c:1.49 Fri Jan 16 20:16:47 2009
+++ src/sys/arch/xen/xen/clock.c Tue Jun 16 21:05:35 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: clock.c,v 1.49 2009/01/16 20:16:47 jym Exp $ */
+/* $NetBSD: clock.c,v 1.50 2009/06/16 21:05:35 bouyer Exp $ */
/*
*
@@ -34,7 +34,7 @@
#include "opt_xen.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.49 2009/01/16 20:16:47 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.50 2009/06/16 21:05:35 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -51,6 +51,7 @@
#include <machine/cpu_counter.h>
#include <dev/clock_subr.h>
+#include <x86/rtc.h>
static int xen_timer_handler(void *, struct intrframe *);
@@ -316,6 +317,13 @@
int s;
if (xendomain_is_privileged()) {
+#ifdef XEN3
+ /* needs to set the RTC chip too */
+ struct clock_ymdhms dt;
+ clock_secs_to_ymdhms(tvp->tv_sec, &dt);
+ rtc_set_ymdhms(NULL, &dt);
+#endif
+
#if __XEN_INTERFACE_VERSION__ < 0x00030204
op.cmd = DOM0_SETTIME;
#else
@@ -332,9 +340,9 @@
op.u.settime.system_time = get_system_time();
splx(s);
#if __XEN_INTERFACE_VERSION__ < 0x00030204
- HYPERVISOR_dom0_op(&op);
+ return HYPERVISOR_dom0_op(&op);
#else
- HYPERVISOR_platform_op(&op);
+ return HYPERVISOR_platform_op(&op);
#endif
}
#endif
Added files:
Index: src/sys/arch/x86/include/rtc.h
diff -u /dev/null src/sys/arch/x86/include/rtc.h:1.1
--- /dev/null Tue Jun 16 21:05:35 2009
+++ src/sys/arch/x86/include/rtc.h Tue Jun 16 21:05:34 2009
@@ -0,0 +1,7 @@
+/* $NetBSD: rtc.h,v 1.1 2009/06/16 21:05:34 bouyer Exp $ */
+
+#include <dev/clock_subr.h>
+
+void rtc_register(void);
+int rtc_get_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
+int rtc_set_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
Index: src/sys/arch/x86/isa/rtc.c
diff -u /dev/null src/sys/arch/x86/isa/rtc.c:1.1
--- /dev/null Tue Jun 16 21:05:35 2009
+++ src/sys/arch/x86/isa/rtc.c Tue Jun 16 21:05:34 2009
@@ -0,0 +1,378 @@
+/* $NetBSD: rtc.c,v 1.1 2009/06/16 21:05:34 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 7.2 (Berkeley) 5/12/91
+ */
+/*-
+ * Copyright (c) 1993, 1994 Charles M. Hannum.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 7.2 (Berkeley) 5/12/91
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or [email protected]
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * Primitive RTC chip routines.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.1 2009/06/16 21:05:34 bouyer Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/kernel.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+#include <i386/isa/nvram.h>
+
+#include <machine/pio.h>
+
+#include <dev/ic/mc146818reg.h>
+#include <x86/rtc.h>
+
+#ifndef __x86_64__
+#include "mca.h"
+#endif
+#if NMCA > 0
+#include <machine/mca_machdep.h> /* for MCA_system */
+#endif
+
+static void rtcinit(void);
+static int rtcget(mc_todregs *);
+static void rtcput(mc_todregs *);
+static int cmoscheck(void);
+static int clock_expandyear(int);
+
+/* XXX use sc? */
+u_int
+mc146818_read(void *sc, u_int reg)
+{
+
+ outb(IO_RTC, reg);
+ return (inb(IO_RTC+1));
+}
+
+void
+mc146818_write(void *sc, u_int reg, u_int datum)
+{
+
+ outb(IO_RTC, reg);
+ outb(IO_RTC+1, datum);
+}
+
+static void
+rtcinit(void)
+{
+ static int first_rtcopen_ever = 1;
+
+ if (!first_rtcopen_ever)
+ return;
+ first_rtcopen_ever = 0;
+
+ mc146818_write(NULL, MC_REGA, /* XXX softc */
+ MC_BASE_32_KHz | MC_RATE_1024_Hz);
+ mc146818_write(NULL, MC_REGB, MC_REGB_24HR); /* XXX softc */
+}
+
+static int
+rtcget(mc_todregs *regs)
+{
+
+ rtcinit();
+ if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
+ return (-1);
+ MC146818_GETTOD(NULL, regs); /* XXX softc */
+ return (0);
+}
+
+static void
+rtcput(mc_todregs *regs)
+{
+
+ rtcinit();
+ MC146818_PUTTOD(NULL, regs); /* XXX softc */
+}
+
+/*
+ * check whether the CMOS layout is "standard"-like (ie, not PS/2-like),
+ * to be called at splclock()
+ */
+static int
+cmoscheck(void)
+{
+ int i;
+ unsigned short cksum = 0;
+
+ for (i = 0x10; i <= 0x2d; i++)
+ cksum += mc146818_read(NULL, i); /* XXX softc */
+
+ return (cksum == (mc146818_read(NULL, 0x2e) << 8)
+ + mc146818_read(NULL, 0x2f));
+}
+
+#if NMCA > 0
+/*
+ * Check whether the CMOS layout is PS/2 like, to be called at splclock().
+ */
+static int cmoscheckps2(void);
+static int
+cmoscheckps2(void)
+{
+#if 0
+ /* Disabled until I find out the CRC checksum algorithm IBM uses */
+ int i;
+ unsigned short cksum = 0;
+
+ for (i = 0x10; i <= 0x31; i++)
+ cksum += mc146818_read(NULL, i); /* XXX softc */
+
+ return (cksum == (mc146818_read(NULL, 0x32) << 8)
+ + mc146818_read(NULL, 0x33));
+#else
+ /* Check 'incorrect checksum' bit of IBM PS/2 Diagnostic Status Byte */
+ return ((mc146818_read(NULL, NVRAM_DIAG) & (1<<6)) == 0);
+#endif
+}
+#endif /* NMCA > 0 */
+
+/*
+ * patchable to control century byte handling:
+ * 1: always update
+ * -1: never touch
+ * 0: try to figure out itself
+ */
+int rtc_update_century = 0;
+
+/*
+ * Expand a two-digit year as read from the clock chip
+ * into full width.
+ * Being here, deal with the CMOS century byte.
+ */
+static int centb = NVRAM_CENTURY;
+static int
+clock_expandyear(int clockyear)
+{
+ int s, clockcentury, cmoscentury;
+
+ clockcentury = (clockyear < 70) ? 20 : 19;
+ clockyear += 100 * clockcentury;
+
+ if (rtc_update_century < 0)
+ return (clockyear);
+
+ s = splclock();
+ if (cmoscheck())
+ cmoscentury = mc146818_read(NULL, NVRAM_CENTURY);
+#if NMCA > 0
+ else if (MCA_system && cmoscheckps2())
+ cmoscentury = mc146818_read(NULL, (centb = 0x37));
+#endif
+ else
+ cmoscentury = 0;
+ splx(s);
+ if (!cmoscentury) {
+#ifdef DIAGNOSTIC
+ printf("clock: unknown CMOS layout\n");
+#endif
+ return (clockyear);
+ }
+ cmoscentury = bcdtobin(cmoscentury);
+
+ if (cmoscentury != clockcentury) {
+ /* XXX note: saying "century is 20" might confuse the naive. */
+ printf("WARNING: NVRAM century is %d but RTC year is %d\n",
+ cmoscentury, clockyear);
+
+ /* Kludge to roll over century. */
+ if ((rtc_update_century > 0) ||
+ ((cmoscentury == 19) && (clockcentury == 20) &&
+ (clockyear == 2000))) {
+ printf("WARNING: Setting NVRAM century to %d\n",
+ clockcentury);
+ s = splclock();
+ mc146818_write(NULL, centb, bintobcd(clockcentury));
+ splx(s);
+ }
+ } else if (cmoscentury == 19 && rtc_update_century == 0)
+ rtc_update_century = 1; /* will update later in resettodr() */
+
+ return (clockyear);
+}
+
+int
+rtc_get_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
+{
+ int s;
+ mc_todregs rtclk;
+
+ s = splclock();
+ if (rtcget(&rtclk)) {
+ splx(s);
+ return -1;
+ }
+ splx(s);
+
+ dt->dt_sec = bcdtobin(rtclk[MC_SEC]);
+ dt->dt_min = bcdtobin(rtclk[MC_MIN]);
+ dt->dt_hour = bcdtobin(rtclk[MC_HOUR]);
+ dt->dt_day = bcdtobin(rtclk[MC_DOM]);
+ dt->dt_mon = bcdtobin(rtclk[MC_MONTH]);
+ dt->dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR]));
+
+ return 0;
+}
+
+int
+rtc_set_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
+{
+ mc_todregs rtclk;
+ int century;
+ int s;
+
+ s = splclock();
+ if (rtcget(&rtclk))
+ memset(&rtclk, 0, sizeof(rtclk));
+ splx(s);
+
+ rtclk[MC_SEC] = bintobcd(dt->dt_sec);
+ rtclk[MC_MIN] = bintobcd(dt->dt_min);
+ rtclk[MC_HOUR] = bintobcd(dt->dt_hour);
+ rtclk[MC_DOW] = dt->dt_wday + 1;
+ rtclk[MC_YEAR] = bintobcd(dt->dt_year % 100);
+ rtclk[MC_MONTH] = bintobcd(dt->dt_mon);
+ rtclk[MC_DOM] = bintobcd(dt->dt_day);
+
+#ifdef DEBUG_CLOCK
+ printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH],
+ rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]);
+#endif
+ s = splclock();
+ rtcput(&rtclk);
+ if (rtc_update_century > 0) {
+ century = bintobcd(dt->dt_year / 100);
+ mc146818_write(NULL, centb, century); /* XXX softc */
+ }
+ splx(s);
+ return 0;
+
+}
+
+void
+rtc_register(void)
+{
+ static struct todr_chip_handle tch;
+ tch.todr_gettime_ymdhms = rtc_get_ymdhms;
+ tch.todr_settime_ymdhms = rtc_set_ymdhms;
+ tch.todr_setwen = NULL;
+
+ todr_attach(&tch);
+}
+