Home | History | Annotate | Line # | Download | only in isa
isaclock.c revision 1.3
      1 /*	$NetBSD: isaclock.c,v 1.3 2003/07/15 03:35:49 lukem 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 
     92 #include <sys/cdefs.h>
     93 __KERNEL_RCSID(0, "$NetBSD: isaclock.c,v 1.3 2003/07/15 03:35:49 lukem Exp $");
     94 
     95 #include <sys/param.h>
     96 #include <sys/systm.h>
     97 #include <sys/callout.h>
     98 #include <sys/time.h>
     99 #include <sys/kernel.h>
    100 #include <sys/device.h>
    101 
    102 #include <machine/cpu.h>
    103 #include <machine/intr.h>
    104 #include <machine/pio.h>
    105 
    106 #include <dev/isa/isareg.h>
    107 #include <dev/isa/isavar.h>
    108 #include <dev/ic/mc146818reg.h>
    109 #include <dev/ic/i8253reg.h>
    110 #include <sandpoint/isa/nvram.h>
    111 #include <sandpoint/isa/spkrreg.h>
    112 
    113 extern void disable_intr(void);	/* In locore.S */
    114 extern void enable_intr(void);	/* In locore.S */
    115 
    116 void	sysbeepstop __P((void *));
    117 void	sysbeep __P((int, int));
    118 void	rtcinit __P((void));
    119 int	rtcget __P((mc_todregs *));
    120 void	rtcput __P((mc_todregs *));
    121 static int yeartoday __P((int));
    122 int 	hexdectodec __P((int));
    123 int	dectohexdec __P((int));
    124 
    125 __inline u_int mc146818_read __P((void *, u_int));
    126 __inline void mc146818_write __P((void *, u_int, u_int));
    127 
    128 #define	SECMIN	((unsigned)60)			/* seconds per minute */
    129 #define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
    130 #define	SECDAY	((unsigned)(24*SECHOUR))	/* seconds per day */
    131 #define	SECYR	((unsigned)(365*SECDAY))	/* seconds per common year */
    132 
    133 __inline u_int
    134 mc146818_read(sc, reg)
    135 	void *sc;					/* XXX use it? */
    136 	u_int reg;
    137 {
    138 
    139 	isa_outb(IO_RTC, (u_char)reg);
    140 	return (isa_inb(IO_RTC+1));
    141 }
    142 
    143 __inline void
    144 mc146818_write(sc, reg, datum)
    145 	void *sc;					/* XXX use it? */
    146 	u_int reg, datum;
    147 {
    148 
    149 	isa_outb(IO_RTC, reg);
    150 	isa_outb(IO_RTC+1, datum);
    151 }
    152 
    153 static int beeping;
    154 
    155 void
    156 sysbeepstop(arg)
    157 	void *arg;
    158 {
    159 	/* disable counter 2 */
    160 	disable_intr();
    161 	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
    162 	enable_intr();
    163 	beeping = 0;
    164 }
    165 
    166 void
    167 sysbeep(pitch, period)
    168 	int pitch, period;
    169 {
    170 	static struct callout sysbeep_ch = CALLOUT_INITIALIZER;
    171 	static int last_pitch;
    172 
    173 	if (beeping)
    174 		callout_stop(&sysbeep_ch);
    175 	if (pitch == 0 || period == 0) {
    176 		sysbeepstop(0);
    177 		last_pitch = 0;
    178 		return;
    179 	}
    180 	if (!beeping || last_pitch != pitch) {
    181 		disable_intr();
    182 		isa_outb(IO_TIMER1 + TIMER_MODE,
    183 			 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
    184 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
    185 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
    186 		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);	/* enable counter 2 */
    187 		enable_intr();
    188 	}
    189 	last_pitch = pitch;
    190 	beeping = 1;
    191 	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
    192 }
    193 
    194 void
    195 rtcinit()
    196 {
    197 	static int first_rtcopen_ever = 1;
    198 
    199 	if (!first_rtcopen_ever)
    200 		return;
    201 	first_rtcopen_ever = 0;
    202 
    203 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
    204 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
    205 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
    206 }
    207 
    208 int
    209 rtcget(regs)
    210 	mc_todregs *regs;
    211 {
    212 
    213 	rtcinit();
    214 	if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
    215 		return (-1);
    216 	MC146818_GETTOD(NULL, regs);			/* XXX softc */
    217 	return (0);
    218 }
    219 
    220 void
    221 rtcput(regs)
    222 	mc_todregs *regs;
    223 {
    224 
    225 	rtcinit();
    226 	MC146818_PUTTOD(NULL, regs);			/* XXX softc */
    227 }
    228 
    229 static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    230 
    231 static int
    232 yeartoday(year)
    233 	int year;
    234 {
    235 
    236 	return ((year % 4) ? 365 : 366);
    237 }
    238 
    239 int
    240 hexdectodec(n)
    241 	int n;
    242 {
    243 
    244 	return (((n >> 4) & 0x0f) * 10 + (n & 0x0f));
    245 }
    246 
    247 int
    248 dectohexdec(n)
    249 	int n;
    250 {
    251 
    252 	return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f));
    253 }
    254 
    255 static int timeset;
    256 
    257 /*
    258  * Initialize the time of day register, based on the time base which is, e.g.
    259  * from a filesystem.
    260  */
    261 void
    262 inittodr(base)
    263 	time_t base;
    264 {
    265 	mc_todregs rtclk;
    266 	time_t n;
    267 	int sec, min, hr, dom, mon, yr;
    268 	int i, days = 0;
    269 	int s;
    270 
    271 	/*
    272 	 * We mostly ignore the suggested time and go for the RTC clock time
    273 	 * stored in the CMOS RAM.  If the time can't be obtained from the
    274 	 * CMOS, or if the time obtained from the CMOS is 5 or more years
    275 	 * less than the suggested time, we used the suggested time.  (In
    276 	 * the latter case, it's likely that the CMOS battery has died.)
    277 	 */
    278 
    279 	if (base < 15*SECYR) {	/* if before 1985, something's odd... */
    280 		printf("WARNING: preposterous time in file system\n");
    281 		/* read the system clock anyway */
    282 		base = 17*SECYR + 186*SECDAY + SECDAY/2;
    283 	}
    284 
    285 	s = splclock();
    286 	if (rtcget(&rtclk)) {
    287 		splx(s);
    288 		printf("WARNING: invalid time in clock chip\n");
    289 		goto fstime;
    290 	}
    291 	splx(s);
    292 
    293 	sec = hexdectodec(rtclk[MC_SEC]);
    294 	min = hexdectodec(rtclk[MC_MIN]);
    295 	hr = hexdectodec(rtclk[MC_HOUR]);
    296 	dom = hexdectodec(rtclk[MC_DOM]);
    297 	mon = hexdectodec(rtclk[MC_MONTH]);
    298 	yr = hexdectodec(rtclk[MC_YEAR]);
    299 	yr = (yr < 70) ? yr+100 : yr;
    300 
    301 	n = sec + 60 * min + 3600 * hr;
    302 	n += (dom - 1) * 3600 * 24;
    303 
    304 	if (yeartoday(yr) == 366)
    305 		month[1] = 29;
    306 	for (i = mon - 2; i >= 0; i--)
    307 		days += month[i];
    308 	month[1] = 28;
    309 	for (i = 70; i < yr; i++)
    310 		days += yeartoday(i);
    311 	n += days * 3600 * 24;
    312 
    313 	n += rtc_offset * 60;
    314 
    315 	if (base < n - 5*SECYR)
    316 		printf("WARNING: file system time much less than clock time\n");
    317 	else if (base > n + 5*SECYR) {
    318 		printf("WARNING: clock time much less than file system time\n");
    319 		printf("WARNING: using file system time\n");
    320 		goto fstime;
    321 	}
    322 
    323 	timeset = 1;
    324 	time.tv_sec = n;
    325 	time.tv_usec = 0;
    326 	return;
    327 
    328 fstime:
    329 	timeset = 1;
    330 	time.tv_sec = base;
    331 	time.tv_usec = 0;
    332 	printf("WARNING: CHECK AND RESET THE DATE!\n");
    333 }
    334 
    335 /*
    336  * Reset the clock.
    337  */
    338 void
    339 resettodr()
    340 {
    341 	mc_todregs rtclk;
    342 	time_t n;
    343 	int diff, i, j;
    344 	int s;
    345 
    346 	/*
    347 	 * We might have been called by boot() due to a crash early
    348 	 * on.  Don't reset the clock chip in this case.
    349 	 */
    350 	if (!timeset)
    351 		return;
    352 
    353 	s = splclock();
    354 	if (rtcget(&rtclk))
    355 		memset(&rtclk, 0, sizeof(rtclk));
    356 	splx(s);
    357 
    358 	diff = rtc_offset * 60;
    359 	n = (time.tv_sec - diff) % (3600 * 24);   /* hrs+mins+secs */
    360 	rtclk[MC_SEC] = dectohexdec(n % 60);
    361 	n /= 60;
    362 	rtclk[MC_MIN] = dectohexdec(n % 60);
    363 	rtclk[MC_HOUR] = dectohexdec(n / 60);
    364 
    365 	n = (time.tv_sec - diff) / (3600 * 24);	/* days */
    366 	rtclk[MC_DOW] = (n + 4) % 7;  /* 1/1/70 is Thursday */
    367 
    368 	for (j = 1970, i = yeartoday(j); n >= i; j++, i = yeartoday(j))
    369 		n -= i;
    370 
    371 	rtclk[MC_YEAR] = dectohexdec(j - 1900);
    372 
    373 	if (i == 366)
    374 		month[1] = 29;
    375 	for (i = 0; n >= month[i]; i++)
    376 		n -= month[i];
    377 	month[1] = 28;
    378 	rtclk[MC_MONTH] = dectohexdec(++i);
    379 
    380 	rtclk[MC_DOM] = dectohexdec(++n);
    381 
    382 	s = splclock();
    383 	rtcput(&rtclk);
    384 	splx(s);
    385 }
    386