Home | History | Annotate | Line # | Download | only in isa
isaclock.c revision 1.2
      1 /*	$NetBSD: isaclock.c,v 1.2 2001/07/22 15:04:00 wiz Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1993, 1994 Charles M. Hannum.
      5  * Copyright (c) 1990 The Regents of the University of California.
      6  * All rights reserved.
      7  *
      8  * This code is derived from software contributed to Berkeley by
      9  * William Jolitz and Don Ahn.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the University of
     22  *	California, Berkeley and its contributors.
     23  * 4. Neither the name of the University nor the names of its contributors
     24  *    may be used to endorse or promote products derived from this software
     25  *    without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     37  * SUCH DAMAGE.
     38  *
     39  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
     40  */
     41 /*
     42  * Mach Operating System
     43  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
     44  * All Rights Reserved.
     45  *
     46  * Permission to use, copy, modify and distribute this software and its
     47  * documentation is hereby granted, provided that both the copyright
     48  * notice and this permission notice appear in all copies of the
     49  * software, derivative works or modified versions, and any portions
     50  * thereof, and that both notices appear in supporting documentation.
     51  *
     52  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     53  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     54  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     55  *
     56  * Carnegie Mellon requests users of this software to return to
     57  *
     58  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     59  *  School of Computer Science
     60  *  Carnegie Mellon University
     61  *  Pittsburgh PA 15213-3890
     62  *
     63  * any improvements or extensions that they make and grant Carnegie Mellon
     64  * the rights to redistribute these changes.
     65  */
     66 /*
     67   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
     68 
     69 		All Rights Reserved
     70 
     71 Permission to use, copy, modify, and distribute this software and
     72 its documentation for any purpose and without fee is hereby
     73 granted, provided that the above copyright notice appears in all
     74 copies and that both the copyright notice and this permission notice
     75 appear in supporting documentation, and that the name of Intel
     76 not be used in advertising or publicity pertaining to distribution
     77 of the software without specific, written prior permission.
     78 
     79 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
     80 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
     81 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
     82 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
     83 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
     84 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
     85 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     86 */
     87 
     88 /*
     89  * Primitive clock interrupt routines.
     90  */
     91 #include <sys/param.h>
     92 #include <sys/systm.h>
     93 #include <sys/callout.h>
     94 #include <sys/time.h>
     95 #include <sys/kernel.h>
     96 #include <sys/device.h>
     97 
     98 #include <machine/cpu.h>
     99 #include <machine/intr.h>
    100 #include <machine/pio.h>
    101 
    102 #include <dev/isa/isareg.h>
    103 #include <dev/isa/isavar.h>
    104 #include <dev/ic/mc146818reg.h>
    105 #include <dev/ic/i8253reg.h>
    106 #include <sandpoint/isa/nvram.h>
    107 #include <sandpoint/isa/spkrreg.h>
    108 
    109 extern void disable_intr(void);	/* In locore.S */
    110 extern void enable_intr(void);	/* In locore.S */
    111 
    112 void	sysbeepstop __P((void *));
    113 void	sysbeep __P((int, int));
    114 void	rtcinit __P((void));
    115 int	rtcget __P((mc_todregs *));
    116 void	rtcput __P((mc_todregs *));
    117 static int yeartoday __P((int));
    118 int 	hexdectodec __P((int));
    119 int	dectohexdec __P((int));
    120 
    121 __inline u_int mc146818_read __P((void *, u_int));
    122 __inline void mc146818_write __P((void *, u_int, u_int));
    123 
    124 #define	SECMIN	((unsigned)60)			/* seconds per minute */
    125 #define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
    126 #define	SECDAY	((unsigned)(24*SECHOUR))	/* seconds per day */
    127 #define	SECYR	((unsigned)(365*SECDAY))	/* seconds per common year */
    128 
    129 __inline u_int
    130 mc146818_read(sc, reg)
    131 	void *sc;					/* XXX use it? */
    132 	u_int reg;
    133 {
    134 
    135 	isa_outb(IO_RTC, (u_char)reg);
    136 	return (isa_inb(IO_RTC+1));
    137 }
    138 
    139 __inline void
    140 mc146818_write(sc, reg, datum)
    141 	void *sc;					/* XXX use it? */
    142 	u_int reg, datum;
    143 {
    144 
    145 	isa_outb(IO_RTC, reg);
    146 	isa_outb(IO_RTC+1, datum);
    147 }
    148 
    149 static int beeping;
    150 
    151 void
    152 sysbeepstop(arg)
    153 	void *arg;
    154 {
    155 	/* disable counter 2 */
    156 	disable_intr();
    157 	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
    158 	enable_intr();
    159 	beeping = 0;
    160 }
    161 
    162 void
    163 sysbeep(pitch, period)
    164 	int pitch, period;
    165 {
    166 	static struct callout sysbeep_ch = CALLOUT_INITIALIZER;
    167 	static int last_pitch;
    168 
    169 	if (beeping)
    170 		callout_stop(&sysbeep_ch);
    171 	if (pitch == 0 || period == 0) {
    172 		sysbeepstop(0);
    173 		last_pitch = 0;
    174 		return;
    175 	}
    176 	if (!beeping || last_pitch != pitch) {
    177 		disable_intr();
    178 		isa_outb(IO_TIMER1 + TIMER_MODE,
    179 			 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
    180 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
    181 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
    182 		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);	/* enable counter 2 */
    183 		enable_intr();
    184 	}
    185 	last_pitch = pitch;
    186 	beeping = 1;
    187 	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
    188 }
    189 
    190 void
    191 rtcinit()
    192 {
    193 	static int first_rtcopen_ever = 1;
    194 
    195 	if (!first_rtcopen_ever)
    196 		return;
    197 	first_rtcopen_ever = 0;
    198 
    199 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
    200 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
    201 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
    202 }
    203 
    204 int
    205 rtcget(regs)
    206 	mc_todregs *regs;
    207 {
    208 
    209 	rtcinit();
    210 	if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
    211 		return (-1);
    212 	MC146818_GETTOD(NULL, regs);			/* XXX softc */
    213 	return (0);
    214 }
    215 
    216 void
    217 rtcput(regs)
    218 	mc_todregs *regs;
    219 {
    220 
    221 	rtcinit();
    222 	MC146818_PUTTOD(NULL, regs);			/* XXX softc */
    223 }
    224 
    225 static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    226 
    227 static int
    228 yeartoday(year)
    229 	int year;
    230 {
    231 
    232 	return ((year % 4) ? 365 : 366);
    233 }
    234 
    235 int
    236 hexdectodec(n)
    237 	int n;
    238 {
    239 
    240 	return (((n >> 4) & 0x0f) * 10 + (n & 0x0f));
    241 }
    242 
    243 int
    244 dectohexdec(n)
    245 	int n;
    246 {
    247 
    248 	return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f));
    249 }
    250 
    251 static int timeset;
    252 
    253 /*
    254  * Initialize the time of day register, based on the time base which is, e.g.
    255  * from a filesystem.
    256  */
    257 void
    258 inittodr(base)
    259 	time_t base;
    260 {
    261 	mc_todregs rtclk;
    262 	time_t n;
    263 	int sec, min, hr, dom, mon, yr;
    264 	int i, days = 0;
    265 	int s;
    266 
    267 	/*
    268 	 * We mostly ignore the suggested time and go for the RTC clock time
    269 	 * stored in the CMOS RAM.  If the time can't be obtained from the
    270 	 * CMOS, or if the time obtained from the CMOS is 5 or more years
    271 	 * less than the suggested time, we used the suggested time.  (In
    272 	 * the latter case, it's likely that the CMOS battery has died.)
    273 	 */
    274 
    275 	if (base < 15*SECYR) {	/* if before 1985, something's odd... */
    276 		printf("WARNING: preposterous time in file system\n");
    277 		/* read the system clock anyway */
    278 		base = 17*SECYR + 186*SECDAY + SECDAY/2;
    279 	}
    280 
    281 	s = splclock();
    282 	if (rtcget(&rtclk)) {
    283 		splx(s);
    284 		printf("WARNING: invalid time in clock chip\n");
    285 		goto fstime;
    286 	}
    287 	splx(s);
    288 
    289 	sec = hexdectodec(rtclk[MC_SEC]);
    290 	min = hexdectodec(rtclk[MC_MIN]);
    291 	hr = hexdectodec(rtclk[MC_HOUR]);
    292 	dom = hexdectodec(rtclk[MC_DOM]);
    293 	mon = hexdectodec(rtclk[MC_MONTH]);
    294 	yr = hexdectodec(rtclk[MC_YEAR]);
    295 	yr = (yr < 70) ? yr+100 : yr;
    296 
    297 	n = sec + 60 * min + 3600 * hr;
    298 	n += (dom - 1) * 3600 * 24;
    299 
    300 	if (yeartoday(yr) == 366)
    301 		month[1] = 29;
    302 	for (i = mon - 2; i >= 0; i--)
    303 		days += month[i];
    304 	month[1] = 28;
    305 	for (i = 70; i < yr; i++)
    306 		days += yeartoday(i);
    307 	n += days * 3600 * 24;
    308 
    309 	n += rtc_offset * 60;
    310 
    311 	if (base < n - 5*SECYR)
    312 		printf("WARNING: file system time much less than clock time\n");
    313 	else if (base > n + 5*SECYR) {
    314 		printf("WARNING: clock time much less than file system time\n");
    315 		printf("WARNING: using file system time\n");
    316 		goto fstime;
    317 	}
    318 
    319 	timeset = 1;
    320 	time.tv_sec = n;
    321 	time.tv_usec = 0;
    322 	return;
    323 
    324 fstime:
    325 	timeset = 1;
    326 	time.tv_sec = base;
    327 	time.tv_usec = 0;
    328 	printf("WARNING: CHECK AND RESET THE DATE!\n");
    329 }
    330 
    331 /*
    332  * Reset the clock.
    333  */
    334 void
    335 resettodr()
    336 {
    337 	mc_todregs rtclk;
    338 	time_t n;
    339 	int diff, i, j;
    340 	int s;
    341 
    342 	/*
    343 	 * We might have been called by boot() due to a crash early
    344 	 * on.  Don't reset the clock chip in this case.
    345 	 */
    346 	if (!timeset)
    347 		return;
    348 
    349 	s = splclock();
    350 	if (rtcget(&rtclk))
    351 		memset(&rtclk, 0, sizeof(rtclk));
    352 	splx(s);
    353 
    354 	diff = rtc_offset * 60;
    355 	n = (time.tv_sec - diff) % (3600 * 24);   /* hrs+mins+secs */
    356 	rtclk[MC_SEC] = dectohexdec(n % 60);
    357 	n /= 60;
    358 	rtclk[MC_MIN] = dectohexdec(n % 60);
    359 	rtclk[MC_HOUR] = dectohexdec(n / 60);
    360 
    361 	n = (time.tv_sec - diff) / (3600 * 24);	/* days */
    362 	rtclk[MC_DOW] = (n + 4) % 7;  /* 1/1/70 is Thursday */
    363 
    364 	for (j = 1970, i = yeartoday(j); n >= i; j++, i = yeartoday(j))
    365 		n -= i;
    366 
    367 	rtclk[MC_YEAR] = dectohexdec(j - 1900);
    368 
    369 	if (i == 366)
    370 		month[1] = 29;
    371 	for (i = 0; n >= month[i]; i++)
    372 		n -= month[i];
    373 	month[1] = 28;
    374 	rtclk[MC_MONTH] = dectohexdec(++i);
    375 
    376 	rtclk[MC_DOM] = dectohexdec(++n);
    377 
    378 	s = splclock();
    379 	rtcput(&rtclk);
    380 	splx(s);
    381 }
    382