[BACK]Return to clock.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / x86 / isa

Annotation of src/sys/arch/x86/isa/clock.c, Revision 1.8.2.5

1.8.2.5 ! yamt        1: /*     $NetBSD: clock.c,v 1.8.2.4 2007/11/15 11:43:39 yamt Exp $       */
1.8.2.2   yamt        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@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>
1.8.2.5 ! yamt      124: __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.8.2.4 2007/11/15 11:43:39 yamt Exp $");
1.8.2.2   yamt      125:
                    126: /* #define CLOCKDEBUG */
                    127: /* #define CLOCK_PARANOIA */
                    128:
                    129: #include "opt_multiprocessor.h"
                    130: #include "opt_ntp.h"
                    131:
                    132: #include <sys/param.h>
                    133: #include <sys/systm.h>
                    134: #include <sys/time.h>
                    135: #include <sys/timetc.h>
                    136: #include <sys/kernel.h>
                    137: #include <sys/device.h>
1.8.2.3   yamt      138: #include <sys/mutex.h>
1.8.2.2   yamt      139:
                    140: #include <machine/cpu.h>
                    141: #include <machine/intr.h>
                    142: #include <machine/pio.h>
                    143: #include <machine/cpufunc.h>
                    144:
                    145: #include <dev/isa/isareg.h>
                    146: #include <dev/isa/isavar.h>
                    147: #include <dev/ic/mc146818reg.h>
                    148: #include <dev/ic/i8253reg.h>
                    149: #include <i386/isa/nvram.h>
                    150: #include <x86/x86/tsc.h>
                    151: #include <dev/clock_subr.h>
                    152: #include <machine/specialreg.h>
                    153:
                    154: #include "config_time.h"               /* for CONFIG_TIME */
                    155:
                    156: #ifndef __x86_64__
                    157: #include "mca.h"
                    158: #endif
                    159: #if NMCA > 0
                    160: #include <machine/mca_machdep.h>       /* for MCA_system */
                    161: #endif
                    162:
                    163: #include "pcppi.h"
                    164: #if (NPCPPI > 0)
                    165: #include <dev/isa/pcppivar.h>
                    166:
                    167: int sysbeepmatch(struct device *, struct cfdata *, void *);
                    168: void sysbeepattach(struct device *, struct device *, void *);
                    169:
                    170: CFATTACH_DECL(sysbeep, sizeof(struct device),
                    171:     sysbeepmatch, sysbeepattach, NULL, NULL);
                    172:
                    173: static int ppi_attached;
                    174: static pcppi_tag_t ppicookie;
                    175: #endif /* PCPPI */
                    176:
                    177: #ifdef CLOCKDEBUG
                    178: int clock_debug = 0;
                    179: #define DPRINTF(arg) if (clock_debug) printf arg
                    180: #else
                    181: #define DPRINTF(arg)
                    182: #endif
                    183:
1.8.2.4   yamt      184: /* Used by lapic.c */
                    185: unsigned int   gettick(void);
1.8.2.2   yamt      186: void           sysbeep(int, int);
                    187: static void     tickle_tc(void);
                    188:
                    189: static int     clockintr(void *, struct intrframe *);
                    190: static void    rtcinit(void);
                    191: static int     rtcget(mc_todregs *);
                    192: static void    rtcput(mc_todregs *);
                    193:
                    194: static int     cmoscheck(void);
                    195:
                    196: static int     clock_expandyear(int);
                    197:
1.8.2.4   yamt      198: static unsigned int    gettick_broken_latch(void);
1.8.2.2   yamt      199:
                    200: static volatile uint32_t i8254_lastcount;
                    201: static volatile uint32_t i8254_offset;
                    202: static volatile int i8254_ticked;
                    203:
1.8.2.3   yamt      204: /* to protect TC timer variables */
                    205: static __cpu_simple_lock_t tmr_lock = __SIMPLELOCK_UNLOCKED;
