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