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