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