[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.4.2.2

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

CVSweb <webmaster@jp.NetBSD.org>