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

unix.superglobalmegacorp.com

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