home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / tahoe / vba / mp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-16  |  36.8 KB  |  1,556 lines

  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
  1556.