Annotation of Net2/arch/tahoe/vba/dr.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1988 The Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * This code is derived from software contributed to Berkeley by
        !             6:  * Computer Consoles Inc.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *     This product includes software developed by the University of
        !            19:  *     California, Berkeley and its contributors.
        !            20:  * 4. Neither the name of the University nor the names of its contributors
        !            21:  *    may be used to endorse or promote products derived from this software
        !            22:  *    without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            34:  * SUCH DAMAGE.
        !            35:  *
        !            36:  *     @(#)dr.c        7.9 (Berkeley) 12/16/90
        !            37:  */
        !            38: 
        !            39: #include "dr.h"
        !            40: #if NDR > 0
        !            41: /*
        !            42:  * DRV11-W DMA interface driver.
        !            43:  *
        !            44:  * UNTESTED WITH 4.3
        !            45:  */
        !            46: #include "../include/mtpr.h"
        !            47: #include "../include/pte.h"
        !            48: 
        !            49: #include "sys/param.h"
        !            50: #include "sys/conf.h"
        !            51: #include "sys/user.h"
        !            52: #include "sys/proc.h"
        !            53: #include "sys/map.h"
        !            54: #include "sys/ioctl.h"
        !            55: #include "sys/buf.h"
        !            56: #include "sys/vm.h"
        !            57: #include "sys/kernel.h"
        !            58: 
        !            59: #include "../vba/vbavar.h"
        !            60: #include "../vba/drreg.h"
        !            61: 
        !            62: #define YES 1
        !            63: #define NO  0
        !            64: 
        !            65: struct  vba_device  *drinfo[NDR];
        !            66: struct  dr_aux dr_aux[NDR];
        !            67: 
        !            68: unsigned drminphys();
        !            69: int     drprobe(), drintr(), drattach(), drtimo(), drrwtimo();
        !            70: int     drstrategy();
        !            71: extern struct  vba_device  *drinfo[];
        !            72: static long drstd[] = { 0 };
        !            73: struct  vba_driver drdriver =
        !            74:     { drprobe, 0, drattach, 0, drstd, "rs", drinfo };
        !            75: 
        !            76: #define RSUNIT(dev) (minor(dev) & 7)
        !            77: #define SPL_UP spl5
        !            78: 
        !            79: /* -------- Per-unit data -------- */
        !            80: 
        !            81: extern struct dr_aux dr_aux[];
        !            82: 
        !            83: #ifdef DR_DEBUG
        !            84: long   DR11 = 0;
        !            85: #endif
        !            86: 
        !            87: drprobe(reg, vi)
        !            88:        caddr_t reg;
        !            89:        struct vba_device *vi;
        !            90: {
        !            91:        register int br, cvec;          /* must be r12, r11 */
        !            92:        struct rsdevice *dr;
        !            93: 
        !            94: #ifdef lint
        !            95:        br = 0; cvec = br; br = cvec;
        !            96:        drintr(0);
        !            97: #endif
        !            98:        if (badaddr(reg, 2))
        !            99:                return (0);
        !           100:        dr = (struct rsdevice *)reg;
        !           101:        dr->dr_intvect = --vi->ui_hd->vh_lastiv;
        !           102: #ifdef DR_DEBUG
        !           103:        printf("dprobe: Set interrupt vector %lx and init\n",dr->dr_intvec);
        !           104: #endif
        !           105:        /* generate interrupt here for autoconfig */
        !           106:        dr->dr_cstat = MCLR;            /* init board and device */
        !           107: #ifdef DR_DEBUG
        !           108:        printf("drprobe: Initial status %lx\n", dr->dr_cstat);
        !           109: #endif
        !           110:        br = 0x18, cvec = dr->dr_intvect;       /* XXX */
        !           111:        return (sizeof (struct rsdevice));              /* DR11 exist */
        !           112: }
        !           113: 
        !           114: /* ARGSUSED */
        !           115: drattach(ui)
        !           116:        struct vba_device *ui;
        !           117: {
        !           118:        register struct dr_aux *rsd;
        !           119: 
        !           120:        rsd = &dr_aux[ui->ui_unit];
        !           121:        rsd->dr_flags = DR_PRES;                /* This dr11 is present */
        !           122:        rsd->dr_addr = (struct rsdevice *)ui->ui_addr; /* Save addr of this dr11 */
        !           123:        rsd->dr_istat = 0;
        !           124:        rsd->dr_bycnt = 0;
        !           125:        rsd->dr_cmd = 0;
        !           126:        rsd->currenttimo = 0;
        !           127: }
        !           128: 
        !           129: /*ARGSUSED*/
        !           130: dropen(dev, flag)
        !           131:        dev_t dev;
        !           132:        int flag;
        !           133: {
        !           134:        register int unit = RSUNIT(dev);
        !           135:        register struct rsdevice *dr;
        !           136:        register struct dr_aux *rsd;
        !           137: 
        !           138:        if (drinfo[unit] == 0 || !drinfo[unit]->ui_alive)
        !           139:                return (ENXIO);
        !           140:        dr = RSADDR(unit);
        !           141:        rsd = &dr_aux[unit];
        !           142:        if (rsd->dr_flags & DR_OPEN) {
        !           143: #ifdef DR_DEBUG
        !           144:                printf("\ndropen: dr11 unit %ld already open",unit);
        !           145: #endif
        !           146:                return (ENXIO);                 /* DR11 already open */
        !           147:        }
        !           148:        rsd->dr_flags |= DR_OPEN;       /* Mark it OPEN */
        !           149:        rsd->dr_istat = 0;              /* Clear status of previous interrupt */
        !           150:        rsd->rtimoticks = hz;           /* Set read no stall timout to 1 sec */
        !           151:        rsd->wtimoticks = hz*60;        /* Set write no stall timout to 1 min */
        !           152:        dr->dr_cstat = DR_ZERO;         /* Clear function & latches */
        !           153:        dr->dr_pulse = (RDMA | RATN);   /* clear leftover attn & e-o-r flags */
        !           154:        drtimo(dev);                    /* start the self kicker */
        !           155:        return (0);
        !           156: }
        !           157: 
        !           158: drclose (dev)
        !           159:        dev_t dev;
        !           160: {
        !           161:        register int unit = RSUNIT(dev);
        !           162:        register struct dr_aux *dra;
        !           163:        register struct rsdevice *rs;
        !           164:        register short s;
        !           165: 
        !           166:        dra = &dr_aux[unit];
        !           167:        if ((dra->dr_flags & DR_OPEN) == 0) {
        !           168: #ifdef DR_DEBUG
        !           169:                printf("\ndrclose: DR11 device %ld not open",unit);
        !           170: #endif
        !           171:                return;
        !           172:        }
        !           173:        dra->dr_flags &= ~(DR_OPEN|DR_ACTV);
        !           174:        rs = dra->dr_addr;
        !           175:        s = SPL_UP();
        !           176:        rs->dr_cstat = DR_ZERO;
        !           177:        if (dra->dr_buf.b_flags & B_BUSY) {
        !           178:                dra->dr_buf.b_flags &= ~B_BUSY;
        !           179:                wakeup((caddr_t)&dra->dr_buf.b_flags);
        !           180:        }
        !           181:        splx(s);
        !           182:        return (0);
        !           183: }
        !           184: 
        !           185: 
        !           186: /*     drread() works exactly like drwrite() except that the
        !           187:        B_READ flag is used when physio() is called
        !           188: */
        !           189: drread (dev, uio)
        !           190:        dev_t dev;
        !           191:        struct uio *uio;
        !           192: {      register struct dr_aux *dra;
        !           193:        register struct buf *bp;
        !           194:        register int spl, err;
        !           195:        register int unit = RSUNIT(dev);
        !           196: 
        !           197:        if (uio->uio_iov->iov_len <= 0 ||       /* Negative count */
        !           198:            uio->uio_iov->iov_len & 1 ||        /* odd count */
        !           199:            (int)uio->uio_iov->iov_base & 1)    /* odd destination address */
        !           200:                return (EINVAL);
        !           201: #ifdef DR_DEBUG
        !           202:        if (DR11 & 8)
        !           203:                printf("\ndrread: (len:%ld)(base:%lx)",
        !           204:                    uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base); 
        !           205: #endif
        !           206:        dra = &dr_aux[RSUNIT(dev)];
        !           207:        dra->dr_op = DR_READ;
        !           208:        bp =  &dra->dr_buf;
        !           209:        bp->b_resid = 0;
        !           210:        if (dra->dr_flags & DR_NORSTALL) {
        !           211:                /*
        !           212:                 * We are in no stall mode, start the timer,
        !           213:                 * raise IPL so nothing can stop us once the
        !           214:                 * timer's running
        !           215:                 */
        !           216:                spl = SPL_UP();
        !           217:                timeout(drrwtimo, (caddr_t)((dra->currenttimo<<8) | unit),
        !           218:                    (int)dra->rtimoticks);
        !           219:                err = physio(drstrategy, bp, dev,B_READ, drminphys, uio);
        !           220:                splx(spl);
        !           221:                if (err)
        !           222:                        return (err);
        !           223:                dra->currenttimo++;     /* Update current timeout number */
        !           224:                /* Did we timeout */
        !           225:                if (dra->dr_flags & DR_TMDM)
        !           226:                        dra->dr_flags &= ~DR_TMDM; /* Clear timeout flag */
        !           227:                return (err);
        !           228:        }
        !           229:        return (physio(drstrategy, bp, dev,B_READ, drminphys, uio));
        !           230: }
        !           231: 
        !           232: drwrite(dev, uio)
        !           233:        dev_t dev;
        !           234:        struct uio *uio;
        !           235: {      register struct dr_aux *dra;
        !           236:        register struct buf *bp;
        !           237:        register int unit = RSUNIT(dev);
        !           238:        int spl, err;
        !           239: 
        !           240:        if (uio->uio_iov->iov_len <= 0 || uio->uio_iov->iov_len & 1 ||
        !           241:            (int)uio->uio_iov->iov_base & 1)
        !           242:                return (EINVAL);
        !           243: #ifdef DR_DEBUG
        !           244:        if (DR11 & 4)
        !           245:                printf("\ndrwrite: (len:%ld)(base:%lx)",
        !           246:                    uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base); 
        !           247: #endif
        !           248:        dra = &dr_aux[RSUNIT(dev)];
        !           249:        dra->dr_op = DR_WRITE;
        !           250:        bp =  &dra->dr_buf;
        !           251:        bp->b_resid = 0;
        !           252:        if (dra->dr_flags & DR_NOWSTALL) {
        !           253:                /*
        !           254:                 * We are in no stall mode, start the timer,
        !           255:                 * raise IPL so nothing can stop us once the
        !           256:                 * timer's running
        !           257:                 */
        !           258:                spl = SPL_UP();
        !           259:                timeout(drrwtimo,(caddr_t)((dra->currenttimo<<8) | unit),
        !           260:                    (int)dra->wtimoticks);
        !           261:                err = physio (drstrategy, bp, dev,B_WRITE, drminphys, uio);
        !           262:                splx(spl);
        !           263:                if (err)
        !           264:                        return (err);
        !           265:                dra->currenttimo++;     /* Update current timeout number */
        !           266:                /* Did we timeout */
        !           267:                if (dra->dr_flags & DR_TMDM)
        !           268:                        dra->dr_flags &= ~DR_TMDM;      /* Clear timeout flag */
        !           269:                return (err);
        !           270:        }
        !           271:        return (physio(drstrategy, bp, dev,B_WRITE, drminphys, uio));
        !           272: }
        !           273: 
        !           274: /*
        !           275:  * Routine used by calling program to issue commands to dr11 driver and 
        !           276:  * through it to the device.
        !           277:  * It is also used to read status from the device and driver and to wait 
        !           278:  * for attention interrupts.
        !           279:  * Status is returned in an 8 elements unsigned short integer array, the 
        !           280:  * first two elements of the array are also used to pass arguments to 
        !           281:  * drioctl() if required.
        !           282:  * The function bits to be written to the dr11 are included in the cmd
        !           283:  * argument. Even if they are not being written to the dr11 in a particular
        !           284:  * drioctl() call, they will update the copy of cmd that is stored in the
        !           285:  * driver. When drstrategy() is called, this updated copy is used if a 
        !           286:  * deferred function bit write has been specified. The "side effect" of
        !           287:  * calls to the drioctl() requires that the last call prior to a read or
        !           288:  * write has an appropriate copy of the function bits in cmd if they are
        !           289:  * to be used in drstrategy().
        !           290:  * When used as command value, the contents of data[0] is the command
        !           291:  * parameter.
        !           292:  */
        !           293: drioctl(dev, cmd, data)
        !           294:        dev_t dev;
        !           295:        int cmd;
        !           296:        long *data;
        !           297: {
        !           298:        register int unit = RSUNIT(dev);
        !           299:        register struct dr_aux *dra;
        !           300:        register struct rsdevice *rsaddr = RSADDR(unit);
        !           301:        int s, error = 0;
        !           302:        u_short status;
        !           303:        long temp;
        !           304: 
        !           305: #ifdef DR_DEBUG
        !           306:        if (DR11 & 0x10)
        !           307:                printf("\ndrioctl: (dev:%lx)(cmd:%lx)(data:%lx)(data[0]:%lx)",
        !           308:                    dev,cmd,data,data[0]);
        !           309: #endif
        !           310:        dra = &dr_aux[unit];
        !           311:        dra->dr_cmd = 0;        /* Fresh copy; clear all previous flags */
        !           312:        switch (cmd) {
        !           313: 
        !           314:        case DRWAIT:            /* Wait for attention interrupt */
        !           315: #ifdef DR_DEBUG
        !           316:                printf("\ndrioctl: wait for attention interrupt");
        !           317: #endif
        !           318:                s = SPL_UP();
        !           319:                /* 
        !           320:                 * If the attention flag in dr_flags is set, it probably
        !           321:                 * means that an attention has arrived by the time a
        !           322:                 * previous DMA end-of-range interrupt was serviced. If
        !           323:                 * ATRX is set, we will return with out sleeping, since
        !           324:                 * we have received an attention since the last call to
        !           325:                 * wait on attention.  This may not be appropriate for
        !           326:                 * some applications.
        !           327:                 */
        !           328:                if ((dra->dr_flags & DR_ATRX) == 0) {
        !           329:                        dra->dr_flags |= DR_ATWT;       /* Set waiting flag */
        !           330:                        /*
        !           331:                         * Enable interrupt; use pulse reg.
        !           332:                         * so function bits are not changed
        !           333:                         */
        !           334:                        rsaddr->dr_pulse = IENB;
        !           335:                        error = tsleep((caddr_t)&dra->dr_cmd, DRPRI | PCATCH,
        !           336:                            devio, 0);
        !           337:                }
        !           338:                splx(s);
        !           339:                break;
        !           340: 
        !           341:        case DRPIOW:                    /* Write to p-i/o register */
        !           342:                rsaddr->dr_data = data[0];
        !           343:                break;
        !           344: 
        !           345:        case DRPACL:                    /* Send pulse to device */
        !           346:                rsaddr->dr_pulse = FCN2;
        !           347:                break;
        !           348: 
        !           349:        case DRDACL:                    /* Defer alco pulse until go */
        !           350:                dra->dr_cmd |= DR_DACL;
        !           351:                break;
        !           352: 
        !           353:        case DRPCYL:                    /* Set cycle with next go */
        !           354:                dra->dr_cmd |= DR_PCYL;
        !           355:                break;
        !           356: 
        !           357:        case DRDFCN:                    /* Update function with next go */
        !           358:                dra->dr_cmd |= DR_DFCN;
        !           359:                break;
        !           360: 
        !           361:        case DRRATN:                    /* Reset attention flag */
        !           362:                rsaddr->dr_pulse = RATN;
        !           363:                break;
        !           364: 
        !           365:        case DRRDMA:                    /* Reset DMA e-o-r flag */
        !           366:                rsaddr->dr_pulse = RDMA;
        !           367:                break;
        !           368: 
        !           369:        case DRSFCN:                    /* Set function bits */
        !           370:                temp = data[0] & DR_FMSK;
        !           371:                /*
        !           372:                 * This has a very important side effect -- It clears
        !           373:                 * the interrupt enable flag. That is fine for this driver,
        !           374:                 * but if it is desired to leave interrupt enable at all
        !           375:                 * times, it will be necessary to read the status register
        !           376:                 * first to get IENB, or carry a software flag that indicates
        !           377:                 * whether interrupts are set, and or this into the control
        !           378:                 * register value being written.
        !           379:                 */
        !           380:                rsaddr->dr_cstat = temp;
        !           381:                break;
        !           382: 
        !           383:        case DRRPER:                    /* Clear parity flag */
        !           384:                rsaddr->dr_pulse = RPER;
        !           385:                break;
        !           386: 
        !           387:        case DRSETRSTALL:               /* Set read stall mode. */
        !           388:                dra->dr_flags &= (~DR_NORSTALL);
        !           389:                break;
        !           390: 
        !           391:        case DRSETNORSTALL:             /* Set no stall read  mode. */
        !           392:                dra->dr_flags |= DR_NORSTALL;
        !           393:                break;
        !           394: 
        !           395:        case DRGETRSTALL:               /* Returns true if in read stall mode */
        !           396:                data[0]  = (dra->dr_flags & DR_NORSTALL)? 0 : 1;
        !           397:                break;
        !           398: 
        !           399:        case DRSETRTIMEOUT:             /* Set read stall timeout (1/10 secs) */
        !           400:                if (data[0] < 1)
        !           401:                        error = EINVAL;
        !           402:                dra->rtimoticks = (data[0] * hz )/10;
        !           403:                break;
        !           404: 
        !           405:        case DRGETRTIMEOUT:             /* Return read stall timeout */
        !           406:                data[0] = ((dra->rtimoticks)*10)/hz;
        !           407:                break;
        !           408: 
        !           409:        case DRSETWSTALL:               /* Set write stall mode. */
        !           410:                dra->dr_flags &= (~DR_NOWSTALL);
        !           411:                break;
        !           412: 
        !           413:        case DRSETNOWSTALL:             /* Set write stall mode. */
        !           414:                dra->dr_flags |= DR_NOWSTALL;
        !           415:                break;
        !           416: 
        !           417:        case DRGETWSTALL:               /* Return true if in write stall mode */
        !           418:                data[0] = (dra->dr_flags & DR_NOWSTALL)? 0 : 1;
        !           419:                break;
        !           420: 
        !           421:        case DRSETWTIMEOUT:             /* Set write stall timeout (1/10's) */
        !           422:                if (data[0] < 1)
        !           423:                        error = EINVAL;
        !           424:                dra->wtimoticks = (data[0] * hz )/10;
        !           425:                break;
        !           426: 
        !           427:        case DRGETWTIMEOUT:             /* Return write stall timeout */
        !           428:                data[0] = ((dra->wtimoticks)*10)/hz;
        !           429:                break;
        !           430: 
        !           431:        case DRWRITEREADY:              /* Return true if can write data */
        !           432:                data[0] = (rsaddr->dr_cstat & STTA)? 1 : 0;
        !           433:                break;
        !           434: 
        !           435:        case DRREADREADY:               /* Return true if data to be read */
        !           436:                data[0] = (rsaddr->dr_cstat & STTB)? 1 : 0;
        !           437:                break;
        !           438: 
        !           439:        case DRBUSY:                    /* Return true if device busy */
        !           440:                /*
        !           441:                 * Internally this is the DR11-W
        !           442:                 * STAT C bit, but there is a bug in the Omega 500/FIFO
        !           443:                 * interface board that it cannot drive this signal low
        !           444:                 * for certain DR11-W ctlr such as the Ikon. We use the
        !           445:                 * REDY signal of the CSR on the Ikon DR11-W instead. 
        !           446:                 */
        !           447: #ifdef notdef
        !           448:                data[0] = (rsaddr->dr_cstat & STTC)? 1 : 0;
        !           449: #else
        !           450:                data[0] = ((rsaddr->dr_cstat & REDY)? 0 : 1);
        !           451: #endif
        !           452:                break;
        !           453: 
        !           454:        case DRRESET:                   /* Reset device */
        !           455:                /* Reset DMA ATN RPER flag */
        !           456:                rsaddr->dr_pulse = (MCLR|RDMA|RATN|RPER);
        !           457:                DELAY(0x1f000);
        !           458:                while ((rsaddr->dr_cstat & REDY) == 0 && error == 0)
        !           459:                        /* Wakeup by drtimo() */
        !           460:                        error = tsleep((caddr_t)dra, DRPRI | PCATCH, devio, 0); 
        !           461:                dra->dr_istat = 0;
        !           462:                dra->dr_cmd = 0;
        !           463:                dra->currenttimo = 0;
        !           464:                break;
        !           465: 
        !           466:        case DR11STAT: {                /* Copy back dr11 status to user */
        !           467:                register struct dr11io *dr = (struct dr11io *)data;
        !           468:                dr->arg[0] = dra->dr_flags;
        !           469:                dr->arg[1] = rsaddr->dr_cstat;
        !           470:                dr->arg[2] = dra->dr_istat;     /* Status at last interrupt */
        !           471:                dr->arg[3] = rsaddr->dr_data;   /* P-i/o input data */
        !           472:                status = (u_short)((rsaddr->dr_addmod << 8) & 0xff00);
        !           473:                dr->arg[4] = status | (u_short)(rsaddr->dr_intvect & 0xff);
        !           474:                dr->arg[5] = rsaddr->dr_range;
        !           475:                dr->arg[6] = rsaddr->dr_rahi;
        !           476:                dr->arg[7] = rsaddr->dr_ralo;
        !           477:                break;
        !           478:        }
        !           479:        case DR11LOOP:                  /* Perform loopback test */
        !           480:                /*
        !           481:                 * NB: MUST HAVE LOOPBACK CABLE ATTACHED --
        !           482:                 * Test results are printed on system console
        !           483:                 */
        !           484:                if (error = suser(u.u_cred, &u.u_acflag))
        !           485:                        break;
        !           486:                dr11loop(rsaddr, dra, unit);
        !           487:                break;
        !           488: 
        !           489:        default:
        !           490:                return (EINVAL);
        !           491:        }
        !           492: #ifdef DR_DEBUG
        !           493:        if (DR11 & 0x10)
        !           494:                printf("**** (data[0]:%lx)",data[0]);
        !           495: #endif
        !           496:        return (error);
        !           497: }
        !           498: 
        !           499: #define NPAT   2
        !           500: #define DMATBL 20
        !           501: u_short        tstpat[DMATBL] = { 0xAAAA, 0x5555};
        !           502: long   DMAin = 0;
        !           503: 
        !           504: /*
        !           505:  * Perform loopback test -- MUST HAVE LOOPBACK CABLE ATTACHED
        !           506:  * Test results are printed on system console
        !           507:  */
        !           508: dr11loop(dr, dra, unit)
        !           509:        struct rsdevice *dr;
        !           510:        struct dr_aux *dra;
        !           511:        int unit;
        !           512: {
        !           513:        register long result, ix;
        !           514:        long addr, wait;
        !           515: 
        !           516:        dr->dr_cstat = MCLR;            /* Clear board & device, disable intr */
        !           517:        printf("\n\t ----- DR11 unit %ld loopback test -----", unit);
        !           518:        printf("\n\t Program I/O ...");
        !           519:        for (ix=0;ix<NPAT;ix++) {
        !           520:                dr->dr_data = tstpat[ix];       /* Write to Data out register */
        !           521:                result = dr->dr_data & 0xFFFF;  /* Read it back */
        !           522:                if (result != tstpat[ix]) {
        !           523:                        printf("Failed, expected : %lx --- actual : %lx",
        !           524:                                tstpat[ix], result);
        !           525:                        return;
        !           526:                }
        !           527:        }
        !           528:        printf("OK\n\t Functions & Status Bits ...");
        !           529:        dr->dr_cstat = (FCN1 | FCN3);
        !           530:        result = dr->dr_cstat & 0xffff;         /* Read them back */
        !           531:        if ((result & (STTC | STTA)) != (STTC |STTA)) {
        !           532:                printf("Failed, expected : %lx --- actual : %lx, ISR:%lx",
        !           533:                        (STTA|STTC), (result & (STTA|STTC)), result);
        !           534:                return;
        !           535:        }
        !           536:        dr->dr_cstat = FCN2;
        !           537:        result = dr->dr_cstat & 0xffff;         /* Read them back */
        !           538:        if ((result & STTB) != STTB) {
        !           539:                printf("Failed, expected : %lx --- actual : %lx, ISR:%lx",
        !           540:                        STTB, (result & STTB), result);
        !           541:                return;
        !           542:        }
        !           543:        printf("OK\n\t DMA output ...");
        !           544:        if (DMAin)
        !           545:                goto dmain;
        !           546:        /* Initialize DMA data buffer */
        !           547:        for (ix=0; ix<DMATBL; ix++)
        !           548:                tstpat[ix] = 0xCCCC + ix;
        !           549:        tstpat[DMATBL-1] = 0xCCCC;      /* Last word output */
        !           550:        /* Setup normal DMA */
        !           551:        addr = (long)vtoph((struct proc *)0, (unsigned)tstpat);
        !           552:        dr->dr_walo = (addr >> 1) & 0xffff;
        !           553:        dr->dr_wahi = (addr >> 17) & 0x7fff;
        !           554:        /* Set DMA range count: (number of words - 1) */
        !           555:        dr->dr_range = DMATBL - 1;
        !           556:        /* Set address modifier code to be used for DMA access to memory */
        !           557:        dr->dr_addmod = DRADDMOD;
        !           558: 
        !           559:        /*
        !           560:         * Clear dmaf and attf to assure a clean dma start, also disable
        !           561:         * attention interrupt
        !           562:         */
        !           563:        dr->dr_pulse = RDMA|RATN|RMSK;  /* Use pulse register */
        !           564:        dr->dr_cstat = GO|CYCL;           /* GO...... */
        !           565: 
        !           566:        /* Wait for DMA complete; REDY and DMAF are true in ISR */
        !           567:        wait = 0;
        !           568:        while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) {
        !           569:                printf("\n\tWait for DMA complete...ISR : %lx", result);
        !           570:                if (++wait > 5) {
        !           571:                        printf("\n\t DMA output fails...timeout!!, ISR:%lx",
        !           572:                                result);
        !           573:                        return;
        !           574:                }
        !           575:        }
        !           576:        result = dr->dr_data & 0xffff;          /* Read last word output */     
        !           577:        if (result != 0xCCCC) {
        !           578:                printf("\n\t Fails, expected : %lx --- actual : %lx",
        !           579:                        0xCCCC, result);
        !           580:                return;
        !           581:        }
        !           582:        printf("OK\n\t DMA input ...");
        !           583: dmain:
        !           584:        dr->dr_data = 0x1111;           /* DMA input data */
        !           585:        /* Setup normal DMA */
        !           586:        addr = (long)vtoph((struct proc *)0, (unsigned)tstpat);
        !           587:        dr->dr_walo = (addr >> 1) & 0xffff;
        !           588:        dr->dr_wahi = (addr >> 17) & 0x7fff;
        !           589:        dr->dr_range = DMATBL - 1;
        !           590:        dr->dr_addmod = (char)DRADDMOD;
        !           591:        dr->dr_cstat = FCN1;            /* Set FCN1 in ICR to DMA in*/
        !           592:        if ((dra->dr_flags & DR_LOOPTST) == 0) {
        !           593:                /* Use pulse reg */  
        !           594:                dr->dr_pulse = RDMA|RATN|RMSK|CYCL|GO;
        !           595:                /* Wait for DMA complete; REDY and DMAF are true in ISR */
        !           596:                wait = 0;
        !           597:                while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) {
        !           598:                        printf("\n\tWait for DMA to complete...ISR:%lx",result);
        !           599:                        if (++wait > 5) {
        !           600:                                printf("\n\t DMA input timeout!!, ISR:%lx",
        !           601:                                        result);
        !           602:                                return;
        !           603:                        }
        !           604:                }
        !           605:        } else  {
        !           606:                /* Enable DMA e-o-r interrupt */
        !           607:                dr->dr_pulse = IENB|RDMA|RATN|CYCL|GO;
        !           608:                /* Wait for DMA complete; DR_LOOPTST is false in dra->dr_flags*/
        !           609:                wait = 0;
        !           610:                while (dra->dr_flags & DR_LOOPTST) { 
        !           611:                        result = dr->dr_cstat & 0xffff;
        !           612:                        printf("\n\tWait for DMA e-o-r intr...ISR:%lx", result);
        !           613:                        if (++wait > 7) {
        !           614:                                printf("\n\t DMA e-o-r timeout!!, ISR:%lx",
        !           615:                                        result);
        !           616:                                dra->dr_flags &= ~DR_LOOPTST;
        !           617:                                return;
        !           618:                        }
        !           619:                }
        !           620:                dra->dr_flags |= DR_LOOPTST;
        !           621:        }
        !           622:        mtpr(P1DC, tstpat);                     /* Purge cache */
        !           623:        mtpr(P1DC, 0x3ff+tstpat);
        !           624:        for (ix=0; ix<DMATBL; ix++) {
        !           625:                if (tstpat[ix] != 0x1111) {
        !           626:                        printf("\n\t Fails, ix:%d, expected:%x --- actual:%x",
        !           627:                                ix, 0x1111, tstpat[ix]);
        !           628:                        return;
        !           629:                }
        !           630:        }
        !           631:        if ((dra->dr_flags & DR_LOOPTST) == 0) {
        !           632:                dra->dr_flags |= DR_LOOPTST;
        !           633:                printf(" OK..\n\tDMA end of range interrupt...");
        !           634:                goto dmain;
        !           635:        }
        !           636:        printf(" OK..\n\tAttention interrupt....");
        !           637:        dr->dr_pulse = IENB|RDMA;
        !           638:        dr->dr_pulse = FCN2;
        !           639:        /* Wait for ATTN interrupt; DR_LOOPTST is false in dra->dr_flags*/
        !           640:        wait = 0;
        !           641:        while (dra->dr_flags & DR_LOOPTST) { 
        !           642:                result = dr->dr_cstat & 0xffff;
        !           643:                printf("\n\tWait for Attention intr...ISR:%lx",result);
        !           644:                if (++wait > 7) {
        !           645:                        printf("\n\t Attention interrupt timeout!!, ISR:%lx",
        !           646:                                result);
        !           647:                        dra->dr_flags &= ~DR_LOOPTST;
        !           648:                        return;
        !           649:                }
        !           650:        }
        !           651:        dra->dr_flags &= ~DR_LOOPTST;
        !           652:        printf(" OK..\n\tDone...");
        !           653: }
        !           654: 
        !           655: /* Reset state on Unibus reset */
        !           656: /*ARGSUSED*/
        !           657: drreset(uban)
        !           658:        int uban;
        !           659: {
        !           660: 
        !           661: }
        !           662: 
        !           663: /*
        !           664:  * An interrupt is caused either by an error,
        !           665:  * base address overflow, or transfer complete
        !           666:  */
        !           667: drintr(dr11)
        !           668:        int dr11;
        !           669: {
        !           670:        register struct dr_aux *dra = &dr_aux[dr11];
        !           671:        register struct rsdevice *rsaddr = RSADDR(dr11);
        !           672:        register struct buf *bp;
        !           673:        register short status;
        !           674: 
        !           675:        status = rsaddr->dr_cstat & 0xffff;     /* get board status register */
        !           676:        dra->dr_istat = status;
        !           677: #ifdef DR_DEBUG
        !           678:        if (DR11 & 2)
        !           679:                printf("\ndrintr: dr11 status : %lx",status & 0xffff);
        !           680: #endif
        !           681:        if (dra->dr_flags & DR_LOOPTST) {       /* doing loopback test */
        !           682:                dra->dr_flags &= ~DR_LOOPTST;
        !           683:                return;
        !           684:        }
        !           685:        /*
        !           686:         * Make sure this is not a stray interrupt; at least one of dmaf or attf
        !           687:         * must be set. Note that if the dr11 interrupt enable latch is reset 
        !           688:         * during a hardware interrupt ack sequence, and by the we get to this 
        !           689:         * point in the interrupt code it will be 0. This is done to give the
        !           690:         * programmer some control over how the two more-or-less independent
        !           691:         * interrupt sources on the board are handled.
        !           692:         * If the attention flag is set when drstrategy() is called to start a
        !           693:         * dma read or write an interrupt will be generated as soon as the
        !           694:         * strategy routine enables interrupts for dma end-of-range. This will
        !           695:         * cause execution of the interrupt routine (not necessarily bad) and
        !           696:         * will cause the interrupt enable mask to be reset (very bad since the
        !           697:         * dma end-of-range condition will not be able to generate an interrupt
        !           698:         * when it occurs) causing the dma operation to time-out (even though
        !           699:         * the dma transfer will be done successfully) or hang the process if a
        !           700:         * software time-out capability is not implemented. One way to avoid 
        !           701:         * this situation is to check for a pending attention interrupt (attf
        !           702:         * set) by calling drioctl() before doing a read or a write. For the
        !           703:         * time being this driver will solve the problem by clearing the attf
        !           704:         * flag in the status register before enabling interrupts in
        !           705:         * drstrategy().
        !           706:         *
        !           707:         * **** The IKON 10084 for which this driver is written will set both
        !           708:         * attf and dmaf if dma is terminated by an attention pulse. This will
        !           709:         * cause a wakeup(&dr_aux), which will be ignored since it is not being 
        !           710:         * waited on, and an iodone(bp) which is the desired action. Some other
        !           711:         * dr11 emulators, in particular the IKON 10077 for the Multibus, donot
        !           712:         * dmaf in this case. This may require some addtional code in the inter-
        !           713:         * rupt routine to ensure that en iodone(bp) is issued when dma is term-
        !           714:         * inated by attention.
        !           715:         */
        !           716:        bp = dra->dr_actf;
        !           717:        if ((status & (ATTF | DMAF)) == 0) {
        !           718:                printf("dr%d: stray interrupt, status=%x", dr11, status);
        !           719:                return;
        !           720:        }
        !           721:        if (status & DMAF) {            /* End-of-range interrupt */
        !           722:                dra->dr_flags |= DR_DMAX;
        !           723: 
        !           724: #ifdef DR_DEBUG
        !           725:                if (DR11 & 2)
        !           726:                printf("\ndrintr: e-o-r interrupt,cstat:%lx,dr_flags:%lx",
        !           727:                        status&0xffff, dra->dr_flags & DR_ACTV);
        !           728: #endif
        !           729:                if ((dra->dr_flags & DR_ACTV) == 0) {
        !           730:                        /* We are not doing DMA !! */
        !           731:                        bp->b_flags |= B_ERROR;
        !           732:                } else {
        !           733:                        if (dra->dr_op == DR_READ)
        !           734:                                mtpr(P1DC, bp->b_un.b_addr);
        !           735:                        dra->dr_bycnt -= bp->b_bcount;
        !           736:                        if (dra->dr_bycnt >0) {
        !           737:                                bp->b_un.b_addr += bp->b_bcount;
        !           738:                                bp->b_bcount = (dra->dr_bycnt > NBPG) ? NBPG:
        !           739:                                        dra->dr_bycnt;
        !           740:                                drstart(rsaddr, dra, bp);
        !           741:                                return;
        !           742:                        }
        !           743:                }
        !           744:                dra->dr_flags &= ~DR_ACTV;
        !           745:                wakeup((caddr_t)dra);           /* Wakeup waiting in drwait() */
        !           746:                rsaddr->dr_pulse = (RPER|RDMA|RATN); /* reset dma e-o-r flag */
        !           747:        }
        !           748:        /*
        !           749:         * Now test for attention interrupt -- It may be set in addition to 
        !           750:         * the dma e-o-r interrupt. If we get one we will issue a wakeup to
        !           751:         * the drioctl() routine which is presumable waiting for one.
        !           752:         * The program may have to monitor the attention interrupt received
        !           753:         * flag in addition to doing waits for the interrupt. Futhermore, 
        !           754:         * interrupts are not enabled unless dma is in progress or drioctl()
        !           755:         * has been called to wait for attention -- this may produce some
        !           756:         * strange results if attf is set on the dr11 when a read or a write
        !           757:         * is initiated, since that will enables interrupts.
        !           758:         * **** The appropriate code for this interrupt routine will probably
        !           759:         * be rather application dependent.
        !           760:         */
        !           761:        if (status & ATTF) {
        !           762:                dra->dr_flags |= DR_ATRX;
        !           763:                dra->dr_flags &= ~DR_ATWT;
        !           764:                rsaddr->dr_cstat = RATN;        /* reset attention flag */
        !           765:                /*
        !           766:                 * Some applications which use attention to terminate
        !           767:                 * dma may also want to issue an iodone() here to
        !           768:                 * wakeup physio().
        !           769:                 */
        !           770:                wakeup((caddr_t)&dra->dr_cmd);
        !           771:        }
        !           772: }
        !           773: 
        !           774: unsigned
        !           775: drminphys(bp)
        !           776:        struct buf *bp;
        !           777: {
        !           778: 
        !           779:        if (bp->b_bcount > 65536)
        !           780:                bp->b_bcount = 65536;
        !           781: }
        !           782: 
        !           783: /*
        !           784:  * This routine performs the device unique operations on the DR11W
        !           785:  * it is passed as an argument to and invoked by physio
        !           786:  */
        !           787: drstrategy (bp)
        !           788:        register struct buf *bp;
        !           789: {
        !           790:        register int s;
        !           791:        int unit = RSUNIT(bp->b_dev);
        !           792:        register struct rsdevice *rsaddr = RSADDR(unit);
        !           793:        register struct dr_aux *dra = &dr_aux[unit];
        !           794:        register int ok;
        !           795: #ifdef DR_DEBUG
        !           796:        register char *caddr;
        !           797:        long drva();
        !           798: #endif
        !           799: 
        !           800:        if ((dra->dr_flags & DR_OPEN) == 0) {   /* Device not open */
        !           801:                bp->b_error = ENXIO;
        !           802:                bp->b_flags |= B_ERROR;
        !           803:                iodone (bp);
        !           804:                return;
        !           805:        }
        !           806:        while (dra->dr_flags & DR_ACTV)
        !           807:                /* Device is active; should never be in here... */
        !           808:                (void) tsleep((caddr_t)&dra->dr_flags, DRPRI, devio, 0);
        !           809:        dra->dr_actf = bp;
        !           810: #ifdef DR_DEBUG
        !           811:        drva(dra, bp->b_proc, bp->b_un.b_addr, bp->b_bcount);
        !           812: #endif
        !           813:        dra->dr_oba = bp->b_un.b_addr;  /* Save original addr, count */
        !           814:        dra->dr_obc = bp->b_bcount;
        !           815:        dra->dr_bycnt = bp->b_bcount;   /* Save xfer count used by drintr() */
        !           816:        if ((((long)bp->b_un.b_addr & 0x3fffffff) >> PGSHIFT) !=
        !           817:            ((((long)bp->b_un.b_addr & 0x3fffffff) + bp->b_bcount) >> PGSHIFT))
        !           818:                bp->b_bcount = NBPG - (((long)bp->b_un.b_addr) & PGOFSET);
        !           819:        dra->dr_flags |= DR_ACTV;       /* Mark active (use in intr handler) */
        !           820:        s = SPL_UP();
        !           821:        drstart(rsaddr,dra,bp);
        !           822:        splx(s);
        !           823:        ok = drwait(rsaddr,dra);
        !           824: #ifdef DR_DEBUG
        !           825:        if (DR11 & 0x40) {
        !           826:                caddr = (char *)dra->dr_oba;
        !           827:                if (dra->dr_op == DR_READ)
        !           828:                        printf("\nAfter read: (%lx)(%lx)",
        !           829:                            caddr[0]&0xff, caddr[1]&0xff);
        !           830:        }
        !           831: #endif
        !           832:        dra->dr_flags &= ~DR_ACTV;              /* Clear active flag */
        !           833:        bp->b_un.b_addr = dra->dr_oba;  /* Restore original addr, count */
        !           834:        bp->b_bcount = dra->dr_obc;
        !           835:        if (!ok)
        !           836:                bp->b_flags |= B_ERROR;
        !           837:        /* Mark buffer B_DONE,so physstrat() in ml/machdep.c won't sleep */
        !           838:        iodone(bp);                     
        !           839:        wakeup((caddr_t)&dra->dr_flags);
        !           840:        /*
        !           841:         * Return to the calling program (physio()). Physio() will sleep
        !           842:         * until awaken by a call to iodone() in the interupt handler --
        !           843:         * which will be called by the dispatcher when it receives dma
        !           844:         * end-of-range interrupt.
        !           845:         */
        !           846: }
        !           847: 
        !           848: drwait(rs, dr)
        !           849:        register struct rsdevice *rs;
        !           850:        register struct dr_aux *dr;
        !           851: {
        !           852:        int s;
        !           853: 
        !           854:        s = SPL_UP();
        !           855:        while (dr->dr_flags & DR_ACTV)
        !           856:                (void) tsleep((caddr_t)dr, DRPRI, devio, 0);
        !           857:        splx(s);
        !           858:        if (dr->dr_flags & DR_TMDM) {           /* DMA timed out */
        !           859:                dr->dr_flags &= ~DR_TMDM;
        !           860:                return (0);
        !           861:        }
        !           862:        if (rs->dr_cstat & (PERR|BERR|TERR)) {
        !           863:                dr->dr_actf->b_flags |= B_ERROR;
        !           864:                return (0);
        !           865:        }
        !           866:        dr->dr_flags &= ~DR_DMAX;
        !           867:        return (1);
        !           868: }
        !           869: 
        !           870: /*
        !           871:  *
        !           872:  * The lower 8-bit of tinfo is the minor device number, the
        !           873:  * remaining higher 8-bit is the current timout number
        !           874:  */
        !           875: drrwtimo(tinfo)
        !           876:        register u_long tinfo;
        !           877: {
        !           878:        register long unit = tinfo & 0xff;
        !           879:        register struct dr_aux *dr = &dr_aux[unit];
        !           880:        register struct rsdevice *rs = dr->dr_addr;
        !           881: 
        !           882:        /*
        !           883:         * If this is not the timeout that drwrite/drread is waiting
        !           884:         * for then we should just go away
        !           885:         */
        !           886:        if ((tinfo &~ 0xff) != (dr->currenttimo << 8))
        !           887:                return;
        !           888:        /* Mark the device timed out */
        !           889:        dr->dr_flags |= DR_TMDM;
        !           890:        dr->dr_flags &= ~DR_ACTV;
        !           891:        rs->dr_pulse = RMSK;                    /* Inihibit interrupt */
        !           892:        rs->dr_pulse = (RPER|RDMA|RATN|IENB);   /* Clear DMA logic */
        !           893:        /*
        !           894:         * Some applications will not issue a master after dma timeout,
        !           895:         * since doing so sends an INIT H pulse to the external device,
        !           896:         * which may produce undesirable side-effects.
        !           897:         */
        !           898:        /* Wake up process waiting in drwait() and flag the error */
        !           899:        dr->dr_actf->b_flags |= B_ERROR;
        !           900:        wakeup((caddr_t)dr->dr_cmd);
        !           901: }
        !           902: 
        !           903: /*
        !           904:  * Kick the driver every second
        !           905:  */
        !           906: drtimo(dev)
        !           907:        dev_t dev;
        !           908: {
        !           909:        register int unit = RSUNIT(dev);
        !           910:        register struct dr_aux *dr;
        !           911: 
        !           912:        dr = &dr_aux[unit];
        !           913:        if (dr->dr_flags & DR_OPEN)
        !           914:                timeout(drtimo, (caddr_t)dev, hz);
        !           915:        wakeup((caddr_t)dr);    /* Wakeup any process waiting for interrupt */
        !           916: }
        !           917: 
        !           918: #ifdef DR_DEBUG
        !           919: drva(dra, p, va, bcnt)
        !           920:        struct dr_aux *dra;
        !           921:        struct proc *p;
        !           922:        char *va;
        !           923:        long bcnt;
        !           924: {
        !           925:        register long first, last , np;
        !           926: 
        !           927:        if (DR11 & 0x20)  {
        !           928:                first = ((long)(vtoph(p, (unsigned)va))) >> 10;
        !           929:                last = ((long)(vtoph(p, (unsigned)va+bcnt))) >> 10;
        !           930:                np = bcnt / 0x3ff;
        !           931:                printf("\ndrva: (op:%ld)(first:%ld)(last:%ld)(np:%ld)(cnt:%ld)",
        !           932:                        dra->dr_op,first,last,np,bcnt);
        !           933:        }
        !           934: }
        !           935: #endif
        !           936: 
        !           937: drstart(rsaddr, dra, bp)
        !           938:        register struct rsdevice *rsaddr;
        !           939:        register struct dr_aux *dra;
        !           940:        register struct buf *bp;
        !           941: {
        !           942:        register long addr;
        !           943:        u_short go;
        !           944: 
        !           945: #ifdef DR_DEBUG
        !           946:        if (dra->dr_op == DR_READ && (DR11 & 8)) {
        !           947:                char *caddr = (char *)bp->b_un.b_addr;
        !           948:                printf("\ndrstart: READ, bcnt:%ld",bp->b_bcount);
        !           949:                printf(",(%lx)(%lx)",caddr[0]&0xff,caddr[1]&0xff);
        !           950:        }
        !           951: #endif
        !           952:        /* we are doing raw IO, bp->b_un.b_addr is user's address */
        !           953:        addr = (long)vtoph(bp->b_proc, (unsigned)bp->b_un.b_addr);
        !           954:        /*
        !           955:         * Set DMA address into DR11 interace registers: DR11 requires that
        !           956:         * the address be right shifted 1 bit position before it is written
        !           957:         * to the board (The board will left shift it one bit position before
        !           958:         * it places the address on the bus
        !           959:         */
        !           960:        rsaddr->dr_walo = (addr >> 1) & 0xffff;
        !           961:        rsaddr->dr_wahi = (addr >> 17) & 0x7fff;
        !           962:        /* Set DMA range count: (number of words - 1) */
        !           963:        rsaddr->dr_range = (bp->b_bcount >> 1) - 1;
        !           964:        /* Set address modifier code to be used for DMA access to memory */
        !           965:        rsaddr->dr_addmod = DRADDMOD;
        !           966:        /*
        !           967:         * Now determine whether this is a read or a write. ***** This is
        !           968:         * probably only usefull for link mode operation, since dr11 doesnot
        !           969:         * controll the direction of data transfer. The C1 control input 
        !           970:         * controls whether the hardware is doing a read or a write. In link
        !           971:         * mode this is controlled by function 1 latch (looped back by the
        !           972:         * cable) and could be set the program. In the general case, the dr11
        !           973:         * doesnot know in advance what the direction of transfer is - although
        !           974:         * the program and protocol logic probably is
        !           975:         */
        !           976: #ifdef DR_DEBUG
        !           977:        if (DR11 & 1)
        !           978:                printf(
        !           979: "\ndrstrat: about to GO..,dr_cmd:%lx,drstat:%lx,drcnt:%ld,cdata:%lx,OP:%ld",
        !           980:                    dra->dr_cmd, rsaddr->dr_cstat, rsaddr->dr_range,
        !           981:                    rsaddr->dr_data, dra->dr_op);
        !           982: #endif
        !           983:        /*
        !           984:         * Update function latches may have been done already by drioctl() if
        !           985:         * request from drioctl()
        !           986:         */
        !           987:        if (dra->dr_cmd & DR_DFCN) {            /* deferred function write */
        !           988:                dra->dr_cmd &= ~DR_DFCN;        /* Clear request */
        !           989:                go = dra->dr_cmd & DR_FMSK;     /* mask out fcn bits */
        !           990:                rsaddr->dr_cstat = go;          /* Write it to the board */
        !           991:        }
        !           992:        /* Clear dmaf and attf to assure a clean dma start */
        !           993:        rsaddr->dr_pulse = RATN|RDMA|RPER;
        !           994:        rsaddr->dr_cstat = IENB|GO|CYCL|dra->dr_op; /* GO...... */
        !           995:        /*
        !           996:         * Now check for software cycle request -- usually
        !           997:         * by transmitter in link mode.
        !           998:         */
        !           999:        if (dra->dr_cmd & DR_PCYL) {
        !          1000:                dra->dr_cmd &= ~DR_PCYL;        /* Clear request */
        !          1001:                rsaddr->dr_pulse = CYCL;        /* Use pulse register again */
        !          1002:        }
        !          1003:        /*
        !          1004:         * Now check for deferred ACLO FCNT2 pulse request -- usually to tell
        !          1005:         * the transmitter (via its attention) that we have enabled dma.
        !          1006:         */
        !          1007:        if (dra->dr_cmd & DR_DACL) {
        !          1008:                dra->dr_cmd &= ~DR_DACL;        /* Clear request */
        !          1009:                rsaddr->dr_pulse = FCN2;        /* Use pulse register again */
        !          1010:        }
        !          1011: }
        !          1012: #endif  NDR

unix.superglobalmegacorp.com

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