Annotation of 43BSDTahoe/sys/tahoevba/mp.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1988 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 are permitted
                      9:  * provided that the above copyright notice and this paragraph are
                     10:  * duplicated in all such forms and that any documentation,
                     11:  * advertising materials, and other materials related to such
                     12:  * distribution and use acknowledge that the software was developed
                     13:  * by the University of California, Berkeley.  The name of the
                     14:  * University may not be used to endorse or promote products derived
                     15:  * from this software without specific prior written permission.
                     16:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     18:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     19:  *
                     20:  *     @(#)mp.c        7.6 (Berkeley) 7/9/88
                     21:  */
                     22: 
                     23: #include "mp.h"
                     24: #if NMP > 0
                     25: /*
                     26:  * Multi Protocol Communications Controller (MPCC).
                     27:  * Asynchronous Terminal Protocol Support.
                     28:  */
                     29: #include "param.h"
                     30: #include "ioctl.h"
                     31: #include "tty.h"
                     32: #include "dir.h"
                     33: #include "user.h"
                     34: #include "map.h"
                     35: #include "buf.h"
                     36: #include "conf.h"
                     37: #include "file.h"
                     38: #include "uio.h"
                     39: #include "errno.h"
                     40: #include "syslog.h"
                     41: #include "vmmac.h"
                     42: #include "kernel.h"
                     43: #include "clist.h"
                     44: 
                     45: #include "../machine/pte.h"
                     46: #include "../machine/mtpr.h"
                     47: 
                     48: #include "../tahoevba/vbavar.h"
                     49: #include "../tahoevba/mpreg.h"
                     50: 
                     51: #define        MPCHUNK 16
                     52: #define        MPPORT(n)       ((n) & 0xf)
                     53: #define        MPUNIT(n)       ((n) >> 4)
                     54: 
                     55: /*
                     56:  * Driver information for auto-configuration stuff.
                     57:  */
                     58: int     mpprobe(), mpattach(), mpintr();
                     59: struct  vba_device *mpinfo[NMP];
                     60: long    mpstd[] = { 0 };
                     61: struct  vba_driver mpdriver =
                     62:     { mpprobe, 0, mpattach, 0, mpstd, "mp", mpinfo };
                     63: 
                     64: int    mpstart();
                     65: struct mpevent *mpparam();
                     66: struct mpevent *mp_getevent();
                     67: 
                     68: /*
                     69:  * The following structure is needed to deal with mpcc's convoluted
                     70:  * method for locating it's mblok structures (hold your stomach).
                     71:  * When an mpcc is reset at boot time it searches host memory
                     72:  * looking for a string that says ``ThIs Is MpCc''.  The mpcc
                     73:  * then reads the structure to locate the pointer to it's mblok
                     74:  * structure (you can wretch now).
                     75:  */
                     76: struct mpbogus {
                     77:        char    s[12];                  /* `ThIs Is MpCc'' */
                     78:        u_char  status;
                     79:        u_char  unused;
                     80:        u_short magic;
                     81:        struct  mblok *mb;
                     82:        struct  mblok *mbloks[NMP];     /* can support at most 16 mpcc's */
                     83: } mpbogus = { 'T','h','I','s',' ','I','s',' ','M','p','C','c' };
                     84: 
                     85: /*
                     86:  * Software state per unit.
                     87:  */
                     88: struct mpsoftc {
                     89:        u_int   ms_ivec;                /* interrupt vector */
                     90:        u_int   ms_softCAR;             /* software carrier for async */
                     91:        struct  mblok *ms_mb;           /* mpcc status area */
                     92:        struct  vb_buf ms_buf;          /* vba resources for ms_mb */
                     93:        struct  hxmtl ms_hxl[MPMAXPORT];/* host transmit list */
                     94:        struct  asyncparam ms_async[MPMAXPORT][MPINSET];/* async structs */
                     95:        char    ms_cbuf[MPMAXPORT][MPOUTSET][CBSIZE];/* input character buffers */
                     96: } mp_softc[NMP];
                     97: 
                     98: struct tty mp_tty[NMP*MPCHUNK];
                     99: #ifndef lint
                    100: int    nmp = NMP*MPCHUNK;
                    101: #endif
                    102: 
                    103: int    ttrstrt();
                    104: 
                    105: mpprobe(reg, vi)
                    106:        caddr_t reg;
                    107:        struct vba_device *vi;
                    108: {
                    109:        register int br, cvec;
                    110:        register struct mpsoftc *ms;
                    111: 
                    112: #ifdef lint
                    113:        br = 0; cvec = br; br = cvec;
                    114:        mpintr(0);
                    115:        mpdlintr(0);
                    116: #endif
                    117:        if (badaddr(reg, 2))
                    118:                return (0);
                    119:        ms = &mp_softc[vi->ui_unit];
                    120:        /*
                    121:         * Allocate page tables and mblok
                    122:         * structure (mblok in non-cached memory).
                    123:         */
                    124:        if (vbainit(&ms->ms_buf, sizeof (struct mblok), VB_32BIT) == 0) {
                    125:                printf("mp%d: vbainit failed\n", vi->ui_unit);
                    126:                return (0);
                    127:        }
                    128:        ms->ms_mb = (struct mblok *)ms->ms_buf.vb_rawbuf;
                    129:        ms->ms_ivec = MPINTRBASE + 2*vi->ui_unit;       /* XXX */
                    130:        br = 0x14, cvec = ms->ms_ivec;                  /* XXX */
                    131:        return (sizeof (*reg));
                    132: }
                    133: 
                    134: mpattach(vi)
                    135:        register struct vba_device *vi;
                    136: {
                    137:        register struct mpsoftc *ms = &mp_softc[vi->ui_unit];
                    138: 
                    139:        ms->ms_softCAR = vi->ui_flags;
                    140:        /*
                    141:         * Setup pointer to mblok, initialize bogus
                    142:         * status block used by mpcc to locate the pointer
                    143:         * and then poke the mpcc to get it to search host
                    144:         * memory to find mblok pointer.
                    145:         */
                    146:        mpbogus.mbloks[vi->ui_unit] = (struct mblok *)ms->ms_buf.vb_physbuf;
                    147:        *(short *)vi->ui_addr = 0x100;          /* magic */
                    148: }
                    149: 
                    150: /*
                    151:  * Open an mpcc port.
                    152:  */
                    153: /* ARGSUSED */
                    154: mpopen(dev, mode)
                    155:        dev_t dev;
                    156: {
                    157:        register struct tty *tp;
                    158:        register struct mpsoftc *ms;
                    159:        int error, s, port, unit, mpu;
                    160:        struct vba_device *vi;
                    161:        struct mpport *mp;
                    162:        struct mpevent *ev;
                    163: 
                    164:        unit = minor(dev);
                    165:        mpu = MPUNIT(unit);
                    166:        if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0)
                    167:                return (ENXIO);
                    168:        tp = &mp_tty[unit];
                    169:        if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
                    170:                return (EBUSY);
                    171:        ms = &mp_softc[mpu];
                    172:        port = MPPORT(unit);
                    173:        if (ms->ms_mb->mb_proto[port] != MPPROTO_ASYNC ||
                    174:            ms->ms_mb->mb_status != MP_OPOPEN)
                    175:                return (ENXIO);
                    176:        mp = &ms->ms_mb->mb_port[port];         /* host mpcc struct */
                    177:        s = spl8();
                    178:        while (mp->mp_flags & MP_PROGRESS)
                    179:                sleep((caddr_t)&tp->t_canq, TTIPRI);
                    180:        while (tp->t_state & TS_WOPEN) 
                    181:                sleep((caddr_t)&tp->t_canq, TTIPRI);
                    182:        tp->t_state |= TS_WOPEN;
                    183:        tp->t_addr = (caddr_t)ms;
                    184:        tp->t_oproc = mpstart;
                    185:        tp->t_dev = dev;
                    186:        if ((tp->t_state & TS_ISOPEN) == 0) {
                    187:                ttychars(tp);
                    188:                if (tp->t_ispeed == 0) {
                    189:                        tp->t_ispeed = B9600;
                    190:                        tp->t_ospeed = B9600;
                    191:                        tp->t_flags = ODDP|EVENP|ECHO;
                    192:                }
                    193:                /*
                    194:                 * Initialize port state: init MPCC interface
                    195:                 * structures for port and setup modem control.
                    196:                 */
                    197:                mp->mp_proto = MPPROTO_ASYNC;           /* XXX */
                    198:                error = mpportinit(ms, mp, port);
                    199:                if (error)
                    200:                        goto bad;
                    201:                ev = mpparam(unit);
                    202:                if (ev == 0) {
                    203:                        error = ENOBUFS;
                    204:                        goto bad;
                    205:                }
                    206:                mpcmd(ev, EVCMD_OPEN, 0, ms->ms_mb, port);
                    207:        }
                    208:        while ((tp->t_state & TS_CARR_ON) == 0)
                    209:                sleep((caddr_t)&tp->t_rawq, TTIPRI);
                    210:        error = (*linesw[tp->t_line].l_open)(dev,tp);
                    211: done:
                    212:        splx(s);
                    213:        /* wakeup anyone waiting for open to complete */
                    214:        wakeup((caddr_t)&tp->t_canq);
                    215: 
                    216:        return (error);
                    217: bad:
                    218:        tp->t_state &= ~TS_WOPEN;
                    219:        goto done;
                    220: }
                    221: 
                    222: /*
                    223:  * Close an mpcc port.
                    224:  */
                    225: /* ARGSUSED */
                    226: mpclose(dev, flag)
                    227:        dev_t dev;
                    228: {
                    229:        register struct tty *tp;
                    230:        register struct mpport *mp;
                    231:        register struct mpevent *ev;
                    232:        int s, port, unit, error;
                    233:        struct mblok *mb;
                    234: 
                    235:        unit = minor(dev);
                    236:        tp = &mp_tty[unit];
                    237:        port = MPPORT(unit);
                    238:        mb = mp_softc[MPUNIT(unit)].ms_mb;
                    239:        mp = &mb->mb_port[port];
                    240:        s = spl8();
                    241:        if (mp->mp_flags & MP_PROGRESS) {       /* close in progress??? */
                    242:                if (mp->mp_flags & MP_REMBSY) {
                    243:                        mp->mp_flags &= ~MP_REMBSY;
                    244:                        splx(s);
                    245:                        return (0);
                    246:                }
                    247:                while (mp->mp_flags & MP_PROGRESS)
                    248:                        sleep((caddr_t)&tp->t_canq,TTIPRI);
                    249:        }
                    250:        error = 0;
                    251:        mp->mp_flags |= MP_PROGRESS;
                    252:        (*linesw[tp->t_line].l_close)(tp);
                    253:        ev = mp_getevent(mp, unit);
                    254:        if (ev == 0) {
                    255:                error = ENOBUFS;
                    256:                mp->mp_flags &= ~MP_PROGRESS;
                    257:                goto out;
                    258:        }
                    259:        if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
                    260:                mpmodem(unit, MMOD_OFF);
                    261:        else
                    262:                mpmodem(unit, MMOD_ON);
                    263:        mpcmd(ev, EVCMD_CLOSE, 0, mb, port);
                    264:        ttyclose(tp);
                    265: out:
                    266:        if (mp->mp_flags & MP_REMBSY)
                    267:                mpclean(mb, port);
                    268:        splx(s);
                    269:        return (error);
                    270: }
                    271: 
                    272: /*
                    273:  * Read from an mpcc port.
                    274:  */
                    275: mpread(dev, uio)
                    276:        dev_t dev;
                    277:        struct uio *uio;
                    278: {
                    279:        struct tty *tp;
                    280: 
                    281:        tp = &mp_tty[minor(dev)];
                    282:        return ((*linesw[tp->t_line].l_read)(tp, uio));
                    283: }
                    284: 
                    285: /*
                    286:  * Write to an mpcc port.
                    287:  */
                    288: mpwrite(dev, uio)
                    289:        dev_t dev;
                    290:        struct uio *uio;
                    291: {
                    292:        struct tty *tp;
                    293: 
                    294:        tp = &mp_tty[minor(dev)];
                    295:        return ((*linesw[tp->t_line].l_write)(tp, uio));
                    296: }
                    297: 
                    298: /*
                    299:  * Ioctl for a mpcc port
                    300:  */
                    301: mpioctl(dev, cmd, data, flag)
                    302:        dev_t dev;
                    303:        caddr_t data;
                    304: {
                    305:        register struct tty *tp;
                    306:        register struct mpsoftc *ms;
                    307:        register struct mpevent *ev;
                    308:        register struct mpport *mp;
                    309:        int s, port, error, unit;
                    310:        struct mblok *mb;
                    311: 
                    312:        unit = minor(dev);
                    313:        tp = &mp_tty[unit];
                    314:        ms = &mp_softc[MPUNIT(unit)];
                    315:        mb = ms->ms_mb;
                    316:        error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
                    317:        if (error >= 0)
                    318:                return (error);
                    319:        error = ttioctl(tp, cmd, data, flag);
                    320:        if (error >= 0) {
                    321:                if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
                    322:                    cmd == TIOCLBIC || cmd == TIOCLSET || cmd == TIOCSETC) {
                    323:                        ev = mpparam(unit);
                    324:                        if (ev == 0)
                    325:                                error = ENOBUFS;
                    326:                        else
                    327:                                mpcmd(ev, EVCMD_IOCTL, A_CHGALL, mb,
                    328:                                    MPPORT(unit));
                    329:                }
                    330:                return (error);
                    331:        }
                    332:        switch (cmd) {
                    333:        case TIOCSBRK:                  /* send break */
                    334:        case TIOCCBRK:                  /* clear break */
                    335:                port = MPPORT(unit);
                    336:                mp = &mb->mb_port[port];
                    337:                s = spl8();
                    338:                ev = mp_getevent(mp, unit);
                    339:                if (ev)
                    340:                        mpcmd(ev, EVCMD_IOCTL,
                    341:                            (cmd == TIOCSBRK ? A_BRKON : A_BRKOFF),
                    342:                            mb, port);
                    343:                else
                    344:                        error = ENOBUFS;
                    345:                splx(s);
                    346:                break;
                    347:        case TIOCSDTR:                  /* set dtr control line */
                    348:                break;
                    349:        case TIOCCDTR:                  /* clear dtr control line */
                    350:                break;
                    351:        default:
                    352:                error = ENOTTY;
                    353:                break;
                    354:        }
                    355:        return (error);
                    356: }
                    357: 
                    358: struct mpevent *
                    359: mpparam(unit)
                    360:        int unit;
                    361: {
                    362:        register struct mpevent *ev;
                    363:        register struct mpport *mp;
                    364:        register struct tty *tp;
                    365:        struct mblok *mb;
                    366:        struct mpsoftc *ms;
                    367:        register struct asyncparam *asp;
                    368:        int port;
                    369: 
                    370:        ms = &mp_softc[MPUNIT(unit)];
                    371:        mb = ms->ms_mb;
                    372:        port = MPPORT(unit);
                    373:        mp = &mb->mb_port[port];
                    374:        ev = mp_getevent(mp, unit);     /* XXX */
                    375:        if (ev == 0)
                    376:                return (ev);
                    377:        tp = &mp_tty[unit];
                    378:        /* YUCK */
                    379:        asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1];
                    380:        asp->ap_xon = (u_char)tp->t_startc;
                    381:        asp->ap_xoff = (u_char)tp->t_stopc;
                    382:        if ((tp->t_flags & RAW) || (tp->t_stopc == -1) || (tp->t_startc == -1))
                    383:                asp->ap_xena = MPA_DIS;
                    384:        else
                    385:                asp->ap_xena = MPA_ENA;
                    386:        asp->ap_xany = ((tp->t_flags & DECCTQ) ? MPA_DIS : MPA_ENA);
                    387: #ifdef notnow
                    388:        if (tp->t_flags & (RAW|LITOUT|PASS8)) {
                    389: #endif
                    390:                asp->ap_data = MPCHAR_8;
                    391:                asp->ap_parity = MPPAR_NONE;
                    392: #ifdef notnow
                    393:        } else {
                    394:                asp->ap_data = MPCHAR_7;
                    395:                if ((tp->t_flags & (EVENP|ODDP)) == ODDP)
                    396:                        asp->ap_parity = MPPAR_ODD;
                    397:                else
                    398:                        asp->ap_parity = MPPAR_EVEN;
                    399:        }
                    400: #endif
                    401:        if (tp->t_ospeed == B110)
                    402:                asp->ap_stop = MPSTOP_2;
                    403:        else
                    404:                asp->ap_stop = MPSTOP_1;
                    405:        if (tp->t_ospeed == EXTA || tp->t_ospeed == EXTB)
                    406:                asp->ap_baud = M19200;
                    407:        else
                    408:                asp->ap_baud = tp->t_ospeed;
                    409:        asp->ap_loop = MPA_DIS;         /* disable loopback */
                    410:        asp->ap_rtimer = A_RCVTIM;      /* default receive timer */
                    411:        if (ms->ms_softCAR & (1<<port))
                    412:                setm(&asp->ap_modem, A_DTR, ASSERT);
                    413:        else
                    414:                setm(&asp->ap_modem, A_DTR, AUTO);
                    415:        seti(&asp->ap_intena, A_DCD);
                    416:        return (ev);
                    417: }
                    418: 
                    419: mpstart(tp)
                    420:        register struct tty *tp;
                    421: {
                    422:        register struct mpevent *ev;
                    423:        register struct mpport *mp;
                    424:        struct mblok *mb;
                    425:        struct mpsoftc *ms;
                    426:        int port, unit, xcnt, n, s, i;
                    427:        struct  hxmtl *hxp;
                    428:        struct clist outq;
                    429: 
                    430:        s = spl8();
                    431:        unit = minor(tp->t_dev);
                    432:        ms = &mp_softc[MPUNIT(unit)];
                    433:        mb = ms->ms_mb;
                    434:        port = MPPORT(unit);
                    435:        mp = &mb->mb_port[port];
                    436:        hxp = &ms->ms_hxl[port];
                    437:        xcnt = 0;
                    438:        outq = tp->t_outq;
                    439:        for (i = 0; i < MPXMIT; i++) {
                    440:                if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
                    441:                        break;
                    442:                if (outq.c_cc <= TTLOWAT(tp)) {
                    443:                        if (tp->t_state & TS_ASLEEP) {
                    444:                                tp->t_state &= ~TS_ASLEEP;
                    445:                                wakeup((caddr_t)&tp->t_outq);
                    446:                        }
                    447:                        if (tp->t_wsel) {
                    448:                                selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
                    449:                                tp->t_wsel = 0;
                    450:                                tp->t_state &= ~TS_WCOLL;
                    451:                        }
                    452:                }
                    453:                if (outq.c_cc == 0)
                    454:                        break;
                    455:                /*
                    456:                 * If we're not currently busy outputting,
                    457:                 * and there is data to be output, set up
                    458:                 * port transmit structure to send to mpcc.
                    459:                 */
                    460:                if (tp->t_flags & (RAW|LITOUT))
                    461:                        n = ndqb(&outq, 0);
                    462:                else {
                    463:                        n = ndqb(&outq, 0200);
                    464:                        if (n == 0) {
                    465:                                n = getc(&outq);
                    466:                                timeout(ttrstrt, (caddr_t)tp, (n&0177)+6);
                    467:                                tp->t_state |= TS_TIMEOUT;
                    468:                                break;
                    469:                        }
                    470:                }
                    471:                hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf);
                    472:                hxp->size[i] = n;
                    473:                xcnt++;         /* count of xmts to send */
                    474:                ndadvance(&outq, n);
                    475:        }
                    476:        /*
                    477:         * If data to send, poke mpcc.
                    478:         */
                    479:        if (xcnt) {
                    480:                ev = mp_getevent(mp, unit);
                    481:                if (ev == 0) {
                    482:                        tp->t_state &= ~(TS_BUSY|TS_TIMEOUT);
                    483:                } else {
                    484:                        tp->t_state |= TS_BUSY;
                    485:                        ev->ev_count = xcnt;
                    486:                        mpcmd(ev, EVCMD_WRITE, 0, mb, MPPORT(unit));
                    487:                }
                    488:        }
                    489:        splx(s);
                    490: }
                    491: 
                    492: /*
                    493:  * Advance cc bytes from q  but don't free memory.
                    494:  */
                    495: ndadvance(q, cc)
                    496:        register struct clist *q;
                    497:        register cc;
                    498: {
                    499:        register struct cblock *bp;
                    500:        char *end;
                    501:        int rem, s;
                    502: 
                    503:        s = spltty();
                    504:        if (q->c_cc <= 0)
                    505:                goto out;
                    506:        while (cc>0 && q->c_cc) {
                    507:                bp = (struct cblock *)((int)q->c_cf & ~CROUND);
                    508:                if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
                    509:                        end = q->c_cl;
                    510:                } else {
                    511:                        end = (char *)((int)bp + sizeof (struct cblock));
                    512:                }
                    513:                rem = end - q->c_cf;
                    514:                if (cc >= rem) {
                    515:                        cc -= rem;
                    516:                        q->c_cc -= rem;
                    517:                        q->c_cf = bp->c_next->c_info;
                    518:                } else {
                    519:                        q->c_cc -= cc;
                    520:                        q->c_cf += cc;
                    521:                        break;
                    522:                }
                    523:        }
                    524:        if (q->c_cc <= 0) {
                    525:                q->c_cf = q->c_cl = NULL;
                    526:                q->c_cc = 0;
                    527:        }
                    528: out:
                    529:        splx(s);
                    530: }
                    531: 
                    532: /*
                    533:  * Stop output on a line, e.g. for ^S/^Q or output flush.
                    534:  */
                    535: /* ARGSUSED */
                    536: mpstop(tp, rw)
                    537:        register struct tty *tp;
                    538:        int rw;
                    539: {
                    540:        int s;
                    541: 
                    542:        s = spl8();
                    543:        /* XXX: DISABLE TRANSMITTER */
                    544:        if (tp->t_state & TS_BUSY) {
                    545:                if ((tp->t_state & TS_TTSTOP) == 0)
                    546:                        tp->t_state |= TS_FLUSH;
                    547:        }
                    548:        splx(s);
                    549: }
                    550: 
                    551: /*
                    552:  * Initialize an async port's MPCC state.
                    553:  */
                    554: mpportinit(ms, mp, port)
                    555:        register struct mpsoftc *ms;
                    556:        register struct mpport *mp;
                    557:        int port;
                    558: {
                    559:        register struct mpevent *ev;
                    560:        register int i;
                    561:        caddr_t ptr;
                    562: 
                    563:        mp->mp_on = mp->mp_off = 0;
                    564:        mp->mp_nextrcv = 0;
                    565:        mp->mp_flags = 0;
                    566:        ev = &mp->mp_recvq[0];
                    567:        for (i = 0; ev < &mp->mp_recvq[MPINSET]; ev++, i++) {
                    568:                ev->ev_status = EVSTATUS_FREE;
                    569:                ev->ev_cmd = 0;
                    570:                ev->ev_opts = 0;
                    571:                ev->ev_error = 0;
                    572:                ev->ev_flags = 0;
                    573:                ev->ev_count = 0;
                    574:                ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]);
                    575:                ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]);
                    576:        }
                    577:        ev = &mp->mp_sendq[0];
                    578:        for (i = 0; ev < &mp->mp_sendq[MPOUTSET]; ev++, i++) {
                    579:                /* init so that L2 can't send any events */
                    580:                /* to host until open has completed      */
                    581:                ev->ev_status = EVSTATUS_FREE;
                    582:                ev->ev_cmd = 0;
                    583:                ev->ev_error = 0;
                    584:                ev->ev_flags = 0;
                    585:                ev->ev_count = 0;
                    586:                ptr = (caddr_t) &ms->ms_cbuf[port][i][0];
                    587:                ev->ev_un.rcvblk = (u_char *)kvtophys(ptr);
                    588:                ev->ev_params = (caddr_t) kvtophys(ptr);
                    589:        }
                    590:        return (0);
                    591: }
                    592: 
                    593: /*
                    594:  * Send an event to an mpcc.
                    595:  */
                    596: mpcmd(ev, cmd, flags, mb, port)
                    597:        register struct mpevent *ev;
                    598:        struct mblok *mb;
                    599: {       
                    600:        int s;
                    601: 
                    602:        s = spl8();
                    603:        /* move host values to inbound entry */
                    604:        ev->ev_cmd = cmd;
                    605:        ev->ev_opts = flags;
                    606:        /* show event ready for mpcc */
                    607:        ev->ev_status = EVSTATUS_GO;
                    608:        mpintmpcc(mb, port);
                    609:        splx(s);
                    610: }
                    611: 
                    612: /*
                    613:  * Return the next available event entry for the indicated port.
                    614:  */
                    615: struct mpevent *
                    616: mp_getevent(mp, unit)
                    617:        register struct mpport *mp;
                    618:        int unit;
                    619: {
                    620:        register struct mpevent *ev;
                    621:        int i, s;
                    622: 
                    623:        s = spl8();
                    624:        ev = &mp->mp_recvq[mp->mp_on];
                    625:        if (ev->ev_status != EVSTATUS_FREE)
                    626:                goto bad;
                    627:        /*
                    628:         * If not a close request, verify one extra
                    629:         * event is available for closing the port.
                    630:         */
                    631:        if ((mp->mp_flags & MP_PROGRESS) == 0) {
                    632:                if ((i = mp->mp_on + 1) >= MPINSET)
                    633:                        i = 0;
                    634:                if (mp->mp_recvq[i].ev_status != EVSTATUS_FREE)
                    635:                        goto bad;
                    636:        }
                    637:        /* init inbound fields marking this entry as busy */
                    638:        ev->ev_error = 0;
                    639:        ev->ev_flags = 0;
                    640:        ev->ev_count = 0;
                    641:        ev->ev_status = EVSTATUS_BUSY;
                    642:        /* adjust pointer to next available inbound entry */
                    643:        adjptr(mp->mp_on, MPINSET);
                    644:        splx(s);
                    645:        return (ev);
                    646: bad:
                    647:        splx(s);
                    648:        log(LOG_ERR, "mp%d: port%d, out of events", MPUNIT(unit), MPPORT(unit));
                    649:        return ((struct mpevent *)0);
                    650: }
                    651: 
                    652: mpmodem(unit, flag)
                    653:        int unit, flag;
                    654: {
                    655:        struct mpsoftc *ms = &mp_softc[MPUNIT(unit)];
                    656:        int port = MPPORT(unit);
                    657:        register struct mpport *mp;
                    658:        register struct asyncparam *asp;
                    659: 
                    660:        mp = &ms->ms_mb->mb_port[port];
                    661:        asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1];
                    662:        if (flag == MMOD_ON) {
                    663:                if (ms->ms_softCAR & (1 << port))
                    664:                        setm(&asp->ap_modem, A_DTR, ASSERT);
                    665:                else
                    666:                        setm(&asp->ap_modem, A_DTR, AUTO);
                    667:                seti(&asp->ap_intena, A_DCD);
                    668:        } else {
                    669:                setm(&asp->ap_modem, 0, DROP);
                    670:                seti(&asp->ap_intena, 0);
                    671:        }
                    672: }
                    673: 
                    674: /*
                    675:  * Set up the modem control structure according to mask.
                    676:  * Each set bit in the mask means assert the corresponding
                    677:  * modem control line, otherwise, it will be dropped.  
                    678:  * RTS is special since it can either be asserted, dropped
                    679:  * or put in auto mode for auto modem control.
                    680:  */
                    681: static
                    682: setm(mc, mask, rts)
                    683:        register struct mdmctl *mc;
                    684:        register int mask;
                    685: {
                    686: 
                    687:        mc->mc_rngdsr = (mask & A_RNGDSR) ? ASSERT : DROP;
                    688:        mc->mc_rate = (mask & A_RATE) ? ASSERT : DROP;
                    689:        mc->mc_dcd = (mask & A_DCD) ? ASSERT : DROP;
                    690:        mc->mc_sectx = (mask & A_SECTX) ? ASSERT : DROP;
                    691:        mc->mc_cts = (mask & A_CTS) ? ASSERT : DROP;
                    692:        mc->mc_secrx = (mask & A_SECRX) ? ASSERT : DROP;
                    693:        mc->mc_dtr = (mask & A_DTR) ? ASSERT : DROP;
                    694:        mc->mc_rts = rts;
                    695: }
                    696: 
                    697: /*
                    698:  * Set up the status change enable field from mask.
                    699:  * When a signal is enabled in this structure and
                    700:  * and a change in state on a corresponding modem
                    701:  * control line occurs, a status change event will
                    702:  * be delivered to the host.
                    703:  */
                    704: static
                    705: seti(mc, mask)
                    706:        register struct mdmctl *mc;
                    707:        register int mask;
                    708: {
                    709: 
                    710:        mc->mc_rngdsr = (mask & A_RNGDSR) ? MDM_ON : MDM_OFF;
                    711:        mc->mc_rate = (mask & A_RATE) ? MDM_ON : MDM_OFF;
                    712:        mc->mc_dcd = (mask & A_DCD) ? MDM_ON : MDM_OFF;
                    713:        mc->mc_sectx = (mask & A_SECTX) ? MDM_ON : MDM_OFF;
                    714:        mc->mc_cts = (mask & A_CTS) ? MDM_ON : MDM_OFF;
                    715:        mc->mc_secrx = (mask & A_SECRX) ? MDM_ON : MDM_OFF;
                    716:        mc->mc_dtr = (mask & A_DTR) ? MDM_ON : MDM_OFF;
                    717:        mc->mc_rts = (mask & A_RTS) ? MDM_ON : MDM_OFF;
                    718: }
                    719: 
                    720: mpcleanport(mb, port)
                    721:        struct mblok *mb;
                    722:        int port;
                    723: {
                    724:        register struct mpport *mp;
                    725:        register struct tty *tp;
                    726: 
                    727:        mp = &mb->mb_port[port];
                    728:        if (mp->mp_proto == MPPROTO_ASYNC) {
                    729:                mp->mp_flags = MP_REMBSY;
                    730:                /* signal loss of carrier and close */
                    731:                tp = &mp_tty[mb->mb_unit*MPCHUNK+port];
                    732:                ttyflush(tp, FREAD|FWRITE);
                    733:                (void) (*linesw[tp->t_line].l_modem)(tp, 0);
                    734:                (void) mpclose(tp->t_dev, 0);
                    735:        }
                    736: }
                    737: 
                    738: mpclean(mb, port)
                    739:        register struct mblok *mb;
                    740:        int port;
                    741: {
                    742:        register struct mpport *mp;
                    743:        register struct mpevent *ev;
                    744:        register int i;
                    745:        u_char list[2];
                    746:        int unit;
                    747: 
                    748:        mp = &mb->mb_port[port];
                    749:        unit = mb->mb_unit;
                    750:        for (i = mp->mp_off; i != mp->mp_on; i = (i+1 % MPINSET)) {
                    751:                ev = &mp->mp_recvq[i];
                    752:                ev->ev_error = ENXIO;
                    753:                ev->ev_status = EVSTATUS_DONE;
                    754:        }
                    755:        list[0] = port, list[1] = MPPORT_EOL;
                    756:        mpxintr(unit, list);
                    757:        mprintr(unit, list);
                    758:        /* Clear async for port */
                    759:        mp->mp_proto = MPPROTO_UNUSED;
                    760:        mp->mp_flags = 0;
                    761:        mp->mp_on = 0;
                    762:        mp->mp_off = 0;
                    763:        mp->mp_nextrcv = 0;
                    764: 
                    765:        mp_tty[unit*MPCHUNK + port].t_state = 0;
                    766:        for (ev = &mp->mp_sendq[0]; ev < &mp->mp_sendq[MPOUTSET]; ev++) {
                    767:                ev->ev_status = EVSTATUS_FREE;
                    768:                ev->ev_cmd = 0;
                    769:                ev->ev_error = 0;
                    770:                ev->ev_un.rcvblk = 0;
                    771:                ev->ev_params = 0;
                    772:        }
                    773:        for (ev = &mp->mp_recvq[0]; ev < &mp->mp_recvq[MPINSET]; ev++) {
                    774:                ev->ev_status = EVSTATUS_FREE;
                    775:                ev->ev_cmd = 0;
                    776:                ev->ev_error = 0;
                    777:                ev->ev_params = 0;
                    778:        }
                    779: }
                    780: 
                    781: /*
                    782:  * MPCC interrupt handler.
                    783:  */
                    784: mpintr(mpcc)
                    785:        int mpcc;
                    786: {
                    787:        register struct mblok *mb;
                    788:        register struct his *his;
                    789: 
                    790:        mb = mp_softc[mpcc].ms_mb;
                    791:        if (mb == 0) {
                    792:                printf("mp%d: stray interrupt\n", mpcc);
                    793:                return;
                    794:        }
                    795:        his = &mb->mb_hostint;
                    796:        his->semaphore &= ~MPSEMA_AVAILABLE;
                    797:        /*
                    798:         * Check for events to be processed.
                    799:         */
                    800:        if (his->proto[MPPROTO_ASYNC].outbdone[0] != MPPORT_EOL)
                    801:                mprintr(mpcc, his->proto[MPPROTO_ASYNC].outbdone);
                    802:        if (his->proto[MPPROTO_ASYNC].inbdone[0] != MPPORT_EOL)
                    803:                mpxintr(mpcc, his->proto[MPPROTO_ASYNC].inbdone);
                    804:        if (mb->mb_harderr || mb->mb_softerr)
                    805:                mperror(mb, mpcc);
                    806:        his->semaphore |= MPSEMA_AVAILABLE;
                    807: }
                    808: 
                    809: /*
                    810:  * Handler for processing completion of transmitted events.
                    811:  */
                    812: mpxintr(unit, list)
                    813:        register u_char *list;
                    814: {
                    815:        register struct mpport *mp;
                    816:        register struct mpevent *ev;
                    817:        register struct mblok *mb;
                    818:        register struct tty *tp;
                    819:        register struct asyncparam *ap;
                    820:        struct mpsoftc *ms;
                    821:        int port, i, j;
                    822: 
                    823:        ms = &mp_softc[unit];
                    824:        mb = mp_softc[unit].ms_mb;
                    825:        for (j = 0; j < MPMAXPORT && ((port = *list++) != MPPORT_EOL); j++) {
                    826:                /*
                    827:                 * Process each completed entry in the inbound queue.
                    828:                 */
                    829:                mp = &mb->mb_port[port];
                    830:                tp = &mp_tty[unit*MPCHUNK + port];
                    831: #define        nextevent(mp)   &mp->mp_recvq[mp->mp_off]
                    832:                ev = nextevent(mp);
                    833:                for(; ev->ev_status & EVSTATUS_DONE; ev = nextevent(mp)) {
                    834:                        /* YUCK */
                    835:                        ap = &ms->ms_async[port][mp->mp_off];
                    836:                        mppurge((caddr_t)ap, (int)sizeof (*ap));
                    837:                        switch (ev->ev_cmd) {
                    838:                        case EVCMD_OPEN:
                    839:                                /*
                    840:                                 * Open completion, start all reads and
                    841:                                 * assert modem status information.
                    842:                                 */
                    843:                                for (i = 0; i < MPOUTSET; i++) 
                    844:                                        mp->mp_sendq[i].ev_status = EVSTATUS_GO;
                    845:                                (*linesw[tp->t_line].l_modem)
                    846:                                    (tp, ap->ap_modem.mc_dcd == ASSERT);
                    847:                                break;
                    848:                        case EVCMD_CLOSE:
                    849:                                /*
                    850:                                 * Close completion, flush all pending
                    851:                                 * transmissions, free resources, and
                    852:                                 * cleanup mpcc port state.
                    853:                                 */
                    854:                                for (i = 0; i < MPOUTSET; i++) {
                    855:                                        mp->mp_sendq[i].ev_status =
                    856:                                            EVSTATUS_FREE;
                    857:                                        mp->mp_sendq[i].ev_un.rcvblk = 0;
                    858:                                        mp->mp_sendq[i].ev_params = 0;
                    859:                                }
                    860:                                tp->t_state &= ~TS_CARR_ON;
                    861:                                mp->mp_on = mp->mp_off = mp->mp_nextrcv = 0;
                    862:                                mp->mp_flags &= ~MP_PROGRESS;
                    863:                                mp->mp_proto = MPPROTO_UNUSED;
                    864:                                wakeup((caddr_t)&tp->t_canq);
                    865:                                goto done;
                    866:                        case EVCMD_IOCTL:
                    867:                                /*
                    868:                                 * Nothing to do, just pitch.
                    869:                                 */
                    870:                                break;
                    871:                        case EVCMD_WRITE:
                    872:                                /*
                    873:                                 * Transmission completed, update tty
                    874:                                 * state and restart output.
                    875:                                 */
                    876:                                tp->t_state &= ~TS_BUSY;
                    877:                                if (tp->t_state & TS_FLUSH)
                    878:                                        tp->t_state &= ~TS_FLUSH;
                    879:                                else {
                    880:                                        register int cc = 0, n;
                    881:                                        struct hxmtl *hxp;
                    882: 
                    883:                                        hxp = &ms->ms_hxl[port];
                    884:                                        for(n = 0; n < ev->ev_count; n++)
                    885:                                                cc += hxp->size[n];
                    886:                                        ndflush(&tp->t_outq, cc);
                    887:                                }
                    888:                                switch (ev->ev_error) {
                    889:                                case A_SIZERR:  /*# error in xmt data size */
                    890:                                        mplog(unit, port, A_XSIZE, 0);
                    891:                                        break;
                    892:                                case A_NXBERR:  /*# no more xmt evt buffers */
                    893:                                        mplog(unit, port, A_NOXBUF, 0);
                    894:                                        break;
                    895:                                }
                    896:                                mpstart(tp);
                    897:                                break;
                    898:                        default:
                    899:                                mplog(unit, port, A_INVCMD, (int)ev->ev_cmd);  
                    900:                                break;
                    901:                        }
                    902:                        /* re-init all values in this entry */
                    903:                        ev->ev_cmd = 0;
                    904:                        ev->ev_opts = 0;
                    905:                        ev->ev_error = 0;
                    906:                        ev->ev_flags = 0;
                    907:                        ev->ev_count = 0;
                    908:                        /* show this entry is available for use */
                    909:                        ev->ev_status = EVSTATUS_FREE;
                    910:                        adjptr(mp->mp_off, MPINSET);
                    911: #undef nextevent
                    912:                }
                    913: done:
                    914:                ;
                    915:        }
                    916: }
                    917: 
                    918: /*
                    919:  * Handler for processing received events.
                    920:  */
                    921: mprintr(unit, list)
                    922:        u_char *list;
                    923: {
                    924:        register struct tty *tp;
                    925:        register struct mpport *mp;
                    926:        register struct mpevent *ev;
                    927:        struct mblok *mb;
                    928:        register int cc;
                    929:        register char *cp;
                    930:        struct mpsoftc *ms;
                    931:        caddr_t ptr;
                    932:        char *rcverr;
                    933:        int port, i;
                    934: 
                    935:        ms = &mp_softc[unit];
                    936:        mb = mp_softc[unit].ms_mb;
                    937:        for (i = 0; i < MPMAXPORT && (port = *list++) != MPPORT_EOL; i++) {
                    938:                tp = &mp_tty[unit*MPCHUNK + port];
                    939:                mp = &mb->mb_port[port];
                    940:                ev = &mp->mp_sendq[mp->mp_nextrcv];
                    941:                while (ev->ev_status & EVSTATUS_DONE) {
                    942:                        if (ev->ev_cmd != EVCMD_READ &&
                    943:                            ev->ev_cmd != EVCMD_STATUS) {
                    944:                                mplog(unit, port, "unexpected command",
                    945:                                    (int)ev->ev_cmd);
                    946:                                goto next;
                    947:                        }
                    948:                        if (ev->ev_cmd == EVCMD_STATUS) {
                    949:                                /*
                    950:                                 * Status change, look for carrier changes.
                    951:                                 */
                    952:                                if (ev->ev_opts == DCDASRT ||
                    953:                                    ev->ev_opts == DCDDROP)
                    954:                                        (*linesw[tp->t_line].l_modem)
                    955:                                            (tp, ev->ev_opts == DCDASRT);
                    956:                                else
                    957:                                        mplog(unit, port,
                    958:                                            "unexpect status command",
                    959:                                            (int)ev->ev_opts);
                    960:                                goto next;
                    961:                        }
                    962:                        /*
                    963:                         * Process received data.
                    964:                         */
                    965:                        if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0)
                    966:                                goto next;
                    967:                        cc = ev->ev_count;
                    968:                        if (cc == 0)
                    969:                                goto next;
                    970:                        /* YUCK */
                    971:                        cp = ms->ms_cbuf[port][mp->mp_nextrcv];
                    972:                        mppurge(cp, CBSIZE);
                    973:                        while (cc-- > 0) {
                    974:                                /*
                    975:                                 * A null character is inserted, potentially
                    976:                                 * when a break or framing error occurs.  If
                    977:                                 * we're not in raw mode, substitute the
                    978:                                 * interrupt character.
                    979:                                 */
                    980:                                if (*cp == 0 &&
                    981:                                    (ev->ev_error == BRKASRT ||
                    982:                                     ev->ev_error == FRAMERR))
                    983:                                        if ((tp->t_flags&RAW) == 0)
                    984:                                                *cp = tp->t_intrc;
                    985:                                (*linesw[tp->t_line].l_rint)(*cp++, tp);
                    986:                        }
                    987:                        /* setup for next read */
                    988:                        ptr = (caddr_t)&mp_softc[unit].ms_cbuf[port][mp->mp_nextrcv][0];
                    989:                        ev->ev_un.rcvblk = (u_char *)kvtophys(ptr);
                    990:                        ev->ev_params = (caddr_t) kvtophys(ptr);
                    991:                        switch(ev->ev_error) {
                    992:                        case RCVDTA:    /* Normal (good) rcv data */
                    993:                                        /* do not report the following */
                    994:                                        /* they are "normal" errors */
                    995:                        case FRAMERR:   /* frame error */
                    996:                        case BRKASRT:   /* Break condition */
                    997:                        case PARERR:    /* parity error */
                    998:                                rcverr = (char *)0;
                    999:                                break;
                   1000:                        case OVRNERR:   /* Overrun error */
                   1001:                                rcverr = "overrun error";
                   1002:                                break;
                   1003:                        case OVFERR:    /* Overflow error */
                   1004:                                rcverr = "overflow error";
                   1005:                                break;
                   1006:                        default:
                   1007:                                rcverr = "undefined rcv error";
                   1008:                        }
                   1009:                        if (rcverr != (char *)0)
                   1010:                                mplog(unit, port, rcverr, (int)ev->ev_error);
                   1011:                next:
                   1012:                        ev->ev_cmd = 0;
                   1013:                        ev->ev_opts = 0;
                   1014:                        ev->ev_error = 0;
                   1015:                        ev->ev_flags = 0;
                   1016:                        ev->ev_status = EVSTATUS_GO;    /* start next read */
                   1017:                        adjptr(mp->mp_nextrcv, MPOUTSET);
                   1018:                        ev = &mp->mp_sendq[mp->mp_nextrcv];
                   1019:                }
                   1020:        }
                   1021: }
                   1022: 
                   1023: /*
                   1024:  * Log an mpcc diagnostic.
                   1025:  */
                   1026: mplog(unit, port, cp, flags)
                   1027:        char *cp;
                   1028: {
                   1029: 
                   1030:        if (flags)
                   1031:                log(LOG_ERR, "mp%d: port%d, %s (%d)\n",
                   1032:                    unit, port, cp, flags);
                   1033:        else
                   1034:                log(LOG_ERR, "mp%d: port%d, %s\n", unit, port, cp);
                   1035: }
                   1036: 
                   1037: int    MPHOSTINT = 1;
                   1038: 
                   1039: mptimeint(mb)
                   1040:        register struct mblok *mb;
                   1041: {
                   1042: 
                   1043:         mb->mb_mpintcnt = 0;
                   1044:         mb->mb_mpintclk = (caddr_t)0;
                   1045:        *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2;
                   1046: }
                   1047: 
                   1048: /*
                   1049:  * Interupt mpcc
                   1050:  */
                   1051: mpintmpcc(mb, port)
                   1052:        register struct mblok *mb;
                   1053: {
                   1054: 
                   1055:         mb->mb_intr[port] |= MPSEMA_WORK;
                   1056:         if (++mb->mb_mpintcnt == MPHOSTINT) {
                   1057:                 mb->mb_mpintcnt = 0;
                   1058:                *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2;
                   1059:                 if (mb->mb_mpintclk) {
                   1060:                         untimeout(mptimeint, (caddr_t)mb);
                   1061:                         mb->mb_mpintclk = 0;
                   1062:                 }
                   1063:         } else {
                   1064:                 if (mb->mb_mpintclk == 0) {
                   1065:                         timeout(mptimeint, (caddr_t)mb, 4);
                   1066:                         mb->mb_mpintclk = (caddr_t)1;
                   1067:                 }
                   1068:         }
                   1069: }
                   1070: 
                   1071: static char *mpherrmsg[] = {
                   1072:        "",
                   1073:        "Bus error",                            /* MPBUSERR */
                   1074:        "Address error",                        /* ADDRERR */
                   1075:        "Undefined ecc interrupt",              /* UNDECC */
                   1076:        "Undefined interrupt",                  /* UNDINT */
                   1077:        "Power failure occurred",               /* PWRFL */
                   1078:        "Stray transmit done interrupt",        /* NOXENTRY */
                   1079:        "Two fast timers on one port",          /* TWOFTMRS */
                   1080:        "Interrupt queue full",                 /* INTQFULL */
                   1081:        "Interrupt queue ack error",            /* INTQERR */
                   1082:        "Uncorrectable dma parity error",       /* CBPERR */
                   1083:        "32 port ACAP failed power up",         /* ACPDEAD */
                   1084: };
                   1085: #define        NHERRS  (sizeof (mpherrmsg) / sizeof (mpherrmsg[0]))
                   1086: 
                   1087: mperror(mb, unit)
                   1088:        register struct mblok *mb;
                   1089:        int unit;
                   1090: {
                   1091:        register char *cp;
                   1092:        register int i;
                   1093: 
                   1094:        if (mb->mb_softerr) {
                   1095:                switch (mb->mb_softerr) {
                   1096:                case DMAPERR:   /* dma parity error */
                   1097:                        cp = "dma parity error";
                   1098:                        break;
                   1099:                case ECCERR:
                   1100:                        cp = "local memory ecc error";
                   1101:                        break;
                   1102:                default:
                   1103:                        cp = "unknown error";
                   1104:                        break;
                   1105:                }
                   1106:                log(LOG_ERR, "mp%d: soft error, %s", unit, cp);
                   1107:                mb->mb_softerr = 0;
                   1108:        }
                   1109:        if (mb->mb_harderr) {
                   1110:                if (mb->mb_harderr < NHERRS)
                   1111:                        cp = mpherrmsg[mb->mb_harderr];
                   1112:                else
                   1113:                        cp = "unknown error";
                   1114:                log(LOG_ERR, "mp%d: hard error, %s", unit, cp);
                   1115:                if (mb->mb_status == MP_OPOPEN) {
                   1116:                        for (i = 0; i < MPMAXPORT; i++) {
                   1117:                                mpcleanport(mb, i);
                   1118:                                mb->mb_proto[i] = MPPROTO_UNUSED;
                   1119:                        }
                   1120:                }
                   1121:                mb->mb_harderr = 0;
                   1122:                mb->mb_status = 0;
                   1123:        }
                   1124: }
                   1125: 
                   1126: mppurge(addr, cc)
                   1127:        register caddr_t addr;
                   1128:        register int cc;
                   1129: {
                   1130: 
                   1131:        for (; cc >= 0; addr += NBPG, cc -= NBPG)
                   1132:                mtpr(P1DC, addr);
                   1133: }
                   1134: 
                   1135: /*
                   1136:  * MPCC Download Pseudo-device.
                   1137:  */
                   1138: char   mpdlbuf[MPDLBUFSIZE];
                   1139: int    mpdlbusy;               /* interlock on download buffer */
                   1140: int    mpdlerr;
                   1141: 
                   1142: mpdlopen(dev)
                   1143:        dev_t dev;
                   1144: {
                   1145:        int unit, mpu;
                   1146:        struct vba_device *vi;
                   1147: 
                   1148:        unit = minor(dev);
                   1149:        mpu = MPUNIT(unit);
                   1150:        if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0)
                   1151:                return (ENODEV);
                   1152:        return (0);
                   1153: }
                   1154: 
                   1155: mpdlwrite(dev, uio)
                   1156:        dev_t dev;
                   1157:        struct uio *uio;
                   1158: {
                   1159:        register struct mpsoftc *ms = &mp_softc[MPUNIT(minor(dev))];
                   1160:        register struct mpdl *dl;
                   1161:        int error;
                   1162: 
                   1163:        if (ms->ms_mb == 0 || ms->ms_mb->mb_status != MP_DLOPEN)
                   1164:                return (EFAULT);
                   1165:        dl = &ms->ms_mb->mb_dl;
                   1166:        dl->mpdl_count = uio->uio_iov->iov_len;
                   1167:        dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf);
                   1168:        if (error = uiomove(mpdlbuf, (int)dl->mpdl_count, UIO_WRITE, uio))
                   1169:                return (error);
                   1170:        uio->uio_resid -= dl->mpdl_count;    /* set up return from write */
                   1171:        dl->mpdl_cmd = MPDLCMD_NORMAL;
                   1172:        error = mpdlwait(dl);
                   1173:        return (error);
                   1174: }
                   1175: 
                   1176: mpdlclose(dev)
                   1177:        dev_t dev;
                   1178: {
                   1179:        register struct mblok *mb = mp_softc[MPUNIT(minor(dev))].ms_mb;
                   1180: 
                   1181:        if (mb == 0 || mb->mb_status != MP_DLDONE) {
                   1182:                mpbogus.status = 0;
                   1183:                if (mpbogus.mb == mpbogus.mbloks[MPUNIT(minor(dev))])
                   1184:                        mpdlbusy--;
                   1185:                return (EEXIST);
                   1186:        }
                   1187:        mb->mb_status = MP_OPOPEN;
                   1188:        mpbogus.status = 0;
                   1189:        /* set to dead, for board handshake */
                   1190:        mb->mb_hostint.imok = MPIMOK_DEAD;
                   1191:        return (0);
                   1192: }
                   1193: 
                   1194: int    mpdltimeout();
                   1195: 
                   1196: /* ARGSUSED */
                   1197: mpdlioctl(dev, cmd, data, flag)
                   1198:        dev_t dev;
                   1199:        caddr_t data;
                   1200: {
                   1201:        register struct mblok *mb;
                   1202:        register struct mpdl *dl;
                   1203:        int unit, error, s, i;
                   1204: 
                   1205:        mb = mp_softc[unit=MPUNIT(minor(dev))].ms_mb;
                   1206:        if (mb == 0)
                   1207:                return (EEXIST);
                   1208:        dl = &mb->mb_dl;
                   1209:        error = 0;
                   1210:        switch (cmd) {
                   1211:        case MPIOPORTMAP:
                   1212:                bcopy(data, (caddr_t)mb->mb_proto, sizeof (mb->mb_proto));
                   1213:                break;
                   1214:        case MPIOHILO:
                   1215:                bcopy(data, (caddr_t)&mb->mb_hiport, 2*(sizeof(mb->mb_hiport)));
                   1216:                break;
                   1217:        case MPIOENDDL:
                   1218:                dl->mpdl_count = 0;
                   1219:                dl->mpdl_data = 0;
                   1220:                dl->mpdl_cmd = MPIOENDDL&IOCPARM_MASK;
                   1221:                error = mpdlwait(dl);
                   1222:                mpccinit(unit);
                   1223:                mb->mb_status = MP_DLDONE;
                   1224:                mpdlbusy--;
                   1225:                break;
                   1226:        case MPIOENDCODE:
                   1227:                dl->mpdl_count = 0;
                   1228:                dl->mpdl_data = 0;
                   1229:                dl->mpdl_cmd = MPIOENDCODE&IOCPARM_MASK;
                   1230:                error = mpdlwait(dl);
                   1231:                break;
                   1232:        case MPIOASYNCNF:
                   1233:                bcopy(data, mpdlbuf, sizeof (struct abdcf));
                   1234:                dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf);
                   1235:                dl->mpdl_count = sizeof (struct abdcf);
                   1236:                dl->mpdl_cmd = MPIOASYNCNF&IOCPARM_MASK;
                   1237:                error = mpdlwait(dl);
                   1238:                break;
                   1239:        case MPIOSTARTDL:
                   1240:                while (mpdlbusy)
                   1241:                        sleep((caddr_t)&mpdlbusy, PZERO+1);
                   1242:                mpdlbusy++;
                   1243:                /* initialize the downloading interface */
                   1244:                mpbogus.magic = MPMAGIC;
                   1245:                mpbogus.mb = mpbogus.mbloks[unit];
                   1246:                mpbogus.status = 1;
                   1247:                dl->mpdl_status = EVSTATUS_FREE;
                   1248:                dl->mpdl_count = 0;
                   1249:                dl->mpdl_cmd = 0;
                   1250:                dl->mpdl_data = (char *) 0;
                   1251:                mpdlerr = 0;
                   1252:                mb->mb_magic = MPMAGIC;
                   1253:                mb->mb_ivec = mp_softc[unit].ms_ivec+1; /* download vector */
                   1254:                mb->mb_status = MP_DLPEND;
                   1255:                mb->mb_diagswitch[0] = 'A';
                   1256:                mb->mb_diagswitch[1] = 'P';
                   1257:                s = spl8();
                   1258:                *(u_short *)mpinfo[unit]->ui_addr = 2;
                   1259:                timeout(mpdltimeout, (caddr_t)mb, 30*hz);
                   1260:                sleep((caddr_t)&mb->mb_status, PZERO+1);
                   1261:                splx(s);
                   1262:                if (mb->mb_status == MP_DLOPEN) {
                   1263:                        untimeout(mpdltimeout, (caddr_t)mb);
                   1264:                } else if (mb->mb_status == MP_DLTIME) {
                   1265:                        mpbogus.status = 0;
                   1266:                        error = ETIMEDOUT;
                   1267:                } else {
                   1268:                        mpbogus.status = 0;
                   1269:                        error = ENXIO;
                   1270:                        log(LOG_ERR, "mp%d: start download: unknown status %x",
                   1271:                            unit, mb->mb_status);
                   1272:                }
                   1273:                bzero((caddr_t)mb->mb_port, sizeof (mb->mb_port));
                   1274:                break;
                   1275:        case MPIORESETBOARD:
                   1276:                s = spl8();
                   1277:                if (mb->mb_imokclk)
                   1278:                        mb->mb_imokclk = 0;
                   1279:                *(u_short *)mpinfo[unit]->ui_addr = 0x100;
                   1280:                if (mb->mb_status == MP_DLOPEN || mb->mb_status == MP_DLDONE) {
                   1281:                        mpdlerr = MP_DLERROR;
                   1282:                        dl->mpdl_status = EVSTATUS_FREE;
                   1283:                        wakeup((caddr_t)&dl->mpdl_status);
                   1284:                        mpbogus.status = 0;
                   1285:                }
                   1286:                for (i = 0; i < MPMAXPORT; i++) {
                   1287:                        if (mb->mb_harderr || mb->mb_softerr)
                   1288:                                mperror(mb, i);
                   1289:                        mpcleanport(mb, i);
                   1290:                        mb->mb_proto[i] = MPPROTO_UNUSED;
                   1291:                }
                   1292:                mb->mb_status = 0;
                   1293:                splx(s);
                   1294:                break;
                   1295:        default:
                   1296:                error = EINVAL;
                   1297:                break;
                   1298:        }
                   1299:        return (error);
                   1300: }
                   1301: 
                   1302: mpccinit(unit)
                   1303:        int unit;
                   1304: {
                   1305:         register struct mblok *mb = mp_softc[unit].ms_mb;
                   1306:         register struct his *his;
                   1307:         register int i, j;
                   1308: 
                   1309:         mb->mb_status = MP_DLDONE;
                   1310:         mb->mb_ivec = mp_softc[unit].ms_ivec;
                   1311:         mb->mb_magic = MPMAGIC;
                   1312:         /* Init host interface structure */
                   1313:         his = &mb->mb_hostint;
                   1314:         his->semaphore = MPSEMA_AVAILABLE;
                   1315:         for (i = 0; i < NMPPROTO; i++)
                   1316:                 for (j = 0; j < MPMAXPORT; j++) {
                   1317:                         his->proto[i].inbdone[j] = MPPORT_EOL;
                   1318:                         his->proto[i].outbdone[j] = MPPORT_EOL;
                   1319:                 }
                   1320:         mb->mb_unit = unit;
                   1321: }
                   1322: 
                   1323: mpdlintr(mpcc)
                   1324:        int mpcc;
                   1325: {
                   1326:        register struct mblok *mb;
                   1327:        register struct mpdl *dl;
                   1328: 
                   1329:        mb = mp_softc[mpcc].ms_mb;
                   1330:        if (mb == 0) {
                   1331:                printf("mp%d: stray download interrupt\n", mpcc);
                   1332:                return;
                   1333:        }
                   1334:        dl = &mb->mb_dl;
                   1335:        switch (mb->mb_status) {
                   1336:        case MP_DLOPEN:
                   1337:                if (dl->mpdl_status != EVSTATUS_DONE)
                   1338:                        mpdlerr = MP_DLERROR;
                   1339:                dl->mpdl_status = EVSTATUS_FREE;
                   1340:                wakeup((caddr_t)&dl->mpdl_status);
                   1341:                return;
                   1342:        case MP_DLPEND:
                   1343:                mb->mb_status = MP_DLOPEN;
                   1344:                wakeup((caddr_t)&mb->mb_status);
                   1345:                /* fall thru... */
                   1346:        case MP_DLTIME:
                   1347:                return;
                   1348:        case MP_OPOPEN:
                   1349:                if (mb->mb_imokclk)
                   1350:                        mb->mb_imokclk = 0;
                   1351:                mb->mb_nointcnt = 0;            /* reset no interrupt count */
                   1352:                mb->mb_hostint.imok = MPIMOK_DEAD;
                   1353:                mb->mb_imokclk = (caddr_t)1;
                   1354:                break;
                   1355:        default:
                   1356:                log(LOG_ERR, "mp%d: mpdlintr, status %x\n",
                   1357:                    mpcc, mb->mb_status);
                   1358:                break;
                   1359:        }
                   1360: }
                   1361: 
                   1362: mpdltimeout(mp)
                   1363:        struct mblok *mp;
                   1364: {
                   1365: 
                   1366:        mp->mb_status = MP_DLTIME;
                   1367:        wakeup((caddr_t)&mp->mb_status);
                   1368: }
                   1369: 
                   1370: /* 
                   1371:  * Wait for a transfer to complete or a timeout to occur.
                   1372:  */
                   1373: mpdlwait(dl)
                   1374:        register struct mpdl *dl;
                   1375: {
                   1376:        int s, error = 0;
                   1377: 
                   1378:        s = spl8();
                   1379:        dl->mpdl_status = EVSTATUS_GO;
                   1380:        while (dl->mpdl_status != EVSTATUS_FREE) {
                   1381:                sleep((caddr_t)&dl->mpdl_status, PZERO+1);
                   1382:                if (mpdlerr == MP_DLERROR)
                   1383:                        error = EIO;
                   1384:        }
                   1385:        splx(s);
                   1386:        return (error);
                   1387: }
                   1388: #endif

unix.superglobalmegacorp.com

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