Annotation of 43BSDReno/sys/hp300/clock.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1988 University of Utah.
        !             3:  * Copyright (c) 1982, 1990 The Regents of the University of California.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * This code is derived from software contributed to Berkeley by
        !             7:  * the Systems Programming Group of the University of Utah Computer
        !             8:  * Science Department.
        !             9:  *
        !            10:  * Redistribution is only permitted until one year after the first shipment
        !            11:  * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
        !            12:  * binary forms are permitted provided that: (1) source distributions retain
        !            13:  * this entire copyright notice and comment, and (2) distributions including
        !            14:  * binaries display the following acknowledgement:  This product includes
        !            15:  * software developed by the University of California, Berkeley and its
        !            16:  * contributors'' in the documentation or other materials provided with the
        !            17:  * distribution and in all advertising materials mentioning features or use
        !            18:  * of this software.  Neither the name of the University nor the names of
        !            19:  * its contributors may be used to endorse or promote products derived from
        !            20:  * this software without specific prior written permission.
        !            21:  * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            22:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            23:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            24:  *
        !            25:  * from: Utah $Hdr: clock.c 1.17 89/11/30$
        !            26:  *
        !            27:  *     @(#)clock.c     7.2 (Berkeley) 6/22/90
        !            28:  */
        !            29: 
        !            30: #include "param.h"
        !            31: #include "user.h"
        !            32: #include "kernel.h"
        !            33: #include "../hpdev/hilreg.h"
        !            34: #include "clockreg.h"
        !            35: 
        !            36: #include "machine/psl.h"
        !            37: #include "machine/cpu.h"
        !            38: 
        !            39: #if defined(GPROF) && defined(PROFTIMER)
        !            40: #include "gprof.h"
        !            41: #endif
        !            42: 
        !            43: int    clkstd[] = { IOV(0x5F8000) };
        !            44: 
        !            45: static int month_days[12] = {
        !            46:        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
        !            47: };
        !            48: struct bbc_tm *gmt_to_bbc();
        !            49: u_char bbc_registers[13];
        !            50: u_char write_bbc_reg(), read_bbc_reg();
        !            51: struct hil_dev *bbcaddr = NULL;
        !            52: 
        !            53: /*
        !            54:  * Machine-dependent clock routines.
        !            55:  *
        !            56:  * Startrtclock restarts the real-time clock, which provides
        !            57:  * hardclock interrupts to kern_clock.c.
        !            58:  *
        !            59:  * Inittodr initializes the time of day hardware which provides
        !            60:  * date functions.
        !            61:  *
        !            62:  * Resettodr restores the time of day hardware after a time change.
        !            63:  *
        !            64:  * A note on the real-time clock:
        !            65:  * We actually load the clock with CLK_INTERVAL-1 instead of CLK_INTERVAL.
        !            66:  * This is because the counter decrements to zero after N+1 enabled clock
        !            67:  * periods where N is the value loaded into the counter.
        !            68:  */
        !            69: 
        !            70: /*
        !            71:  * Start the real-time clock.
        !            72:  */
        !            73: startrtclock()
        !            74: {
        !            75:        register struct clkreg *clk = (struct clkreg *)clkstd[0];
        !            76: 
        !            77:        clk->clk_cr2 = CLK_CR1;
        !            78:        clk->clk_cr1 = CLK_RESET;
        !            79:        clk->clk_cr2 = CLK_CR3;
        !            80:        clk->clk_cr3 = 0;
        !            81:        clk->clk_msb1 = (CLK_INTERVAL-1) >> 8 & 0xFF;
        !            82:        clk->clk_lsb1 = (CLK_INTERVAL-1) & 0xFF;
        !            83:        clk->clk_msb2 = 0;
        !            84:        clk->clk_lsb2 = 0;
        !            85:        clk->clk_msb3 = 0;
        !            86:        clk->clk_lsb3 = 0;
        !            87:        clk->clk_cr2 = CLK_CR1;
        !            88:        clk->clk_cr1 = CLK_IENAB;
        !            89: }
        !            90: 
        !            91: /*
        !            92:  * Returns number of usec since last recorded clock "tick"
        !            93:  * (i.e. clock interrupt).
        !            94:  */
        !            95: clkread()
        !            96: {
        !            97:        register struct clkreg *clk = (struct clkreg *) clkstd[0];
        !            98:        register int high, low;
        !            99: 
        !           100:        high = clk->clk_msb1;
        !           101:        low = clk->clk_lsb1;
        !           102:        if (high != clk->clk_msb1)
        !           103:                high = clk->clk_msb1;
        !           104: 
        !           105:        high = (CLK_INTERVAL-1) - ((high << 8) | low);
        !           106:        /*
        !           107:         * Pending interrupt indicates that the counter has wrapped
        !           108:         * since we went to splhigh().  Need to compensate.
        !           109:         */
        !           110:        if (clk->clk_sr & CLK_INT1)
        !           111:                high += CLK_INTERVAL;
        !           112:        return((high * tick) / CLK_INTERVAL);
        !           113: }
        !           114: 
        !           115: #include "clock.h"
        !           116: #if NCLOCK > 0
        !           117: /*
        !           118:  * /dev/clock: mappable high resolution timer.
        !           119:  *
        !           120:  * This code implements a 32-bit recycling counter (with a 4 usec period)
        !           121:  * using timers 2 & 3 on the 6840 clock chip.  The counter can be mapped
        !           122:  * RO into a user's address space to achieve low overhead (no system calls),
        !           123:  * high-precision timing.
        !           124:  *
        !           125:  * Note that timer 3 is also used for the high precision profiling timer
        !           126:  * (PROFTIMER code above).  Care should be taken when both uses are
        !           127:  * configured as only a token effort is made to avoid conflicting use.
        !           128:  */
        !           129: #include "proc.h"
        !           130: #include "ioctl.h"
        !           131: #include "mapmem.h"
        !           132: #include "malloc.h"
        !           133: #include "clockioctl.h"
        !           134: 
        !           135: int clockon = 0;               /* non-zero if high-res timer enabled */
        !           136: #ifdef PROFTIMER
        !           137: int  profprocs = 0;            /* # of procs using profiling timer */
        !           138: #endif
        !           139: #ifdef DEBUG
        !           140: int clockdebug = 0;
        !           141: #endif
        !           142: 
        !           143: /*ARGSUSED*/
        !           144: clockopen(dev, flags)
        !           145:        dev_t dev;
        !           146: {
        !           147: #ifdef PROFTIMER
        !           148: #ifdef GPROF
        !           149:        /*
        !           150:         * Kernel profiling enabled, give up.
        !           151:         */
        !           152:        if (profiling)
        !           153:                return(EBUSY);
        !           154: #endif
        !           155:        /*
        !           156:         * If any user processes are profiling, give up.
        !           157:         */
        !           158:        if (profprocs)
        !           159:                return(EBUSY);
        !           160: #endif
        !           161:        if (!clockon) {
        !           162:                startclock();
        !           163:                clockon++;
        !           164:        }
        !           165:        return(0);
        !           166: }
        !           167: 
        !           168: /*ARGSUSED*/
        !           169: clockclose(dev, flags)
        !           170:        dev_t dev;
        !           171: {
        !           172: #ifdef MAPMEM
        !           173:        (void) clockunmmap(dev, (caddr_t)0);
        !           174: #endif
        !           175:        stopclock();
        !           176:        clockon = 0;
        !           177:        return(0);
        !           178: }
        !           179: 
        !           180: /*ARGSUSED*/
        !           181: clockioctl(dev, cmd, data, flag)
        !           182:        dev_t dev;
        !           183:        caddr_t data;
        !           184: {
        !           185:        int error = 0;
        !           186:        
        !           187:        switch (cmd) {
        !           188: 
        !           189: #ifdef MAPMEM
        !           190:        case CLOCKMAP:
        !           191:                error = clockmmap(dev, (caddr_t *)data);
        !           192:                break;
        !           193: 
        !           194:        case CLOCKUNMAP:
        !           195:                error = clockunmmap(dev, *(caddr_t *)data);
        !           196:                break;
        !           197: 
        !           198:        case CLOCKGETRES:
        !           199:                *(int *)data = CLK_RESOLUTION;
        !           200:                break;
        !           201: #endif
        !           202: 
        !           203:        default:
        !           204:                error = EINVAL;
        !           205:                break;
        !           206:        }
        !           207:        return(error);
        !           208: }
        !           209: 
        !           210: /*ARGSUSED*/
        !           211: clockmap(dev, off, prot)
        !           212:        dev_t dev;
        !           213: {
        !           214: #ifdef MMAP
        !           215:        return((off + (IOBASE+CLKSR-1)) >> PGSHIFT);
        !           216: #endif
        !           217: }
        !           218: 
        !           219: #ifdef MAPMEM
        !           220: 
        !           221: struct mapmemops clockops = {
        !           222:        (int (*)())0, (int (*)())0, (int (*)())0, (int (*)())0
        !           223: };
        !           224: 
        !           225: clockmmap(dev, addrp)
        !           226:        dev_t dev;
        !           227:        caddr_t *addrp;
        !           228: {
        !           229:        struct proc *p = u.u_procp;             /* XXX */
        !           230:        struct mapmem *mp;
        !           231:        int id, error, clockmapin();
        !           232: 
        !           233:        id = minor(dev);        /* XXX */
        !           234:        error = mmalloc(p, id, addrp, NBPG, MM_RO|MM_CI|MM_NOCORE,
        !           235:                        &clockops, &mp);
        !           236: #ifdef DEBUG
        !           237:        if (clockdebug)
        !           238:                printf("clockmmap(%d): addr %x\n", p->p_pid, *addrp);
        !           239: #endif
        !           240:        if (error == 0)
        !           241:                if (error = mmmapin(p, mp, clockmapin))
        !           242:                        (void) mmfree(p, mp);
        !           243:        return(error);
        !           244: }
        !           245: 
        !           246: clockunmmap(dev, addr)
        !           247:        dev_t dev;
        !           248:        caddr_t addr;
        !           249: {
        !           250:        struct proc *p = u.u_procp;             /* XXX */
        !           251:        register struct mapmem *mp, **mpp;
        !           252:        int found, id;
        !           253: 
        !           254: #ifdef DEBUG
        !           255:        if (clockdebug)
        !           256:                printf("clockunmmap(%d): addr %x\n", p->p_pid, addr);
        !           257: #endif
        !           258:        id = minor(dev);        /* XXX */
        !           259:        found = 0;
        !           260:        mpp = &u.u_mmap;
        !           261:        for (mp = *mpp; mp; mp = *mpp) {
        !           262:                if (mp->mm_id != id || mp->mm_ops != &clockops) {
        !           263:                        mpp = &mp->mm_next;
        !           264:                        continue;
        !           265:                }
        !           266:                if (addr &&
        !           267:                    (addr < mp->mm_uva || addr >= mp->mm_uva+mp->mm_size)) {
        !           268:                        mpp = &mp->mm_next;
        !           269:                        continue;
        !           270:                }
        !           271:                mmmapout(p, mp);
        !           272:                (void) mmfree(p, mp);
        !           273:                found++;
        !           274:        }
        !           275:        return(found ? 0 : EINVAL);
        !           276: }
        !           277: 
        !           278: /*ARGSUSED*/
        !           279: clockmapin(mp, off)
        !           280:        struct mapmem *mp;
        !           281: {
        !           282:        return((off + (IOBASE+CLKSR-1)) >> PGSHIFT);
        !           283: }
        !           284: #endif
        !           285: 
        !           286: startclock()
        !           287: {
        !           288:        register struct clkreg *clk = (struct clkreg *)clkstd[0];
        !           289: 
        !           290:        clk->clk_msb2 = -1; clk->clk_lsb2 = -1;
        !           291:        clk->clk_msb3 = -1; clk->clk_lsb3 = -1;
        !           292: 
        !           293:        clk->clk_cr2 = CLK_CR3;
        !           294:        clk->clk_cr3 = CLK_OENAB|CLK_8BIT;
        !           295:        clk->clk_cr2 = CLK_CR1;
        !           296:        clk->clk_cr1 = CLK_IENAB;
        !           297: }
        !           298: 
        !           299: stopclock()
        !           300: {
        !           301:        register struct clkreg *clk = (struct clkreg *)clkstd[0];
        !           302: 
        !           303:        clk->clk_cr2 = CLK_CR3;
        !           304:        clk->clk_cr3 = 0;
        !           305:        clk->clk_cr2 = CLK_CR1;
        !           306:        clk->clk_cr1 = CLK_IENAB;
        !           307: }
        !           308: #endif
        !           309: 
        !           310: #ifdef PROFTIMER
        !           311: /*
        !           312:  * This code allows the hp300 kernel to use one of the extra timers on
        !           313:  * the clock chip for profiling, instead of the regular system timer.
        !           314:  * The advantage of this is that the profiling timer can be turned up to
        !           315:  * a higher interrupt rate, giving finer resolution timing. The profclock
        !           316:  * routine is called from the lev6intr in locore, and is a specialized
        !           317:  * routine that calls addupc. The overhead then is far less than if
        !           318:  * hardclock/softclock was called. Further, the context switch code in
        !           319:  * locore has been changed to turn the profile clock on/off when switching
        !           320:  * into/out of a process that is profiling (startprofclock/stopprofclock).
        !           321:  * This reduces the impact of the profiling clock on other users, and might
        !           322:  * possibly increase the accuracy of the profiling. 
        !           323:  */
        !           324: int  profint   = PRF_INTERVAL; /* Clock ticks between interrupts */
        !           325: int  profscale = 0;            /* Scale factor from sys clock to prof clock */
        !           326: char profon    = 0;            /* Is profiling clock on? */
        !           327: 
        !           328: /* profon values - do not change, locore.s assumes these values */
        !           329: #define PRF_NONE       0x00
        !           330: #define        PRF_USER        0x01
        !           331: #define        PRF_KERNEL      0x80
        !           332: 
        !           333: initprofclock()
        !           334: {
        !           335: #if NCLOCK > 0
        !           336:        /*
        !           337:         * If the high-res timer is running, force profiling off.
        !           338:         * Unfortunately, this gets reflected back to the user not as
        !           339:         * an error but as a lack of results.
        !           340:         */
        !           341:        if (clockon) {
        !           342:                u.u_prof.pr_scale = 0;
        !           343:                return;
        !           344:        }
        !           345:        /*
        !           346:         * Keep track of the number of user processes that are profiling
        !           347:         * by checking the scale value.
        !           348:         *
        !           349:         * XXX: this all assumes that the profiling code is well behaved;
        !           350:         * i.e. profil() is called once per process with pcscale non-zero
        !           351:         * to turn it on, and once with pcscale zero to turn it off.
        !           352:         * Also assumes you don't do any forks or execs.  Oh well, there
        !           353:         * is always adb...
        !           354:         */
        !           355:        if (u.u_prof.pr_scale)
        !           356:                profprocs++;
        !           357:        else
        !           358:                profprocs--;
        !           359: #endif
        !           360:        /*
        !           361:         * The profile interrupt interval must be an even divisor
        !           362:         * of the CLK_INTERVAL so that scaling from a system clock
        !           363:         * tick to a profile clock tick is possible using integer math.
        !           364:         */
        !           365:        if (profint > CLK_INTERVAL || (CLK_INTERVAL % profint) != 0)
        !           366:                profint = CLK_INTERVAL;
        !           367:        profscale = CLK_INTERVAL / profint;
        !           368: }
        !           369: 
        !           370: startprofclock()
        !           371: {
        !           372:        register struct clkreg *clk = (struct clkreg *)clkstd[0];
        !           373: 
        !           374:        clk->clk_msb3 = (profint-1) >> 8 & 0xFF;
        !           375:        clk->clk_lsb3 = (profint-1) & 0xFF;
        !           376: 
        !           377:        clk->clk_cr2 = CLK_CR3;
        !           378:        clk->clk_cr3 = CLK_IENAB;
        !           379: }
        !           380: 
        !           381: stopprofclock()
        !           382: {
        !           383:        register struct clkreg *clk = (struct clkreg *)clkstd[0];
        !           384: 
        !           385:        clk->clk_cr2 = CLK_CR3;
        !           386:        clk->clk_cr3 = 0;
        !           387: }
        !           388: 
        !           389: #ifdef GPROF
        !           390: /*
        !           391:  * profclock() is expanded in line in lev6intr() unless profiling kernel.
        !           392:  * Assumes it is called with clock interrupts blocked.
        !           393:  */
        !           394: profclock(pc, ps)
        !           395:        caddr_t pc;
        !           396:        int ps;
        !           397: {
        !           398:        /*
        !           399:         * Came from user mode.
        !           400:         * If this process is being profiled record the tick.
        !           401:         */
        !           402:        if (USERMODE(ps)) {
        !           403:                if (u.u_prof.pr_scale)
        !           404:                        addupc(pc, &u.u_prof, 1);
        !           405:        }
        !           406:        /*
        !           407:         * Came from kernel (supervisor) mode.
        !           408:         * If we are profiling the kernel, record the tick.
        !           409:         */
        !           410:        else if (profiling < 2) {
        !           411:                register int s = pc - s_lowpc;
        !           412: 
        !           413:                if (s < s_textsize)
        !           414:                        kcount[s / (HISTFRACTION * sizeof (*kcount))]++;
        !           415:        }
        !           416:        /*
        !           417:         * Kernel profiling was on but has been disabled.
        !           418:         * Mark as no longer profiling kernel and if all profiling done,
        !           419:         * disable the clock.
        !           420:         */
        !           421:        if (profiling && (profon & PRF_KERNEL)) {
        !           422:                profon &= ~PRF_KERNEL;
        !           423:                if (profon == PRF_NONE)
        !           424:                        stopprofclock();
        !           425:        }
        !           426: }
        !           427: #endif
        !           428: #endif
        !           429: 
        !           430: /*
        !           431:  * Initialize the time of day register, based on the time base which is, e.g.
        !           432:  * from a filesystem.
        !           433:  */
        !           434: inittodr(base)
        !           435:        time_t base;
        !           436: {
        !           437:        u_long timbuf = base;   /* assume no battery clock exists */
        !           438:        static int bbcinited = 0;
        !           439: 
        !           440:        /* XXX */
        !           441:        if (!bbcinited) {
        !           442:                if (badbaddr(&BBCADDR->hil_stat))
        !           443:                        printf("WARNING: no battery clock\n");
        !           444:                else
        !           445:                        bbcaddr = BBCADDR;
        !           446:                bbcinited = 1;
        !           447:        }
        !           448: 
        !           449:        /*
        !           450:         * bbc_to_gmt converts and stores the gmt in timbuf.
        !           451:         * If an error is detected in bbc_to_gmt, or if the filesystem
        !           452:         * time is more recent than the gmt time in the clock,
        !           453:         * then use the filesystem time and warn the user.
        !           454:         */
        !           455:        if (!bbc_to_gmt(&timbuf) || timbuf < base) {
        !           456:                printf("WARNING: bad date in battery clock\n");
        !           457:                timbuf = base;
        !           458:        }
        !           459:        if (base < 5*SECYR) {
        !           460:                printf("WARNING: preposterous time in file system");
        !           461:                timbuf = 6*SECYR + 186*SECDAY + SECDAY/2;
        !           462:                printf(" -- CHECK AND RESET THE DATE!\n");
        !           463:        }
        !           464:        
        !           465:        /* Battery clock does not store usec's, so forget about it. */
        !           466:        time.tv_sec = timbuf;
        !           467: }
        !           468: 
        !           469: resettodr()
        !           470: {
        !           471:        register int i;
        !           472:        register struct bbc_tm *tmptr;
        !           473: 
        !           474:        tmptr = gmt_to_bbc(time.tv_sec);
        !           475: 
        !           476:        decimal_to_bbc(0, 1,  tmptr->tm_sec);
        !           477:        decimal_to_bbc(2, 3,  tmptr->tm_min);
        !           478:        decimal_to_bbc(4, 5,  tmptr->tm_hour);
        !           479:        decimal_to_bbc(7, 8,  tmptr->tm_mday);
        !           480:        decimal_to_bbc(9, 10, tmptr->tm_mon);
        !           481:        decimal_to_bbc(11, 12, tmptr->tm_year);
        !           482: 
        !           483:        /* Some bogusness to deal with seemingly broken hardware. Nonsense */
        !           484:        bbc_registers[5] = ((tmptr->tm_hour / 10) & 0x03) + 8;
        !           485: 
        !           486:        write_bbc_reg(15, 13);  /* reset prescalar */
        !           487: 
        !           488:        for (i = 0; i <= NUM_BBC_REGS; i++)
        !           489:                if (bbc_registers[i] != write_bbc_reg(i, bbc_registers[i])) {
        !           490:                        printf("Cannot set battery backed clock\n");
        !           491:                        break;
        !           492:                }
        !           493: }
        !           494: 
        !           495: struct bbc_tm *
        !           496: gmt_to_bbc(tim)
        !           497:        long tim;
        !           498: {
        !           499:        register int i;
        !           500:        register long hms, day;
        !           501:        static struct bbc_tm rt;
        !           502: 
        !           503:        day = tim / SECDAY;
        !           504:        hms = tim % SECDAY;
        !           505: 
        !           506:        /* Hours, minutes, seconds are easy */
        !           507:        rt.tm_hour = hms / 3600;
        !           508:        rt.tm_min  = (hms % 3600) / 60;
        !           509:        rt.tm_sec  = (hms % 3600) % 60;
        !           510: 
        !           511:        /* Number of years in days */
        !           512:        for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++)
        !           513:                day -= days_in_year(i);
        !           514:        rt.tm_year = i;
        !           515:        
        !           516:        /* Number of months in days left */
        !           517:        if (leapyear(rt.tm_year))
        !           518:                days_in_month(FEBRUARY) = 29;
        !           519:        for (i = 1; day >= days_in_month(i); i++)
        !           520:                day -= days_in_month(i);
        !           521:        days_in_month(FEBRUARY) = 28;
        !           522:        rt.tm_mon = i;
        !           523: 
        !           524:        /* Days are what is left over (+1) from all that. */
        !           525:        rt.tm_mday = day + 1;  
        !           526:        
        !           527:        return(&rt);
        !           528: }
        !           529: 
        !           530: bbc_to_gmt(timbuf)
        !           531:        u_long *timbuf;
        !           532: {
        !           533:        register int i;
        !           534:        register u_long tmp;
        !           535:        int year, month, day, hour, min, sec;
        !           536: 
        !           537:        read_bbc();
        !           538: 
        !           539:        sec = bbc_to_decimal(1, 0);
        !           540:        min = bbc_to_decimal(3, 2);
        !           541: 
        !           542:        /*
        !           543:         * Hours are different for some reason. Makes no sense really.
        !           544:         */
        !           545:        hour  = ((bbc_registers[5] & 0x03) * 10) + bbc_registers[4];
        !           546:        day   = bbc_to_decimal(8, 7);
        !           547:        month = bbc_to_decimal(10, 9);
        !           548:        year  = bbc_to_decimal(12, 11) + 1900;
        !           549: 
        !           550:        range_test(hour, 0, 23);
        !           551:        range_test(day, 1, 31);
        !           552:        range_test(month, 1, 12);
        !           553:        range_test(year, STARTOFTIME, 2000);
        !           554: 
        !           555:        tmp = 0;
        !           556: 
        !           557:        for (i = STARTOFTIME; i < year; i++)
        !           558:                tmp += days_in_year(i);
        !           559:        if (leapyear(year) && month > FEBRUARY)
        !           560:                tmp++;
        !           561: 
        !           562:        for (i = 1; i < month; i++)
        !           563:                tmp += days_in_month(i);
        !           564:        
        !           565:        tmp += (day - 1);
        !           566:        tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec;
        !           567: 
        !           568:        *timbuf = tmp;
        !           569:        return(1);
        !           570: }
        !           571: 
        !           572: read_bbc()
        !           573: {
        !           574:        register int i, read_okay;
        !           575: 
        !           576:        read_okay = 0;
        !           577:        while (!read_okay) {
        !           578:                read_okay = 1;
        !           579:                for (i = 0; i <= NUM_BBC_REGS; i++)
        !           580:                        bbc_registers[i] = read_bbc_reg(i);
        !           581:                for (i = 0; i <= NUM_BBC_REGS; i++)
        !           582:                        if (bbc_registers[i] != read_bbc_reg(i))
        !           583:                                read_okay = 0;
        !           584:        }
        !           585: }
        !           586: 
        !           587: u_char
        !           588: read_bbc_reg(reg)
        !           589:        int reg;
        !           590: {
        !           591:        u_char data = reg;
        !           592: 
        !           593:        if (bbcaddr) {
        !           594:                send_hil_cmd(bbcaddr, BBC_SET_REG, &data, 1, NULL);
        !           595:                send_hil_cmd(bbcaddr, BBC_READ_REG, NULL, 0, &data);
        !           596:        }
        !           597:        return(data);
        !           598: }
        !           599: 
        !           600: u_char
        !           601: write_bbc_reg(reg, data)
        !           602:        u_int data;
        !           603: {
        !           604:        u_char tmp;
        !           605: 
        !           606:        tmp = (u_char) ((data << HIL_SSHIFT) | reg);
        !           607: 
        !           608:        if (bbcaddr) {
        !           609:                send_hil_cmd(bbcaddr, BBC_SET_REG, &tmp, 1, NULL);
        !           610:                send_hil_cmd(bbcaddr, BBC_WRITE_REG, NULL, 0, NULL);
        !           611:                send_hil_cmd(bbcaddr, BBC_READ_REG, NULL, 0, &tmp);
        !           612:        }
        !           613:        return(tmp);
        !           614: }      

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.