clock.c revision 1.26
1/* $OpenBSD: clock.c,v 1.26 2002/05/16 15:33:10 mickey Exp $ */ 2/* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */ 3 4/*- 5 * Copyright (c) 1993, 1994 Charles Hannum. 6 * Copyright (c) 1990 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * William Jolitz and Don Ahn. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)clock.c 7.2 (Berkeley) 5/12/91 41 */ 42/* 43 * Mach Operating System 44 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 45 * All Rights Reserved. 46 * 47 * Permission to use, copy, modify and distribute this software and its 48 * documentation is hereby granted, provided that both the copyright 49 * notice and this permission notice appear in all copies of the 50 * software, derivative works or modified versions, and any portions 51 * thereof, and that both notices appear in supporting documentation. 52 * 53 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 54 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 55 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 56 * 57 * Carnegie Mellon requests users of this software to return to 58 * 59 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 60 * School of Computer Science 61 * Carnegie Mellon University 62 * Pittsburgh PA 15213-3890 63 * 64 * any improvements or extensions that they make and grant Carnegie Mellon 65 * the rights to redistribute these changes. 66 */ 67/* 68 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. 69 70 All Rights Reserved 71 72Permission to use, copy, modify, and distribute this software and 73its documentation for any purpose and without fee is hereby 74granted, provided that the above copyright notice appears in all 75copies and that both the copyright notice and this permission notice 76appear in supporting documentation, and that the name of Intel 77not be used in advertising or publicity pertaining to distribution 78of the software without specific, written prior permission. 79 80INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 81INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 82IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 83CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 84LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 85NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 86WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 87*/ 88 89/* 90 * Primitive clock interrupt routines. 91 */ 92#include <sys/types.h> 93#include <sys/param.h> 94#include <sys/systm.h> 95#include <sys/time.h> 96#include <sys/kernel.h> 97#include <sys/device.h> 98#include <sys/timeout.h> 99 100#include <machine/cpu.h> 101#include <machine/intr.h> 102#include <machine/pio.h> 103#include <machine/cpufunc.h> 104 105#include <dev/clock_subr.h> 106#include <dev/isa/isareg.h> 107#include <dev/isa/isavar.h> 108#include <dev/ic/mc146818reg.h> 109#include <i386/isa/nvram.h> 110#include <i386/isa/timerreg.h> 111 112#include "pcppi.h" 113#if (NPCPPI > 0) 114#include <dev/isa/pcppivar.h> 115 116#define __BROKEN_INDIRECT_CONFIG /* XXX */ 117#ifdef __BROKEN_INDIRECT_CONFIG 118int sysbeepmatch(struct device *, void *, void *); 119#else 120int sysbeepmatch(struct device *, struct cfdata *, void *); 121#endif 122void sysbeepattach(struct device *, struct device *, void *); 123 124struct cfattach sysbeep_ca = { 125 sizeof(struct device), sysbeepmatch, sysbeepattach 126}; 127 128struct cfdriver sysbeep_cd = { 129 NULL, "sysbeep", DV_DULL 130}; 131 132static int ppi_attached; 133static pcppi_tag_t ppicookie; 134#endif /* PCPPI */ 135 136void spinwait(int); 137void findcpuspeed(void); 138int clockintr(void *); 139int gettick(void); 140void sysbeep(int, int); 141int rtcget(mc_todregs *); 142void rtcput(mc_todregs *); 143int hexdectodec(int); 144int dectohexdec(int); 145int rtcintr(void *); 146void rtcdrain(void *); 147 148u_int mc146818_read(void *, u_int); 149void mc146818_write(void *, u_int, u_int); 150 151#if defined(I586_CPU) || defined(I686_CPU) 152int pentium_mhz, clock_broken_latch; 153#endif 154 155#define SECMIN ((unsigned)60) /* seconds per minute */ 156#define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ 157 158u_int 159mc146818_read(sc, reg) 160 void *sc; /* XXX use it? */ 161 u_int reg; 162{ 163 int s; 164 u_char v; 165 166 s = splhigh(); 167 outb(IO_RTC, reg); 168 DELAY(1); 169 v = inb(IO_RTC+1); 170 DELAY(1); 171 splx(s); 172 return (v); 173} 174 175void 176mc146818_write(sc, reg, datum) 177 void *sc; /* XXX use it? */ 178 u_int reg, datum; 179{ 180 int s; 181 182 s = splhigh(); 183 outb(IO_RTC, reg); 184 DELAY(1); 185 outb(IO_RTC+1, datum); 186 DELAY(1); 187 splx(s); 188} 189 190void 191startrtclock() 192{ 193 int s; 194 195 findcpuspeed(); /* use the clock (while it's free) 196 to find the cpu speed */ 197 initrtclock(); 198 199 /* Check diagnostic status */ 200 if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) /* XXX softc */ 201 printf("RTC BIOS diagnostic error %b\n", (unsigned int) s, 202 NVRAM_DIAG_BITS); 203} 204 205void 206rtcdrain(void *v) 207{ 208 struct timeout *to = (struct timeout *)v; 209 210 if (to != NULL) 211 timeout_del(to); 212 213 /* 214 * Drain any un-acknowledged RTC interrupts. 215 * See comment in cpu_initclocks(). 216 */ 217 while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) 218 ; /* Nothing. */ 219} 220 221void 222initrtclock() 223{ 224 /* initialize 8253 clock */ 225 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 226 227 /* Correct rounding will buy us a better precision in timekeeping */ 228 outb(IO_TIMER1, TIMER_DIV(hz) % 256); 229 outb(IO_TIMER1, TIMER_DIV(hz) / 256); 230 231#if defined(CPU_I586) || defined(CPU_I686) 232 { 233 extern int cpu_id; 234 switch (cpu_id) { 235 case 0x440: /* Cyrix MediaGX */ 236 case 0x540: /* Cyrix GXm */ 237 clock_broken_latch = 1; 238 break; 239 default: 240 clock_broken_latch = 0; 241 break; 242 } 243 } 244#endif 245} 246 247int 248clockintr(arg) 249 void *arg; 250{ 251 struct clockframe *frame = arg; /* not strictly necessary */ 252 253 hardclock(frame); 254 return (1); 255} 256 257int 258rtcintr(arg) 259 void *arg; 260{ 261 struct clockframe *frame = arg; /* not strictly necessary */ 262 u_int stat = 0; 263 264 /* 265 * If rtcintr is 'late', next intr may happen immediately. 266 * Get them all. (Also, see comment in cpu_initclocks().) 267 */ 268 while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) { 269 statclock(frame); 270 stat = 1; 271 } 272 return (stat); 273} 274 275int 276gettick() 277{ 278 279#if defined(I586_CPU) || defined(I686_CPU) 280 if (clock_broken_latch) { 281 int v1, v2, v3; 282 int w1, w2, w3; 283 284 disable_intr(); 285 286 v1 = inb(TIMER_CNTR0); 287 v1 |= inb(TIMER_CNTR0) << 8; 288 v2 = inb(TIMER_CNTR0); 289 v2 |= inb(TIMER_CNTR0) << 8; 290 v3 = inb(TIMER_CNTR0); 291 v3 |= inb(TIMER_CNTR0) << 8; 292 293 enable_intr(); 294 295 if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200) 296 return (v2); 297 298#define _swap_val(a, b) do { \ 299 int c = a; \ 300 a = b; \ 301 b = c; \ 302} while (0) 303 304 /* sort v1 v2 v3 */ 305 if (v1 < v2) 306 _swap_val(v1, v2); 307 if (v2 < v3) 308 _swap_val(v2, v3); 309 if (v1 < v2) 310 _swap_val(v1, v2); 311 312 /* compute the middle value */ 313 if (v1 - v3 < 0x200) 314 return (v2); 315 w1 = v2 - v3; 316 w2 = v3 - v1 + TIMER_DIV(hz); 317 w3 = v1 - v2; 318 if (w1 >= w2) { 319 if (w1 >= w3) 320 return (v1); 321 } else { 322 if (w2 >= w3) 323 return (v2); 324 } 325 return (v3); 326 } else 327#endif 328 { 329 u_char lo, hi; 330 331 disable_intr(); 332 /* Select counter 0 and latch it. */ 333 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 334 lo = inb(TIMER_CNTR0); 335 hi = inb(TIMER_CNTR0); 336 337 enable_intr(); 338 return ((hi << 8) | lo); 339 } 340} 341 342/* 343 * Wait "n" microseconds. 344 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz. 345 * Note: timer had better have been programmed before this is first used! 346 * (Note that we use `rate generator' mode, which counts at 1:1; `square 347 * wave' mode counts at 2:1). 348 */ 349void 350delay(n) 351 int n; 352{ 353 int limit, tick, otick; 354 355 /* 356 * Read the counter first, so that the rest of the setup overhead is 357 * counted. 358 */ 359 otick = gettick(); 360 361#ifdef __GNUC__ 362 /* 363 * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so 364 * we can take advantage of the intermediate 64-bit quantity to prevent 365 * loss of significance. 366 */ 367 n -= 5; 368 if (n < 0) 369 return; 370 __asm __volatile("mul %2\n\tdiv %3" 371 : "=a" (n) 372 : "0" (n), "r" (TIMER_FREQ), "r" (1000000) 373 : "%edx", "cc"); 374#else 375 /* 376 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and 377 * without any avoidable overflows. 378 */ 379 n -= 20; 380 { 381 int sec = n / 1000000, 382 usec = n % 1000000; 383 n = sec * TIMER_FREQ + 384 usec * (TIMER_FREQ / 1000000) + 385 usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 + 386 usec * (TIMER_FREQ % 1000) / 1000000; 387 } 388#endif 389 390 limit = TIMER_FREQ / hz; 391 392 while (n > 0) { 393 tick = gettick(); 394 if (tick > otick) 395 n -= limit - (tick - otick); 396 else 397 n -= otick - tick; 398 otick = tick; 399 } 400} 401 402#if (NPCPPI > 0) 403int 404sysbeepmatch(parent, match, aux) 405 struct device *parent; 406#ifdef __BROKEN_INDIRECT_CONFIG 407 void *match; 408#else 409 struct cfdata *match; 410#endif 411 void *aux; 412{ 413 return (!ppi_attached); 414} 415 416void 417sysbeepattach(parent, self, aux) 418 struct device *parent, *self; 419 void *aux; 420{ 421 printf("\n"); 422 423 ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie; 424 ppi_attached = 1; 425} 426#endif 427 428void 429sysbeep(pitch, period) 430 int pitch, period; 431{ 432#if (NPCPPI > 0) 433 if (ppi_attached) 434 pcppi_bell(ppicookie, pitch, period, 0); 435#endif 436} 437 438unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ 439 440#define FIRST_GUESS 0x2000 441 442void 443findcpuspeed() 444{ 445 int i; 446 int remainder; 447 448 /* Put counter in count down mode */ 449 outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); 450 outb(TIMER_CNTR0, 0xff); 451 outb(TIMER_CNTR0, 0xff); 452 for (i = FIRST_GUESS; i; i--) 453 ; 454 /* Read the value left in the counter */ 455 remainder = gettick(); 456 /* 457 * Formula for delaycount is: 458 * (loopcount * timer clock speed) / (counter ticks * 1000) 459 */ 460 delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff-remainder); 461} 462 463#if defined(I586_CPU) || defined(I686_CPU) 464void 465calibrate_cyclecounter() 466{ 467 unsigned long long count, last_count; 468#ifdef NTP 469 extern long time_precision; 470#endif 471 472 __asm __volatile(".byte 0xf, 0x31" : "=A" (last_count)); 473 delay(1000000); 474 __asm __volatile(".byte 0xf, 0x31" : "=A" (count)); 475 pentium_mhz = ((count - last_count) + 500000) / 1000000; 476#ifdef NTP 477 time_precision = 1; /* XXX */ 478#endif 479} 480#endif 481 482void 483cpu_initclocks() 484{ 485 static struct timeout rtcdrain_timeout; 486 stathz = 128; 487 profhz = 1024; 488 489 /* 490 * XXX If you're doing strange things with multiple clocks, you might 491 * want to keep track of clock handlers. 492 */ 493 (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr, 494 0, "clock"); 495 (void)isa_intr_establish(NULL, 8, IST_PULSE, IPL_CLOCK, rtcintr, 496 0, "rtc"); 497 498 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); 499 mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE); 500 501 /* 502 * On a number of i386 systems, the rtc will fail to start when booting 503 * the system. This is due to us missing to acknowledge an interrupt 504 * during early stages of the boot process. If we do not acknowledge 505 * the interrupt, the rtc clock will not generate further interrupts. 506 * To solve this, once interrupts are enabled, use a timeout (once) 507 * to drain any un-acknowledged rtc interrupt(s). 508 */ 509 510 timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout); 511 timeout_add(&rtcdrain_timeout, 1); 512} 513 514int 515rtcget(regs) 516 mc_todregs *regs; 517{ 518 if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */ 519 return (-1); 520 MC146818_GETTOD(NULL, regs); /* XXX softc */ 521 return (0); 522} 523 524void 525rtcput(regs) 526 mc_todregs *regs; 527{ 528 MC146818_PUTTOD(NULL, regs); /* XXX softc */ 529} 530 531int 532hexdectodec(n) 533 int n; 534{ 535 536 return (((n >> 4) & 0x0f) * 10 + (n & 0x0f)); 537} 538 539int 540dectohexdec(n) 541 int n; 542{ 543 544 return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f)); 545} 546 547static int timeset; 548 549/* 550 * check whether the CMOS layout is "standard"-like (ie, not PS/2-like), 551 * to be called at splclock() 552 */ 553int cmoscheck(void); 554int 555cmoscheck() 556{ 557 int i; 558 unsigned short cksum = 0; 559 560 for (i = 0x10; i <= 0x2d; i++) 561 cksum += mc146818_read(NULL, i); /* XXX softc */ 562 563 return (cksum == (mc146818_read(NULL, 0x2e) << 8) 564 + mc146818_read(NULL, 0x2f)); 565} 566 567/* 568 * patchable to control century byte handling: 569 * 1: always update 570 * -1: never touch 571 * 0: try to figure out itself 572 */ 573int rtc_update_century = 0; 574 575/* 576 * Expand a two-digit year as read from the clock chip 577 * into full width. 578 * Being here, deal with the CMOS century byte. 579 */ 580int clock_expandyear(int); 581int 582clock_expandyear(clockyear) 583 int clockyear; 584{ 585 int s, clockcentury, cmoscentury; 586 587 clockcentury = (clockyear < 70) ? 20 : 19; 588 clockyear += 100 * clockcentury; 589 590 if (rtc_update_century < 0) 591 return (clockyear); 592 593 s = splclock(); 594 if (cmoscheck()) 595 cmoscentury = mc146818_read(NULL, NVRAM_CENTURY); 596 else 597 cmoscentury = 0; 598 splx(s); 599 if (!cmoscentury) { 600#ifdef DIAGNOSTIC 601 printf("clock: unknown CMOS layout\n"); 602#endif 603 return (clockyear); 604 } 605 cmoscentury = hexdectodec(cmoscentury); 606 607 if (cmoscentury != clockcentury) { 608 /* XXX note: saying "century is 20" might confuse the naive. */ 609 printf("WARNING: NVRAM century is %d but RTC year is %d\n", 610 cmoscentury, clockyear); 611 612 /* Kludge to roll over century. */ 613 if ((rtc_update_century > 0) || 614 ((cmoscentury == 19) && (clockcentury == 20) && 615 (clockyear == 2000))) { 616 printf("WARNING: Setting NVRAM century to %d\n", 617 clockcentury); 618 s = splclock(); 619 mc146818_write(NULL, NVRAM_CENTURY, 620 dectohexdec(clockcentury)); 621 splx(s); 622 } 623 } else if (cmoscentury == 19 && rtc_update_century == 0) 624 rtc_update_century = 1; /* will update later in resettodr() */ 625 626 return (clockyear); 627} 628 629/* 630 * Initialize the time of day register, based on the time base which is, e.g. 631 * from a filesystem. 632 */ 633void 634inittodr(base) 635 time_t base; 636{ 637 mc_todregs rtclk; 638 struct clock_ymdhms dt; 639 int s; 640 641 /* 642 * We mostly ignore the suggested time and go for the RTC clock time 643 * stored in the CMOS RAM. If the time can't be obtained from the 644 * CMOS, or if the time obtained from the CMOS is 5 or more years 645 * less than the suggested time, we used the suggested time. (In 646 * the latter case, it's likely that the CMOS battery has died.) 647 */ 648 649 if (base < 15*SECYR) { /* if before 1985, something's odd... */ 650 printf("WARNING: preposterous time in file system\n"); 651 /* read the system clock anyway */ 652 base = 17*SECYR + 186*SECDAY + SECDAY/2; 653 } 654 655 time.tv_usec = 0; 656 657 s = splclock(); 658 if (rtcget(&rtclk)) { 659 splx(s); 660 printf("WARNING: invalid time in clock chip\n"); 661 goto fstime; 662 } 663 splx(s); 664 665 dt.dt_sec = hexdectodec(rtclk[MC_SEC]); 666 dt.dt_min = hexdectodec(rtclk[MC_MIN]); 667 dt.dt_hour = hexdectodec(rtclk[MC_HOUR]); 668 dt.dt_day = hexdectodec(rtclk[MC_DOM]); 669 dt.dt_mon = hexdectodec(rtclk[MC_MONTH]); 670 dt.dt_year = clock_expandyear(hexdectodec(rtclk[MC_YEAR])); 671 672 673 /* 674 * If time_t is 32 bits, then the "End of Time" is 675 * Mon Jan 18 22:14:07 2038 (US/Eastern) 676 * This code copes with RTC's past the end of time if time_t 677 * is an int32 or less. Needed because sometimes RTCs screw 678 * up or are badly set, and that would cause the time to go 679 * negative in the calculation below, which causes Very Bad 680 * Mojo. This at least lets the user boot and fix the problem. 681 * Note the code is self eliminating once time_t goes to 64 bits. 682 */ 683 if (sizeof(time_t) <= sizeof(int32_t)) { 684 if (dt.dt_year >= 2038) { 685 printf("WARNING: RTC time at or beyond 2038.\n"); 686 dt.dt_year = 2037; 687 printf("WARNING: year set back to 2037.\n"); 688 printf("WARNING: CHECK AND RESET THE DATE!\n"); 689 } 690 } 691 692 time.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60; 693 if (tz.tz_dsttime) 694 time.tv_sec -= 3600; 695 696 if (base < time.tv_sec - 5*SECYR) 697 printf("WARNING: file system time much less than clock time\n"); 698 else if (base > time.tv_sec + 5*SECYR) { 699 printf("WARNING: clock time much less than file system time\n"); 700 printf("WARNING: using file system time\n"); 701 goto fstime; 702 } 703 704 timeset = 1; 705 return; 706 707fstime: 708 timeset = 1; 709 time.tv_sec = base; 710 printf("WARNING: CHECK AND RESET THE DATE!\n"); 711} 712 713/* 714 * Reset the clock. 715 */ 716void 717resettodr() 718{ 719 mc_todregs rtclk; 720 struct clock_ymdhms dt; 721 int diff; 722 int century; 723 int s; 724 725 /* 726 * We might have been called by boot() due to a crash early 727 * on. Don't reset the clock chip in this case. 728 */ 729 if (!timeset) 730 return; 731 732 s = splclock(); 733 if (rtcget(&rtclk)) 734 bzero(&rtclk, sizeof(rtclk)); 735 splx(s); 736 737 diff = tz.tz_minuteswest * 60; 738 if (tz.tz_dsttime) 739 diff -= 3600; 740 clock_secs_to_ymdhms(time.tv_sec - diff, &dt); 741 742 rtclk[MC_SEC] = dectohexdec(dt.dt_sec); 743 rtclk[MC_MIN] = dectohexdec(dt.dt_min); 744 rtclk[MC_HOUR] = dectohexdec(dt.dt_hour); 745 rtclk[MC_DOW] = dt.dt_wday; 746 rtclk[MC_YEAR] = dectohexdec(dt.dt_year % 100); 747 rtclk[MC_MONTH] = dectohexdec(dt.dt_mon); 748 rtclk[MC_DOM] = dectohexdec(dt.dt_day); 749 s = splclock(); 750 rtcput(&rtclk); 751 if (rtc_update_century > 0) { 752 century = dectohexdec(dt.dt_year / 100); 753 mc146818_write(NULL, NVRAM_CENTURY, century); /* XXX softc */ 754 } 755 splx(s); 756} 757 758void 759setstatclockrate(arg) 760 int arg; 761{ 762 if (arg == stathz) 763 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); 764 else 765 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz); 766} 767