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@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