1.8.2.2   yamt      206:
                    207: inline u_int mc146818_read(void *, u_int);
                    208: inline void mc146818_write(void *, u_int, u_int);
                    209:
                    210: u_int i8254_get_timecount(struct timecounter *);
                    211: static void rtc_register(void);
                    212:
                    213: static struct timecounter i8254_timecounter = {
                    214:        i8254_get_timecount,    /* get_timecount */
                    215:        0,                      /* no poll_pps */
                    216:        ~0u,                    /* counter_mask */
                    217:        TIMER_FREQ,             /* frequency */
                    218:        "i8254",                /* name */
                    219:        100,                    /* quality */
                    220:        NULL,                   /* prev */
                    221:        NULL,                   /* next */
                    222: };
                    223:
                    224: /* XXX use sc? */
                    225: inline u_int
                    226: mc146818_read(void *sc, u_int reg)
                    227: {
                    228:
                    229:        outb(IO_RTC, reg);
                    230:        return (inb(IO_RTC+1));
                    231: }
                    232:
                    233: /* XXX use sc? */
                    234: inline void
                    235: mc146818_write(void *sc, u_int reg, u_int datum)
                    236: {
                    237:
                    238:        outb(IO_RTC, reg);
                    239:        outb(IO_RTC+1, datum);
                    240: }
                    241:
                    242: u_long rtclock_tval;           /* i8254 reload value for countdown */
                    243: int    rtclock_init = 0;
                    244:
                    245: int clock_broken_latch = 0;
                    246:
                    247: #ifdef CLOCK_PARANOIA
                    248: static int ticks[6];
                    249: #endif
                    250: /*
                    251:  * i8254 latch check routine:
                    252:  *     National Geode (formerly Cyrix MediaGX) has a serious bug in
                    253:  *     its built-in i8254-compatible clock module.
                    254:  *     machdep sets the variable 'clock_broken_latch' to indicate it.
                    255:  */
                    256:
