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