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

unix.superglobalmegacorp.com

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