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

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

CVSweb <webmaster@jp.NetBSD.org>