isaclock.c revision 1.2 1 1.2 wiz /* $NetBSD: isaclock.c,v 1.2 2001/07/22 15:04:00 wiz 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.2 wiz memset(&rtclk, 0, 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