1.8.2.4   yamt      257: static unsigned int
1.8.2.2   yamt      258: gettick_broken_latch(void)
                    259: {
                    260:        u_long flags;
                    261:        int v1, v2, v3;
                    262:        int w1, w2, w3;
                    263:
                    264:        /* Don't want someone screwing with the counter while we're here. */
1.8.2.4   yamt      265:        flags = x86_read_psl();
                    266:        x86_disable_intr();
1.8.2.2   yamt      267:
                    268:        v1 = inb(IO_TIMER1+TIMER_CNTR0);
                    269:        v1 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
                    270:        v2 = inb(IO_TIMER1+TIMER_CNTR0);
                    271:        v2 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
                    272:        v3 = inb(IO_TIMER1+TIMER_CNTR0);
                    273:        v3 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
                    274:
1.8.2.4   yamt      275:        x86_write_psl(flags);
1.8.2.2   yamt      276:
                    277: #ifdef CLOCK_PARANOIA
                    278:        if (clock_debug) {
                    279:                ticks[0] = ticks[3];
                    280:                ticks[1] = ticks[4];
                    281:                ticks[2] = ticks[5];
                    282:                ticks[3] = v1;
                    283:                ticks[4] = v2;
                    284:                ticks[5] = v3;
                    285:        }
                    286: #endif
                    287:
                    288:        if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200)
                    289:                return (v2);
                    290:
                    291: #define _swap_val(a, b) do { \
                    292:        int c = a; \
                    293:        a = b; \
                    294:        b = c; \
                    295: } while (0)
                    296:
                    297:        /*
                    298:         * sort v1 v2 v3
                    299:         */
                    300:        if (v1 < v2)
                    301:                _swap_val(v1, v2);
                    302:        if (v2 < v3)
                    303:                _swap_val(v2, v3);
                    304:        if (v1 < v2)
                    305:                _swap_val(v1, v2);
                    306:
                    307:        /*
                    308:         * compute the middle value
                    309:         */
                    310:
                    311:        if (v1 - v3 < 0x200)
                    312:                return (v2);
                    313:
                    314:        w1 = v2 - v3;
                    315:        w2 = v3 - v1 + rtclock_tval;
                    316:        w3 = v1 - v2;
                    317:        if (w1 >= w2) {
                    318:                if (w1 >= w3)
                    319:                        return (v1);
                    320:        } else {
                    321:                if (w2 >= w3)
                    322:                        return (v2);
                    323:        }
                    324:        return (v3);
                    325: }
                    326:
                    327: /* minimal initialization, enough for delay() */
                    328: void
                    329: initrtclock(u_long freq)
                    330: {
                    331:        u_long tval;
1.8.2.3   yamt      332:
1.8.2.2   yamt      333:        /*
                    334:         * Compute timer_count, the count-down count the timer will be
                    335:         * set to.  Also, correctly round
                    336:         * this by carrying an extra bit through the division.
                    337:         */
                    338:        tval = (freq * 2) / (u_long) hz;
                    339:        tval = (tval / 2) + (tval & 0x1);
                    340:
                    341:        /* initialize 8254 clock */
                    342:        outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
                    343:
                    344:        /* Correct rounding will buy us a better precision in timekeeping */
                    345:        outb(IO_TIMER1+TIMER_CNTR0, tval % 256);
                    346:        outb(IO_TIMER1+TIMER_CNTR0, tval / 256);
                    347:
                    348:        rtclock_tval = tval ? tval : 0xFFFF;
                    349:        rtclock_init = 1;
                    350: }
                    351:
                    352: void
                    353: startrtclock(void)
                    354: {
                    355:        int s;
                    356:
                    357:        if (!rtclock_init)
                    358:                initrtclock(TIMER_FREQ);
                    359:
                    360:        /* Check diagnostic status */
                    361:        if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) { /* XXX softc */
                    362:                char bits[128];
                    363:                printf("RTC BIOS diagnostic error %s\n",
                    364:                    bitmask_snprintf(s, NVRAM_DIAG_BITS, bits, sizeof(bits)));
                    365:        }
                    366:
                    367:        tc_init(&i8254_timecounter);
                    368:
                    369:        init_TSC();
                    370:        rtc_register();
                    371: }
                    372:
1.8.2.3   yamt      373: /*
                    374:  * Must be called at splclock().
                    375:  */
1.8.2.2   yamt      376: static void
                    377: tickle_tc(void)
                    378: {
                    379: #if defined(MULTIPROCESSOR)
                    380:        struct cpu_info *ci = curcpu();
                    381:        /*
                    382:         * If we are not the primary CPU, we're not allowed to do
                    383:         * any more work.
                    384:         */
                    385:        if (CPU_IS_PRIMARY(ci) == 0)
                    386:                return;
                    387: #endif
                    388:        if (rtclock_tval && timecounter->tc_get_timecount == i8254_get_timecount) {
1.8.2.3   yamt      389:                __cpu_simple_lock(&tmr_lock);
1.8.2.2   yamt      390:                if (i8254_ticked)
                    391:                        i8254_ticked    = 0;
                    392:                else {
                    393:                        i8254_offset   += rtclock_tval;
                    394:                        i8254_lastcount = 0;
                    395:                }
1.8.2.3   yamt      396:                __cpu_simple_unlock(&tmr_lock);
1.8.2.2   yamt      397:        }
                    398:
                    399: }
                    400:
                    401: static int
                    402: clockintr(void *arg, struct intrframe *frame)
                    403: {
                    404:        tickle_tc();
                    405:
                    406:        hardclock((struct clockframe *)frame);
                    407:
                    408: #if NMCA > 0
                    409:        if (MCA_system) {
                    410:                /* Reset PS/2 clock interrupt by asserting bit 7 of port 0x61 */
                    411:                outb(0x61, inb(0x61) | 0x80);
                    412:        }
                    413: #endif
                    414:        return -1;
                    415: }
                    416:
                    417: u_int
                    418: i8254_get_timecount(struct timecounter *tc)
                    419: {
                    420:        u_int count;
                    421:        u_char high, low;
                    422:        u_long flags;
                    423:
                    424:        /* Don't want someone screwing with the counter while we're here. */
1.8.2.4   yamt      425:        flags = x86_read_psl();
                    426:        x86_disable_intr();
1.8.2.3   yamt      427:        __cpu_simple_lock(&tmr_lock);
1.8.2.2   yamt      428:
                    429:        /* Select timer0 and latch counter value. */
                    430:        outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
                    431:
                    432:        low = inb(IO_TIMER1 + TIMER_CNTR0);
                    433:        high = inb(IO_TIMER1 + TIMER_CNTR0);
                    434:        count = rtclock_tval - ((high << 8) | low);
                    435:
                    436:        if (rtclock_tval && (count < i8254_lastcount || !i8254_ticked)) {
                    437:                i8254_ticked = 1;
                    438:                i8254_offset += rtclock_tval;
                    439:        }
                    440:
                    441:        i8254_lastcount = count;
                    442:        count += i8254_offset;
                    443:
1.8.2.3   yamt      444:        __cpu_simple_unlock(&tmr_lock);
1.8.2.4   yamt      445:        x86_write_psl(flags);
1.8.2.3   yamt      446:
1.8.2.2   yamt      447:        return (count);
                    448: }
                    449:
1.8.2.4   yamt      450: unsigned int
1.8.2.2   yamt      451: gettick(void)
                    452: {
                    453:        u_long flags;
                    454:        u_char lo, hi;
                    455:
                    456:        if (clock_broken_latch)
                    457:                return (gettick_broken_latch());
                    458:
                    459:        /* Don't want someone screwing with the counter while we're here. */
1.8.2.4   yamt      460:        flags = x86_read_psl();
                    461:        x86_disable_intr();
1.8.2.2   yamt      462:        /* Select counter 0 and latch it. */
                    463:        outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
                    464:        lo = inb(IO_TIMER1+TIMER_CNTR0);
                    465:        hi = inb(IO_TIMER1+TIMER_CNTR0);
1.8.2.4   yamt      466:        x86_write_psl(flags);
1.8.2.2   yamt      467:        return ((hi << 8) | lo);
                    468: }
                    469:
                    470: /*
                    471:  * Wait approximately `n' microseconds.
                    472:  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
                    473:  * Note: timer had better have been programmed before this is first used!
                    474:  * (Note that we use `rate generator' mode, which counts at 1:1; `square
                    475:  * wave' mode counts at 2:1).
                    476:  * Don't rely on this being particularly accurate.
                    477:  */
                    478: void
1.8.2.4   yamt      479: i8254_delay(unsigned int n)
1.8.2.2   yamt      480: {
1.8.2.4   yamt      481:        unsigned int cur_tick, initial_tick;
                    482:        int remaining;
1.8.2.2   yamt      483:        static const int delaytab[26] = {
                    484:                 0,  2,  3,  4,  5,  6,  7,  9, 10, 11,
                    485:                12, 13, 15, 16, 17, 18, 19, 21, 22, 23,
                    486:                24, 25, 27, 28, 29, 30,
                    487:        };
                    488:
                    489:        /* allow DELAY() to be used before startrtclock() */
                    490:        if (!rtclock_init)
                    491:                initrtclock(TIMER_FREQ);
                    492:
                    493:        /*
                    494:         * Read the counter first, so that the rest of the setup overhead is
                    495:         * counted.
                    496:         */
1.8.2.4   yamt      497:        initial_tick = gettick();
1.8.2.2   yamt      498:
                    499:        if (n <= 25)
1.8.2.4   yamt      500:                remaining = delaytab[n];
                    501:        else if (n <= UINT_MAX / TIMER_FREQ) {
1.8.2.2   yamt      502:                /*
1.8.2.4   yamt      503:                 * For unsigned arithmetic, division can be replaced with
                    504:                 * multiplication with the inverse and a shift.
1.8.2.2   yamt      505:                 */
1.8.2.4   yamt      506:                remaining = n * TIMER_FREQ / 1000000;
                    507:        } else {
                    508:                /* This is a very long delay.
                    509:                 * Being slow here doesn't matter.
1.8.2.2   yamt      510:                 */
1.8.2.4   yamt      511:                remaining = (unsigned long long) n * TIMER_FREQ / 1000000;
1.8.2.2   yamt      512:        }
                    513:
1.8.2.4   yamt      514:        while (remaining > 0) {
1.8.2.2   yamt      515: #ifdef CLOCK_PARANOIA
                    516:                int delta;
1.8.2.4   yamt      517:                cur_tick = gettick();
                    518:                if (cur_tick > initial_tick)
                    519:                        delta = rtclock_tval - (cur_tick - initial_tick);
1.8.2.2   yamt      520:                else
1.8.2.4   yamt      521:                        delta = initial_tick - cur_tick;
1.8.2.2   yamt      522:                if (delta < 0 || delta >= rtclock_tval / 2) {
                    523:                        DPRINTF(("delay: ignore ticks %.4x-%.4x",
1.8.2.4   yamt      524:                                 initial_tick, cur_tick));
1.8.2.2   yamt      525:                        if (clock_broken_latch) {
                    526:                                DPRINTF(("  (%.4x %.4x %.4x %.4x %.4x %.4x)\n",
                    527:                                         ticks[0], ticks[1], ticks[2],
                    528:                                         ticks[3], ticks[4], ticks[5]));
                    529:                        } else {
                    530:                                DPRINTF(("\n"));
                    531:                        }
                    532:                } else
1.8.2.4   yamt      533:                        remaining -= delta;
1.8.2.2   yamt      534: #else
1.8.2.4   yamt      535:                cur_tick = gettick();
                    536:                if (cur_tick > initial_tick)
                    537:                        remaining -= rtclock_tval - (cur_tick - initial_tick);
1.8.2.2   yamt      538:                else
1.8.2.4   yamt      539:                        remaining -= initial_tick - cur_tick;
1.8.2.2   yamt      540: #endif
1.8.2.4   yamt      541:                initial_tick = cur_tick;
1.8.2.2   yamt      542:        }
                    543: }
                    544:
                    545: #if (NPCPPI > 0)
                    546: int
                    547: sysbeepmatch(struct device *parent, struct cfdata *match,
                    548:     void *aux)
                    549: {
                    550:        return (!ppi_attached);
                    551: }
                    552:
                    553: void
                    554: sysbeepattach(struct device *parent, struct device *self,
                    555:     void *aux)
                    556: {
                    557:        aprint_naive("\n");
                    558:        aprint_normal("\n");
                    559:
                    560:        ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie;
                    561:        ppi_attached = 1;
                    562: }
                    563: #endif
                    564:
                    565: void
                    566: sysbeep(int pitch, int period)
                    567: {
                    568: #if (NPCPPI > 0)
                    569:        if (ppi_attached)
                    570:                pcppi_bell(ppicookie, pitch, period, 0);
                    571: #endif
                    572: }
                    573:
                    574: void
                    575: i8254_initclocks(void)
                    576: {
                    577:
                    578:        /*
                    579:         * XXX If you're doing strange things with multiple clocks, you might
                    580:         * want to keep track of clock handlers.
                    581:         */
                    582:        (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK,
                    583:            (int (*)(void *))clockintr, 0);
                    584: }
                    585:
                    586: static void
                    587: rtcinit(void)
                    588: {
                    589:        static int first_rtcopen_ever = 1;
                    590:
                    591:        if (!first_rtcopen_ever)
                    592:                return;
                    593:        first_rtcopen_ever = 0;
                    594:
                    595:        mc146818_write(NULL, MC_REGA,                   /* XXX softc */
                    596:            MC_BASE_32_KHz | MC_RATE_1024_Hz);
                    597:        mc146818_write(NULL, MC_REGB, MC_REGB_24HR);    /* XXX softc */
                    598: }
                    599:
                    600: static int
                    601: rtcget(mc_todregs *regs)
                    602: {
                    603:
                    604:        rtcinit();
                    605:        if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
                    606:                return (-1);
                    607:        MC146818_GETTOD(NULL, regs);                    /* XXX softc */
                    608:        return (0);
                    609: }
                    610:
                    611: static void
                    612: rtcput(mc_todregs *regs)
                    613: {
                    614:
                    615:        rtcinit();
                    616:        MC146818_PUTTOD(NULL, regs);                    /* XXX softc */
                    617: }
                    618:
                    619: /*
                    620:  * check whether the CMOS layout is "standard"-like (ie, not PS/2-like),
                    621:  * to be called at splclock()
                    622:  */
                    623: static int
                    624: cmoscheck(void)
                    625: {
                    626:        int i;
                    627:        unsigned short cksum = 0;
                    628:
                    629:        for (i = 0x10; i <= 0x2d; i++)
                    630:                cksum += mc146818_read(NULL, i); /* XXX softc */
                    631:
                    632:        return (cksum == (mc146818_read(NULL, 0x2e) << 8)
                    633:                          + mc146818_read(NULL, 0x2f));
                    634: }
                    635:
                    636: #if NMCA > 0
                    637: /*
                    638:  * Check whether the CMOS layout is PS/2 like, to be called at splclock().
                    639:  */
                    640: static int cmoscheckps2(void);
                    641: static int
                    642: cmoscheckps2(void)
                    643: {
                    644: #if 0
                    645:        /* Disabled until I find out the CRC checksum algorithm IBM uses */
                    646:        int i;
                    647:        unsigned short cksum = 0;
                    648:
                    649:        for (i = 0x10; i <= 0x31; i++)
                    650:                cksum += mc146818_read(NULL, i); /* XXX softc */
                    651:
                    652:        return (cksum == (mc146818_read(NULL, 0x32) << 8)
                    653:                          + mc146818_read(NULL, 0x33));
                    654: #else
                    655:        /* Check 'incorrect checksum' bit of IBM PS/2 Diagnostic Status Byte */
                    656:        return ((mc146818_read(NULL, NVRAM_DIAG) & (1<<6)) == 0);
                    657: #endif
                    658: }
                    659: #endif /* NMCA > 0 */
                    660:
                    661: /*
                    662:  * patchable to control century byte handling:
                    663:  * 1: always update
                    664:  * -1: never touch
                    665:  * 0: try to figure out itself
                    666:  */
                    667: int rtc_update_century = 0;
                    668:
                    669: /*
                    670:  * Expand a two-digit year as read from the clock chip
                    671:  * into full width.
                    672:  * Being here, deal with the CMOS century byte.
                    673:  */
                    674: static int centb = NVRAM_CENTURY;
                    675: static int
                    676: clock_expandyear(int clockyear)
                    677: {
                    678:        int s, clockcentury, cmoscentury;
                    679:
                    680:        clockcentury = (clockyear < 70) ? 20 : 19;
                    681:        clockyear += 100 * clockcentury;
                    682:
                    683:        if (rtc_update_century < 0)
                    684:                return (clockyear);
                    685:
                    686:        s = splclock();
                    687:        if (cmoscheck())
                    688:                cmoscentury = mc146818_read(NULL, NVRAM_CENTURY);
                    689: #if NMCA > 0
                    690:        else if (MCA_system && cmoscheckps2())
                    691:                cmoscentury = mc146818_read(NULL, (centb = 0x37));
                    692: #endif
                    693:        else
                    694:                cmoscentury = 0;
                    695:        splx(s);
                    696:        if (!cmoscentury) {
                    697: #ifdef DIAGNOSTIC
                    698:                printf("clock: unknown CMOS layout\n");
                    699: #endif
                    700:                return (clockyear);
                    701:        }
                    702:        cmoscentury = bcdtobin(cmoscentury);
                    703:
                    704:        if (cmoscentury != clockcentury) {
                    705:                /* XXX note: saying "century is 20" might confuse the naive. */
                    706:                printf("WARNING: NVRAM century is %d but RTC year is %d\n",
                    707:                       cmoscentury, clockyear);
                    708:
                    709:                /* Kludge to roll over century. */
                    710:                if ((rtc_update_century > 0) ||
                    711:                    ((cmoscentury == 19) && (clockcentury == 20) &&
                    712:                     (clockyear == 2000))) {
                    713:                        printf("WARNING: Setting NVRAM century to %d\n",
                    714:                               clockcentury);
                    715:                        s = splclock();
                    716:                        mc146818_write(NULL, centb, bintobcd(clockcentury));
                    717:                        splx(s);
                    718:                }
                    719:        } else if (cmoscentury == 19 && rtc_update_century == 0)
                    720:                rtc_update_century = 1; /* will update later in resettodr() */
                    721:
                    722:        return (clockyear);
                    723: }
                    724:
                    725: static int
                    726: rtc_get_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
                    727: {
                    728:        int s;
                    729:        mc_todregs rtclk;
                    730:
                    731:        s = splclock();
                    732:        if (rtcget(&rtclk)) {
                    733:                splx(s);
                    734:                return -1;
                    735:        }
                    736:        splx(s);
                    737:
                    738:        dt->dt_sec = bcdtobin(rtclk[MC_SEC]);
                    739:        dt->dt_min = bcdtobin(rtclk[MC_MIN]);
                    740:        dt->dt_hour = bcdtobin(rtclk[MC_HOUR]);
                    741:        dt->dt_day = bcdtobin(rtclk[MC_DOM]);
                    742:        dt->dt_mon = bcdtobin(rtclk[MC_MONTH]);
                    743:        dt->dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR]));
                    744:
                    745:        return 0;
                    746: }
                    747:
                    748: static int
                    749: rtc_set_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
                    750: {
                    751:        mc_todregs rtclk;
                    752:        int century;
                    753:        int s;
                    754:
                    755:        s = splclock();
                    756:        if (rtcget(&rtclk))
                    757:                memset(&rtclk, 0, sizeof(rtclk));
                    758:        splx(s);
                    759:
                    760:        rtclk[MC_SEC] = bintobcd(dt->dt_sec);
                    761:        rtclk[MC_MIN] = bintobcd(dt->dt_min);
                    762:        rtclk[MC_HOUR] = bintobcd(dt->dt_hour);
                    763:        rtclk[MC_DOW] = dt->dt_wday + 1;
                    764:        rtclk[MC_YEAR] = bintobcd(dt->dt_year % 100);
                    765:        rtclk[MC_MONTH] = bintobcd(dt->dt_mon);
                    766:        rtclk[MC_DOM] = bintobcd(dt->dt_day);
                    767:
                    768: #ifdef DEBUG_CLOCK
                    769:        printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH],
                    770:           rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]);
                    771: #endif
                    772:        s = splclock();
                    773:        rtcput(&rtclk);
                    774:        if (rtc_update_century > 0) {
                    775:                century = bintobcd(dt->dt_year / 100);
                    776:                mc146818_write(NULL, centb, century); /* XXX softc */
                    777:        }
                    778:        splx(s);
                    779:        return 0;
                    780:
                    781: }
                    782:
                    783: static void
                    784: rtc_register(void)
                    785: {
                    786:        static struct todr_chip_handle  tch;
                    787:        tch.todr_gettime_ymdhms = rtc_get_ymdhms;
                    788:        tch.todr_settime_ymdhms = rtc_set_ymdhms;
                    789:        tch.todr_setwen = NULL;
                    790:
                    791:        todr_attach(&tch);
                    792: }
                    793:
                    794: void
                    795: setstatclockrate(int arg)
                    796: {
                    797: }

CVSweb <webmaster@jp.NetBSD.org>