1b092cf00Skarels /*
2b092cf00Skarels * Copyright (c) 1988 Regents of the University of California.
3b092cf00Skarels * All rights reserved.
4b092cf00Skarels *
520eaab23Skarels * This code is derived from software contributed to Berkeley by
620eaab23Skarels * Computer Consoles Inc.
720eaab23Skarels *
8f69c3528Sbostic * %sccs.include.redist.c%
9b092cf00Skarels *
10*3760269aSmarc * @(#)mp.c 7.17 (Berkeley) 05/16/91
11b092cf00Skarels */
129f1eda9eSsam
139f1eda9eSsam #include "mp.h"
149f1eda9eSsam #if NMP > 0
159f1eda9eSsam /*
169f1eda9eSsam * Multi Protocol Communications Controller (MPCC).
179f1eda9eSsam * Asynchronous Terminal Protocol Support.
189f1eda9eSsam */
190dce6c9dSbostic #include "sys/param.h"
200dce6c9dSbostic #include "sys/ioctl.h"
210dce6c9dSbostic #include "sys/tty.h"
220dce6c9dSbostic #include "sys/user.h"
230dce6c9dSbostic #include "sys/map.h"
240dce6c9dSbostic #include "sys/buf.h"
250dce6c9dSbostic #include "sys/conf.h"
260dce6c9dSbostic #include "sys/file.h"
270dce6c9dSbostic #include "sys/errno.h"
280dce6c9dSbostic #include "sys/syslog.h"
290dce6c9dSbostic #include "sys/vmmac.h"
300dce6c9dSbostic #include "sys/kernel.h"
310dce6c9dSbostic #include "sys/clist.h"
329f1eda9eSsam
330dce6c9dSbostic #include "../include/pte.h"
340dce6c9dSbostic #include "../include/mtpr.h"
35b092cf00Skarels
360dce6c9dSbostic #include "../vba/vbavar.h"
370dce6c9dSbostic #include "../vba/mpreg.h"
389f1eda9eSsam
399f1eda9eSsam #define MPCHUNK 16
409f1eda9eSsam #define MPPORT(n) ((n) & 0xf)
419f1eda9eSsam #define MPUNIT(n) ((n) >> 4)
429f1eda9eSsam
439f1eda9eSsam /*
449f1eda9eSsam * Driver information for auto-configuration stuff.
459f1eda9eSsam */
469f1eda9eSsam int mpprobe(), mpattach(), mpintr();
479f1eda9eSsam struct vba_device *mpinfo[NMP];
489f1eda9eSsam long mpstd[] = { 0 };
499f1eda9eSsam struct vba_driver mpdriver =
509f1eda9eSsam { mpprobe, 0, mpattach, 0, mpstd, "mp", mpinfo };
519f1eda9eSsam
529f1eda9eSsam int mpstart();
53ea54ad41Smarc int mpparam();
54ea54ad41Smarc struct mpevent *mpparam2();
559f1eda9eSsam struct mpevent *mp_getevent();
569f1eda9eSsam
579f1eda9eSsam /*
589f1eda9eSsam * The following structure is needed to deal with mpcc's convoluted
599f1eda9eSsam * method for locating it's mblok structures (hold your stomach).
609f1eda9eSsam * When an mpcc is reset at boot time it searches host memory
619f1eda9eSsam * looking for a string that says ``ThIs Is MpCc''. The mpcc
629f1eda9eSsam * then reads the structure to locate the pointer to it's mblok
639f1eda9eSsam * structure (you can wretch now).
649f1eda9eSsam */
659f1eda9eSsam struct mpbogus {
669f1eda9eSsam char s[12]; /* `ThIs Is MpCc'' */
679f1eda9eSsam u_char status;
689f1eda9eSsam u_char unused;
699f1eda9eSsam u_short magic;
709f1eda9eSsam struct mblok *mb;
719f1eda9eSsam struct mblok *mbloks[NMP]; /* can support at most 16 mpcc's */
729f1eda9eSsam } mpbogus = { 'T','h','I','s',' ','I','s',' ','M','p','C','c' };
739f1eda9eSsam
749f1eda9eSsam /*
759f1eda9eSsam * Software state per unit.
769f1eda9eSsam */
779f1eda9eSsam struct mpsoftc {
789f1eda9eSsam u_int ms_ivec; /* interrupt vector */
799f1eda9eSsam u_int ms_softCAR; /* software carrier for async */
809f1eda9eSsam struct mblok *ms_mb; /* mpcc status area */
819f1eda9eSsam struct vb_buf ms_buf; /* vba resources for ms_mb */
829f1eda9eSsam struct hxmtl ms_hxl[MPMAXPORT];/* host transmit list */
839f1eda9eSsam struct asyncparam ms_async[MPMAXPORT][MPINSET];/* async structs */
849f1eda9eSsam char ms_cbuf[MPMAXPORT][MPOUTSET][CBSIZE];/* input character buffers */
859f1eda9eSsam } mp_softc[NMP];
869f1eda9eSsam
87ea54ad41Smarc struct speedtab
88ea54ad41Smarc mpspeedtab[] = {
89ea54ad41Smarc 9600, M9600, /* baud rate = 9600 */
90ea54ad41Smarc 4800, M4800, /* baud rate = 4800 */
91ea54ad41Smarc 2400, M2400, /* baud rate = 2400 */
92ea54ad41Smarc 1800, M1800, /* baud rate = 1800 */
93ea54ad41Smarc 1200, M1200, /* baud rate = 1200 */
94ea54ad41Smarc 600, M600, /* baud rate = 600 */
95ea54ad41Smarc 300, M300, /* baud rate = 300 */
96ea54ad41Smarc 200, M200, /* baud rate = 200 */
97ea54ad41Smarc 150, M150, /* baud rate = 150 */
98ea54ad41Smarc 134, M134_5, /* baud rate = 134.5 */
99ea54ad41Smarc 110, M110, /* baud rate = 110 */
100ea54ad41Smarc 75, M75, /* baud rate = 75 */
101ea54ad41Smarc 50, M50, /* baud rate = 50 */
102ea54ad41Smarc 0, M0, /* baud rate = 0 */
103ea54ad41Smarc 2000, M2000, /* baud rate = 2000 */
104ea54ad41Smarc 3600, M3600, /* baud rate = 3600 */
105ea54ad41Smarc 7200, M7200, /* baud rate = 7200 */
106ea54ad41Smarc 19200, M19200, /* baud rate = 19,200 */
107ea54ad41Smarc 24000, M24000, /* baud rate = 24,000 */
108ea54ad41Smarc 28400, M28400, /* baud rate = 28,400 */
109ea54ad41Smarc 37800, M37800, /* baud rate = 37,800 */
110ea54ad41Smarc 40300, M40300, /* baud rate = 40,300 */
111ea54ad41Smarc 48000, M48000, /* baud rate = 48,000 */
112ea54ad41Smarc 52000, M52000, /* baud rate = 52,000 */
113ea54ad41Smarc 56800, M56800, /* baud rate = 56,800 */
114ea54ad41Smarc EXTA, MEXTA, /* baud rate = Ext A */
115ea54ad41Smarc EXTB, MEXTB, /* baud rate = Ext B */
116ea54ad41Smarc -1, -1,
117ea54ad41Smarc };
118ea54ad41Smarc
1199f1eda9eSsam struct tty mp_tty[NMP*MPCHUNK];
1209f1eda9eSsam #ifndef lint
1219f1eda9eSsam int nmp = NMP*MPCHUNK;
1229f1eda9eSsam #endif
1239f1eda9eSsam
1249f1eda9eSsam int ttrstrt();
1259f1eda9eSsam
mpprobe(reg,vi)1269f1eda9eSsam mpprobe(reg, vi)
1279f1eda9eSsam caddr_t reg;
1289f1eda9eSsam struct vba_device *vi;
1299f1eda9eSsam {
1309f1eda9eSsam register int br, cvec;
1319f1eda9eSsam register struct mpsoftc *ms;
1329f1eda9eSsam
1339f1eda9eSsam #ifdef lint
1349f1eda9eSsam br = 0; cvec = br; br = cvec;
1359f1eda9eSsam mpintr(0);
136b092cf00Skarels mpdlintr(0);
1379f1eda9eSsam #endif
1389f1eda9eSsam if (badaddr(reg, 2))
1399f1eda9eSsam return (0);
1409f1eda9eSsam ms = &mp_softc[vi->ui_unit];
1419f1eda9eSsam /*
1429f1eda9eSsam * Allocate page tables and mblok
1439f1eda9eSsam * structure (mblok in non-cached memory).
1449f1eda9eSsam */
1459f1eda9eSsam if (vbainit(&ms->ms_buf, sizeof (struct mblok), VB_32BIT) == 0) {
1469f1eda9eSsam printf("mp%d: vbainit failed\n", vi->ui_unit);
1479f1eda9eSsam return (0);
1489f1eda9eSsam }
1499f1eda9eSsam ms->ms_mb = (struct mblok *)ms->ms_buf.vb_rawbuf;
1509f1eda9eSsam ms->ms_ivec = MPINTRBASE + 2*vi->ui_unit; /* XXX */
1519f1eda9eSsam br = 0x14, cvec = ms->ms_ivec; /* XXX */
152563fe95eSkarels return (sizeof (*reg));
1539f1eda9eSsam }
1549f1eda9eSsam
mpattach(vi)1559f1eda9eSsam mpattach(vi)
1569f1eda9eSsam register struct vba_device *vi;
1579f1eda9eSsam {
1589f1eda9eSsam register struct mpsoftc *ms = &mp_softc[vi->ui_unit];
1599f1eda9eSsam
1609f1eda9eSsam ms->ms_softCAR = vi->ui_flags;
1619f1eda9eSsam /*
1629f1eda9eSsam * Setup pointer to mblok, initialize bogus
1639f1eda9eSsam * status block used by mpcc to locate the pointer
1649f1eda9eSsam * and then poke the mpcc to get it to search host
1659f1eda9eSsam * memory to find mblok pointer.
1669f1eda9eSsam */
1679f1eda9eSsam mpbogus.mbloks[vi->ui_unit] = (struct mblok *)ms->ms_buf.vb_physbuf;
1689f1eda9eSsam *(short *)vi->ui_addr = 0x100; /* magic */
1699f1eda9eSsam }
1709f1eda9eSsam
1719f1eda9eSsam /*
1729f1eda9eSsam * Open an mpcc port.
1739f1eda9eSsam */
174b092cf00Skarels /* ARGSUSED */
mpopen(dev,mode)1759f1eda9eSsam mpopen(dev, mode)
1769f1eda9eSsam dev_t dev;
1779f1eda9eSsam {
1789f1eda9eSsam register struct tty *tp;
1799f1eda9eSsam register struct mpsoftc *ms;
1809f1eda9eSsam int error, s, port, unit, mpu;
1819f1eda9eSsam struct vba_device *vi;
1829f1eda9eSsam struct mpport *mp;
1839f1eda9eSsam struct mpevent *ev;
1849f1eda9eSsam
1859f1eda9eSsam unit = minor(dev);
1869f1eda9eSsam mpu = MPUNIT(unit);
1879f1eda9eSsam if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0)
1889f1eda9eSsam return (ENXIO);
1899f1eda9eSsam tp = &mp_tty[unit];
1909f1eda9eSsam if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
1919f1eda9eSsam return (EBUSY);
1929f1eda9eSsam ms = &mp_softc[mpu];
1939f1eda9eSsam port = MPPORT(unit);
1949f1eda9eSsam if (ms->ms_mb->mb_proto[port] != MPPROTO_ASYNC ||
1959f1eda9eSsam ms->ms_mb->mb_status != MP_OPOPEN)
1969f1eda9eSsam return (ENXIO);
1979f1eda9eSsam mp = &ms->ms_mb->mb_port[port]; /* host mpcc struct */
1989f1eda9eSsam s = spl8();
1997c9a9841Sbostic /*
2007c9a9841Sbostic * serialize open and close events
2017c9a9841Sbostic */
202ea54ad41Smarc while ((mp->mp_flags & MP_PROGRESS) || ((tp->t_state & TS_WOPEN) &&
203ea54ad41Smarc !(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL)))
204da918786Skarels if (error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH,
205da918786Skarels ttopen, 0)) {
206da918786Skarels splx(s);
207da918786Skarels return (error);
208da918786Skarels }
2097c9a9841Sbostic restart:
2109f1eda9eSsam tp->t_state |= TS_WOPEN;
2119f1eda9eSsam tp->t_addr = (caddr_t)ms;
2129f1eda9eSsam tp->t_oproc = mpstart;
213ea54ad41Smarc tp->t_param = mpparam;
2149f1eda9eSsam tp->t_dev = dev;
215236c5145Sbostic if ((tp->t_state & TS_ISOPEN) == 0) {
2169f1eda9eSsam ttychars(tp);
2179f1eda9eSsam if (tp->t_ispeed == 0) {
218ea54ad41Smarc tp->t_ispeed = TTYDEF_SPEED;
219ea54ad41Smarc tp->t_ospeed = TTYDEF_SPEED;
220ea54ad41Smarc tp->t_iflag = TTYDEF_IFLAG;
221ea54ad41Smarc tp->t_oflag = TTYDEF_OFLAG;
222ea54ad41Smarc tp->t_lflag = TTYDEF_LFLAG;
223ea54ad41Smarc tp->t_cflag = TTYDEF_CFLAG;
2249f1eda9eSsam }
2259f1eda9eSsam /*
2269f1eda9eSsam * Initialize port state: init MPCC interface
2279f1eda9eSsam * structures for port and setup modem control.
2289f1eda9eSsam */
2299f1eda9eSsam error = mpportinit(ms, mp, port);
2309f1eda9eSsam if (error)
2319f1eda9eSsam goto bad;
232ea54ad41Smarc ev = mpparam2(tp, &tp->t_termios);
2339f1eda9eSsam if (ev == 0) {
2349f1eda9eSsam error = ENOBUFS;
2359f1eda9eSsam goto bad;
2369f1eda9eSsam }
2377c9a9841Sbostic mp->mp_flags |= MP_PROGRESS;
2389f1eda9eSsam mpcmd(ev, EVCMD_OPEN, 0, ms->ms_mb, port);
2397c9a9841Sbostic /*
2407c9a9841Sbostic * wait for port to start
2417c9a9841Sbostic */
2427c9a9841Sbostic while (mp->mp_proto != MPPROTO_ASYNC)
243da918786Skarels if (error = tsleep((caddr_t)&tp->t_canq,
244da918786Skarels TTIPRI | PCATCH, ttopen, 0))
245da918786Skarels goto bad;
246ea54ad41Smarc ttsetwater(tp);
2477c9a9841Sbostic mp->mp_flags &= ~MP_PROGRESS;
248236c5145Sbostic }
249da918786Skarels while ((mode&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
250ea54ad41Smarc (tp->t_state & TS_CARR_ON) == 0) {
251034a05d2Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
252034a05d2Smarc ttopen, 0))
253da918786Skarels goto bad;
2547c9a9841Sbostic /*
2557c9a9841Sbostic * a mpclose() might have disabled port. if so restart
2567c9a9841Sbostic */
2577c9a9841Sbostic if (mp->mp_proto != MPPROTO_ASYNC)
2587c9a9841Sbostic goto restart;
2597c9a9841Sbostic tp->t_state |= TS_WOPEN;
2607c9a9841Sbostic }
2619f1eda9eSsam error = (*linesw[tp->t_line].l_open)(dev,tp);
2629f1eda9eSsam done:
2639f1eda9eSsam splx(s);
2647c9a9841Sbostic /*
2657c9a9841Sbostic * wakeup those processes waiting for the open to complete
2667c9a9841Sbostic */
2679f1eda9eSsam wakeup((caddr_t)&tp->t_canq);
2689f1eda9eSsam return (error);
2699f1eda9eSsam bad:
2709f1eda9eSsam tp->t_state &= ~TS_WOPEN;
2719f1eda9eSsam goto done;
2729f1eda9eSsam }
2739f1eda9eSsam
2749f1eda9eSsam /*
2759f1eda9eSsam * Close an mpcc port.
2769f1eda9eSsam */
277b092cf00Skarels /* ARGSUSED */
mpclose(dev,flag)278b092cf00Skarels mpclose(dev, flag)
2799f1eda9eSsam dev_t dev;
2809f1eda9eSsam {
2819f1eda9eSsam register struct tty *tp;
2829f1eda9eSsam register struct mpport *mp;
2839f1eda9eSsam register struct mpevent *ev;
284da918786Skarels int s, port, unit, error = 0;
2859f1eda9eSsam struct mblok *mb;
2869f1eda9eSsam
2879f1eda9eSsam unit = minor(dev);
2889f1eda9eSsam tp = &mp_tty[unit];
2899f1eda9eSsam port = MPPORT(unit);
2909f1eda9eSsam mb = mp_softc[MPUNIT(unit)].ms_mb;
2919f1eda9eSsam mp = &mb->mb_port[port];
2929f1eda9eSsam s = spl8();
2937c9a9841Sbostic if (mp->mp_flags & MP_PROGRESS) {
2949f1eda9eSsam if (mp->mp_flags & MP_REMBSY) {
2959f1eda9eSsam mp->mp_flags &= ~MP_REMBSY;
2969f1eda9eSsam splx(s);
2979f1eda9eSsam return (0);
2989f1eda9eSsam }
2999f1eda9eSsam while (mp->mp_flags & MP_PROGRESS)
300da918786Skarels if (error = tsleep((caddr_t)&tp->t_canq,
301da918786Skarels TTIPRI | PCATCH, ttclos, 0)) {
302da918786Skarels splx(s);
303da918786Skarels return (error);
3049f1eda9eSsam }
305da918786Skarels }
3069f1eda9eSsam mp->mp_flags |= MP_PROGRESS;
307*3760269aSmarc (*linesw[tp->t_line].l_close)(tp, flag);
3087c9a9841Sbostic ev = mp_getevent(mp, unit, 1);
3099f1eda9eSsam if (ev == 0) {
3109f1eda9eSsam error = ENOBUFS;
311e165ffd9Sbostic mp->mp_flags &= ~MP_PROGRESS;
3129f1eda9eSsam goto out;
3139f1eda9eSsam }
314e165ffd9Sbostic if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
315e165ffd9Sbostic mpmodem(unit, MMOD_OFF);
316e165ffd9Sbostic else
317e165ffd9Sbostic mpmodem(unit, MMOD_ON);
3189f1eda9eSsam mpcmd(ev, EVCMD_CLOSE, 0, mb, port);
319da918786Skarels error = ttyclose(tp);
3209f1eda9eSsam out:
3219f1eda9eSsam if (mp->mp_flags & MP_REMBSY)
3229f1eda9eSsam mpclean(mb, port);
3237c9a9841Sbostic else
324da918786Skarels while (mp->mp_flags & MP_PROGRESS && error == 0)
325da918786Skarels error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH,
326da918786Skarels ttclos, 0);
3279f1eda9eSsam splx(s);
3289f1eda9eSsam return (error);
3299f1eda9eSsam }
3309f1eda9eSsam
3319f1eda9eSsam /*
3329f1eda9eSsam * Read from an mpcc port.
3339f1eda9eSsam */
mpread(dev,uio,flag)334ea54ad41Smarc mpread(dev, uio, flag)
3359f1eda9eSsam dev_t dev;
3369f1eda9eSsam struct uio *uio;
3379f1eda9eSsam {
3389f1eda9eSsam struct tty *tp;
3399f1eda9eSsam
3409f1eda9eSsam tp = &mp_tty[minor(dev)];
341ea54ad41Smarc return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
3429f1eda9eSsam }
3439f1eda9eSsam
3449f1eda9eSsam /*
3459f1eda9eSsam * Write to an mpcc port.
3469f1eda9eSsam */
mpwrite(dev,uio,flag)347ea54ad41Smarc mpwrite(dev, uio, flag)
3489f1eda9eSsam dev_t dev;
3499f1eda9eSsam struct uio *uio;
3509f1eda9eSsam {
3519f1eda9eSsam struct tty *tp;
3529f1eda9eSsam
3539f1eda9eSsam tp = &mp_tty[minor(dev)];
354ea54ad41Smarc return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
3559f1eda9eSsam }
3569f1eda9eSsam
3579f1eda9eSsam /*
3589f1eda9eSsam * Ioctl for a mpcc port
3599f1eda9eSsam */
mpioctl(dev,cmd,data,flag)3609f1eda9eSsam mpioctl(dev, cmd, data, flag)
3619f1eda9eSsam dev_t dev;
3629f1eda9eSsam caddr_t data;
3639f1eda9eSsam {
3649f1eda9eSsam register struct tty *tp;
3659f1eda9eSsam register struct mpsoftc *ms;
3669f1eda9eSsam register struct mpport *mp;
367ea54ad41Smarc register struct mpevent *ev;
3689f1eda9eSsam int s, port, error, unit;
3699f1eda9eSsam struct mblok *mb;
3709f1eda9eSsam
3719f1eda9eSsam unit = minor(dev);
3729f1eda9eSsam tp = &mp_tty[unit];
3739f1eda9eSsam ms = &mp_softc[MPUNIT(unit)];
3749f1eda9eSsam mb = ms->ms_mb;
3757c9a9841Sbostic port = MPPORT(unit);
3767c9a9841Sbostic mp = &mb->mb_port[port];
3777c9a9841Sbostic if (mp->mp_proto != MPPROTO_ASYNC)
3787c9a9841Sbostic return(ENXIO);
3799f1eda9eSsam error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3809f1eda9eSsam if (error >= 0)
3819f1eda9eSsam return (error);
3829f1eda9eSsam error = ttioctl(tp, cmd, data, flag);
383ea54ad41Smarc if (error >= 0)
3849f1eda9eSsam return (error);
3859f1eda9eSsam switch (cmd) {
3869f1eda9eSsam case TIOCSBRK: /* send break */
3879f1eda9eSsam case TIOCCBRK: /* clear break */
3889f1eda9eSsam s = spl8();
3897c9a9841Sbostic while (mp->mp_flags & MP_IOCTL) {
390da918786Skarels if (error = tsleep((caddr_t)&tp->t_canq,
391da918786Skarels TTIPRI | PCATCH, ttyout, 0)) {
392da918786Skarels splx(s);
393da918786Skarels return (error);
394da918786Skarels }
3957c9a9841Sbostic if (mp->mp_proto != MPPROTO_ASYNC) {
3967c9a9841Sbostic splx(s);
3977c9a9841Sbostic return (ENXIO);
3987c9a9841Sbostic }
3997c9a9841Sbostic }
4007c9a9841Sbostic ev = mp_getevent(mp, unit, 0);
4017c9a9841Sbostic if (ev) {
4027c9a9841Sbostic mp->mp_flags |= MP_IOCTL;
4039f1eda9eSsam mpcmd(ev, EVCMD_IOCTL,
4047c9a9841Sbostic (cmd == TIOCSBRK ? A_BRKON : A_BRKOFF), mb, port);
4057c9a9841Sbostic } else
4069f1eda9eSsam error = ENOBUFS;
4079f1eda9eSsam splx(s);
4089f1eda9eSsam break;
4099f1eda9eSsam case TIOCSDTR: /* set dtr control line */
4109f1eda9eSsam break;
4119f1eda9eSsam case TIOCCDTR: /* clear dtr control line */
4129f1eda9eSsam break;
4139f1eda9eSsam default:
4149f1eda9eSsam error = ENOTTY;
4159f1eda9eSsam break;
4169f1eda9eSsam }
4179f1eda9eSsam return (error);
4189f1eda9eSsam }
4199f1eda9eSsam
420ea54ad41Smarc mpparam(tp, t)
421ea54ad41Smarc struct tty *tp;
422ea54ad41Smarc struct termios *t;
423ea54ad41Smarc {
424ea54ad41Smarc register struct mpevent *ev;
425ea54ad41Smarc int unit = minor(tp->t_dev);
426ea54ad41Smarc struct mpsoftc *ms = &mp_softc[MPUNIT(unit)];
427ea54ad41Smarc struct mblok *mb = ms->ms_mb;
428ea54ad41Smarc
429ea54ad41Smarc ev = mpparam2(tp, t);
430ea54ad41Smarc if (ev == 0)
431ea54ad41Smarc return (ENOBUFS);
432ea54ad41Smarc mpcmd(ev, EVCMD_IOCTL, A_CHGALL, mb, MPPORT(unit));
433ea54ad41Smarc return (0);
434ea54ad41Smarc }
435ea54ad41Smarc
4369f1eda9eSsam struct mpevent *
mpparam2(tp,t)437ea54ad41Smarc mpparam2(tp, t)
438ea54ad41Smarc register struct tty *tp;
439ea54ad41Smarc struct termios *t;
4409f1eda9eSsam {
4419f1eda9eSsam register struct mpevent *ev;
4429f1eda9eSsam register struct mpport *mp;
443ea54ad41Smarc int unit = minor(tp->t_dev);
4449f1eda9eSsam struct mblok *mb;
4459f1eda9eSsam struct mpsoftc *ms;
4469f1eda9eSsam register struct asyncparam *asp;
447ea54ad41Smarc int port, speedcode;
4489f1eda9eSsam
4499f1eda9eSsam ms = &mp_softc[MPUNIT(unit)];
4509f1eda9eSsam mb = ms->ms_mb;
4519f1eda9eSsam port = MPPORT(unit);
4529f1eda9eSsam mp = &mb->mb_port[port];
4537c9a9841Sbostic ev = mp_getevent(mp, unit, 0); /* XXX */
454ea54ad41Smarc speedcode = ttspeedtab(t->c_ospeed, mpspeedtab);
455ea54ad41Smarc if (ev == 0 || speedcode < 0) {
456ea54ad41Smarc printf("mp mpunit %d port %d param2 failed ev: %x speed %d, wanted %d\n",
457ea54ad41Smarc MPUNIT(unit), port, ev, speedcode, t->c_ospeed);
458ea54ad41Smarc return (0); /* XXX */
459ea54ad41Smarc }
4609f1eda9eSsam /* YUCK */
4619f1eda9eSsam asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1];
462ea54ad41Smarc asp->ap_xon = t->c_cc[VSTART];
463ea54ad41Smarc asp->ap_xoff = t->c_cc[VSTOP];
464ea54ad41Smarc if (!(t->c_iflag&IXON) || (asp->ap_xon == _POSIX_VDISABLE) ||
465ea54ad41Smarc (asp->ap_xoff == _POSIX_VDISABLE))
466c870bd1bSbostic asp->ap_xena = MPA_DIS;
467c870bd1bSbostic else
468c870bd1bSbostic asp->ap_xena = MPA_ENA;
469ea54ad41Smarc asp->ap_xany = ((t->c_iflag & IXANY) ? MPA_ENA : MPA_DIS);
4709f1eda9eSsam #ifdef notnow
471ea54ad41Smarc if (t->t_cflag&CSIZE) == CS8) {
4729f1eda9eSsam #endif
4739f1eda9eSsam asp->ap_data = MPCHAR_8;
4749f1eda9eSsam asp->ap_parity = MPPAR_NONE;
4759f1eda9eSsam #ifdef notnow
4769f1eda9eSsam } else {
4779f1eda9eSsam asp->ap_data = MPCHAR_7;
478ea54ad41Smarc if ((t->c_flags & (EVENP|ODDP)) == ODDP) /* XXX */
4799f1eda9eSsam asp->ap_parity = MPPAR_ODD;
4809f1eda9eSsam else
4819f1eda9eSsam asp->ap_parity = MPPAR_EVEN;
4829f1eda9eSsam }
4839f1eda9eSsam #endif
4847c9a9841Sbostic asp->ap_loop = MPA_DIS; /* disable loopback */
4857c9a9841Sbostic asp->ap_rtimer = A_RCVTIM; /* default receive timer */
486ea54ad41Smarc if (t->c_ospeed == B110)
4879f1eda9eSsam asp->ap_stop = MPSTOP_2;
4889f1eda9eSsam else
4899f1eda9eSsam asp->ap_stop = MPSTOP_1;
490ea54ad41Smarc if (t->c_ospeed == 0) {
4917c9a9841Sbostic tp->t_state |= TS_HUPCLS;
4927c9a9841Sbostic setm(&asp->ap_modem, 0, DROP);
4937c9a9841Sbostic seti(&asp->ap_intena, A_DCD);
4947c9a9841Sbostic return (ev);
4957c9a9841Sbostic }
496ea54ad41Smarc if (t->c_ospeed == EXTA || t->c_ospeed == EXTB)
4979f1eda9eSsam asp->ap_baud = M19200;
4989f1eda9eSsam else
499ea54ad41Smarc asp->ap_baud = speedcode;
500ea54ad41Smarc if (1 || ms->ms_softCAR & (1<<port)) /* XXX HARDWIRE FOR NOW */
5019f1eda9eSsam setm(&asp->ap_modem, A_DTR, ASSERT);
5029f1eda9eSsam else
5039f1eda9eSsam setm(&asp->ap_modem, A_DTR, AUTO);
5049f1eda9eSsam seti(&asp->ap_intena, A_DCD);
5059f1eda9eSsam return(ev);
5069f1eda9eSsam }
5079f1eda9eSsam
mpstart(tp)5089f1eda9eSsam mpstart(tp)
5099f1eda9eSsam register struct tty *tp;
5109f1eda9eSsam {
5119f1eda9eSsam register struct mpevent *ev;
5129f1eda9eSsam register struct mpport *mp;
5139f1eda9eSsam struct mblok *mb;
5149f1eda9eSsam struct mpsoftc *ms;
5159f1eda9eSsam int port, unit, xcnt, n, s, i;
5169f1eda9eSsam struct hxmtl *hxp;
5179f1eda9eSsam struct clist outq;
5189f1eda9eSsam
5199f1eda9eSsam s = spl8();
5209f1eda9eSsam unit = minor(tp->t_dev);
5219f1eda9eSsam ms = &mp_softc[MPUNIT(unit)];
5229f1eda9eSsam mb = ms->ms_mb;
5239f1eda9eSsam port = MPPORT(unit);
5249f1eda9eSsam mp = &mb->mb_port[port];
5259f1eda9eSsam hxp = &ms->ms_hxl[port];
5269f1eda9eSsam xcnt = 0;
5279f1eda9eSsam outq = tp->t_outq;
5289f1eda9eSsam for (i = 0; i < MPXMIT; i++) {
5299f1eda9eSsam if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
5309f1eda9eSsam break;
531ea54ad41Smarc if (outq.c_cc <= tp->t_lowat) {
5329f1eda9eSsam if (tp->t_state & TS_ASLEEP) {
5339f1eda9eSsam tp->t_state &= ~TS_ASLEEP;
5349f1eda9eSsam wakeup((caddr_t)&tp->t_outq);
5359f1eda9eSsam }
5369f1eda9eSsam if (tp->t_wsel) {
5379f1eda9eSsam selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5389f1eda9eSsam tp->t_wsel = 0;
5399f1eda9eSsam tp->t_state &= ~TS_WCOLL;
5409f1eda9eSsam }
5419f1eda9eSsam }
5429f1eda9eSsam if (outq.c_cc == 0)
5439f1eda9eSsam break;
5449f1eda9eSsam /*
5459f1eda9eSsam * If we're not currently busy outputting,
5469f1eda9eSsam * and there is data to be output, set up
5479f1eda9eSsam * port transmit structure to send to mpcc.
5489f1eda9eSsam */
549ea54ad41Smarc if (1) /* || tp->t_flags & (RAW|LITOUT)) XXX FIX */
5509f1eda9eSsam n = ndqb(&outq, 0);
5519f1eda9eSsam else {
5529f1eda9eSsam n = ndqb(&outq, 0200);
5539f1eda9eSsam if (n == 0) {
5547c9a9841Sbostic if (xcnt > 0)
5557c9a9841Sbostic break;
5569f1eda9eSsam n = getc(&outq);
5579f1eda9eSsam timeout(ttrstrt, (caddr_t)tp, (n&0177)+6);
5589f1eda9eSsam tp->t_state |= TS_TIMEOUT;
5599f1eda9eSsam break;
5609f1eda9eSsam }
5619f1eda9eSsam }
562b092cf00Skarels hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf);
5639f1eda9eSsam hxp->size[i] = n;
5649f1eda9eSsam xcnt++; /* count of xmts to send */
5659f1eda9eSsam ndadvance(&outq, n);
5669f1eda9eSsam }
5679f1eda9eSsam /*
5689f1eda9eSsam * If data to send, poke mpcc.
5699f1eda9eSsam */
5709f1eda9eSsam if (xcnt) {
5717c9a9841Sbostic ev = mp_getevent(mp, unit, 0);
5729f1eda9eSsam if (ev == 0) {
5739f1eda9eSsam tp->t_state &= ~(TS_BUSY|TS_TIMEOUT);
5749f1eda9eSsam } else {
5759f1eda9eSsam tp->t_state |= TS_BUSY;
5769f1eda9eSsam ev->ev_count = xcnt;
5779f1eda9eSsam mpcmd(ev, EVCMD_WRITE, 0, mb, MPPORT(unit));
5789f1eda9eSsam }
5799f1eda9eSsam }
5809f1eda9eSsam splx(s);
5819f1eda9eSsam }
5829f1eda9eSsam
5839f1eda9eSsam /*
5849f1eda9eSsam * Advance cc bytes from q but don't free memory.
5859f1eda9eSsam */
ndadvance(q,cc)5869f1eda9eSsam ndadvance(q, cc)
5879f1eda9eSsam register struct clist *q;
5889f1eda9eSsam register cc;
5899f1eda9eSsam {
5909f1eda9eSsam register struct cblock *bp;
5919f1eda9eSsam char *end;
5929f1eda9eSsam int rem, s;
5939f1eda9eSsam
5949f1eda9eSsam s = spltty();
5959f1eda9eSsam if (q->c_cc <= 0)
5969f1eda9eSsam goto out;
5979f1eda9eSsam while (cc>0 && q->c_cc) {
5989f1eda9eSsam bp = (struct cblock *)((int)q->c_cf & ~CROUND);
5999f1eda9eSsam if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
6009f1eda9eSsam end = q->c_cl;
6019f1eda9eSsam } else {
6029f1eda9eSsam end = (char *)((int)bp + sizeof (struct cblock));
6039f1eda9eSsam }
6049f1eda9eSsam rem = end - q->c_cf;
6059f1eda9eSsam if (cc >= rem) {
6069f1eda9eSsam cc -= rem;
6079f1eda9eSsam q->c_cc -= rem;
6089f1eda9eSsam q->c_cf = bp->c_next->c_info;
6099f1eda9eSsam } else {
6109f1eda9eSsam q->c_cc -= cc;
6119f1eda9eSsam q->c_cf += cc;
6129f1eda9eSsam break;
6139f1eda9eSsam }
6149f1eda9eSsam }
6159f1eda9eSsam if (q->c_cc <= 0) {
6169f1eda9eSsam q->c_cf = q->c_cl = NULL;
6179f1eda9eSsam q->c_cc = 0;
6189f1eda9eSsam }
6199f1eda9eSsam out:
6209f1eda9eSsam splx(s);
6219f1eda9eSsam }
6229f1eda9eSsam
6239f1eda9eSsam /*
6249f1eda9eSsam * Stop output on a line, e.g. for ^S/^Q or output flush.
6259f1eda9eSsam */
626b092cf00Skarels /* ARGSUSED */
mpstop(tp,rw)6279f1eda9eSsam mpstop(tp, rw)
6289f1eda9eSsam register struct tty *tp;
6299f1eda9eSsam int rw;
6309f1eda9eSsam {
6317c9a9841Sbostic register struct mpport *mp;
6327c9a9841Sbostic register struct mpevent *ev;
6337c9a9841Sbostic int unit = minor(tp->t_dev);
6347c9a9841Sbostic int port;
6357c9a9841Sbostic struct mblok *mb;
636b092cf00Skarels int s;
6379f1eda9eSsam
6389f1eda9eSsam s = spl8();
6399f1eda9eSsam if (tp->t_state & TS_BUSY) {
6407c9a9841Sbostic if ((tp->t_state & TS_TTSTOP) == 0) {
6419f1eda9eSsam tp->t_state |= TS_FLUSH;
6427c9a9841Sbostic port = MPPORT(unit);
6437c9a9841Sbostic mb = mp_softc[MPUNIT(unit)].ms_mb;
6447c9a9841Sbostic mp = &mb->mb_port[port];
6457c9a9841Sbostic ev = mp_getevent(mp, unit, 0);
6467c9a9841Sbostic if (ev == 0) {
6477c9a9841Sbostic splx(s);
6487c9a9841Sbostic return;
6497c9a9841Sbostic }
6507c9a9841Sbostic mpcmd(ev, EVCMD_WRITE, A_FLUSH, mb, port);
6517c9a9841Sbostic }
6529f1eda9eSsam }
6539f1eda9eSsam splx(s);
6549f1eda9eSsam }
6559f1eda9eSsam
6569f1eda9eSsam /*
6579f1eda9eSsam * Initialize an async port's MPCC state.
6589f1eda9eSsam */
mpportinit(ms,mp,port)6599f1eda9eSsam mpportinit(ms, mp, port)
6609f1eda9eSsam register struct mpsoftc *ms;
6619f1eda9eSsam register struct mpport *mp;
6629f1eda9eSsam int port;
6639f1eda9eSsam {
6649f1eda9eSsam register struct mpevent *ev;
6659f1eda9eSsam register int i;
6669f1eda9eSsam caddr_t ptr;
6679f1eda9eSsam
6689f1eda9eSsam mp->mp_on = mp->mp_off = 0;
6699f1eda9eSsam mp->mp_nextrcv = 0;
6709f1eda9eSsam mp->mp_flags = 0;
6719f1eda9eSsam ev = &mp->mp_recvq[0];
6729f1eda9eSsam for (i = 0; ev < &mp->mp_recvq[MPINSET]; ev++, i++) {
6739f1eda9eSsam ev->ev_status = EVSTATUS_FREE;
6749f1eda9eSsam ev->ev_cmd = 0;
6759f1eda9eSsam ev->ev_opts = 0;
6769f1eda9eSsam ev->ev_error = 0;
6779f1eda9eSsam ev->ev_flags = 0;
6789f1eda9eSsam ev->ev_count = 0;
679b092cf00Skarels ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]);
680b092cf00Skarels ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]);
6819f1eda9eSsam }
6829f1eda9eSsam ev = &mp->mp_sendq[0];
6839f1eda9eSsam for (i = 0; ev < &mp->mp_sendq[MPOUTSET]; ev++, i++) {
6849f1eda9eSsam /* init so that L2 can't send any events */
6859f1eda9eSsam /* to host until open has completed */
6869f1eda9eSsam ev->ev_status = EVSTATUS_FREE;
6879f1eda9eSsam ev->ev_cmd = 0;
6887c9a9841Sbostic ev->ev_opts = 0;
6899f1eda9eSsam ev->ev_error = 0;
6909f1eda9eSsam ev->ev_flags = 0;
6919f1eda9eSsam ev->ev_count = 0;
6929f1eda9eSsam ptr = (caddr_t) &ms->ms_cbuf[port][i][0];
693b092cf00Skarels ev->ev_un.rcvblk = (u_char *)kvtophys(ptr);
694b092cf00Skarels ev->ev_params = (caddr_t) kvtophys(ptr);
6959f1eda9eSsam }
6969f1eda9eSsam return (0);
6979f1eda9eSsam }
6989f1eda9eSsam
6999f1eda9eSsam /*
7009f1eda9eSsam * Send an event to an mpcc.
7019f1eda9eSsam */
mpcmd(ev,cmd,flags,mb,port)7029f1eda9eSsam mpcmd(ev, cmd, flags, mb, port)
7039f1eda9eSsam register struct mpevent *ev;
7049f1eda9eSsam struct mblok *mb;
7059f1eda9eSsam {
7069f1eda9eSsam int s;
7079f1eda9eSsam
7089f1eda9eSsam s = spl8();
7099f1eda9eSsam /* move host values to inbound entry */
7109f1eda9eSsam ev->ev_cmd = cmd;
7119f1eda9eSsam ev->ev_opts = flags;
7129f1eda9eSsam /* show event ready for mpcc */
7139f1eda9eSsam ev->ev_status = EVSTATUS_GO;
7149f1eda9eSsam mpintmpcc(mb, port);
7159f1eda9eSsam splx(s);
7169f1eda9eSsam }
7179f1eda9eSsam
7189f1eda9eSsam /*
7199f1eda9eSsam * Return the next available event entry for the indicated port.
7209f1eda9eSsam */
7219f1eda9eSsam struct mpevent *
mp_getevent(mp,unit,cls_req)7227c9a9841Sbostic mp_getevent(mp, unit, cls_req)
7239f1eda9eSsam register struct mpport *mp;
7249f1eda9eSsam int unit;
7257c9a9841Sbostic int cls_req;
7269f1eda9eSsam {
7279f1eda9eSsam register struct mpevent *ev;
7289f1eda9eSsam int i, s;
7299f1eda9eSsam
7309f1eda9eSsam s = spl8();
7319f1eda9eSsam ev = &mp->mp_recvq[mp->mp_on];
7329f1eda9eSsam if (ev->ev_status != EVSTATUS_FREE)
7339f1eda9eSsam goto bad;
7349f1eda9eSsam /*
7359f1eda9eSsam * If not a close request, verify one extra
7369f1eda9eSsam * event is available for closing the port.
7379f1eda9eSsam */
7387c9a9841Sbostic if (!cls_req) {
7399f1eda9eSsam if ((i = mp->mp_on + 1) >= MPINSET)
7409f1eda9eSsam i = 0;
7419f1eda9eSsam if (mp->mp_recvq[i].ev_status != EVSTATUS_FREE)
7429f1eda9eSsam goto bad;
7439f1eda9eSsam }
7449f1eda9eSsam /* init inbound fields marking this entry as busy */
7457c9a9841Sbostic ev->ev_cmd = 0;
7467c9a9841Sbostic ev->ev_opts = 0;
7479f1eda9eSsam ev->ev_error = 0;
7489f1eda9eSsam ev->ev_flags = 0;
7499f1eda9eSsam ev->ev_count = 0;
7509f1eda9eSsam ev->ev_status = EVSTATUS_BUSY;
7519f1eda9eSsam /* adjust pointer to next available inbound entry */
7529f1eda9eSsam adjptr(mp->mp_on, MPINSET);
7539f1eda9eSsam splx(s);
7549f1eda9eSsam return (ev);
7559f1eda9eSsam bad:
7569f1eda9eSsam splx(s);
7577c9a9841Sbostic log(LOG_ERR, "mp%d: port%d, out of events\n",
7587c9a9841Sbostic MPUNIT(unit), MPPORT(unit));
7599f1eda9eSsam return ((struct mpevent *)0);
7609f1eda9eSsam }
7619f1eda9eSsam
mpmodem(unit,flag)7629f1eda9eSsam mpmodem(unit, flag)
7639f1eda9eSsam int unit, flag;
7649f1eda9eSsam {
7659f1eda9eSsam struct mpsoftc *ms = &mp_softc[MPUNIT(unit)];
7669f1eda9eSsam int port = MPPORT(unit);
7679f1eda9eSsam register struct mpport *mp;
7689f1eda9eSsam register struct asyncparam *asp;
7699f1eda9eSsam
7709f1eda9eSsam mp = &ms->ms_mb->mb_port[port];
7719f1eda9eSsam asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1];
7729f1eda9eSsam if (flag == MMOD_ON) {
773ea54ad41Smarc if (1 || ms->ms_softCAR & (1 << port))/* XXX HARDWIRE FOR NOW */
7749f1eda9eSsam setm(&asp->ap_modem, A_DTR, ASSERT);
7759f1eda9eSsam else
7769f1eda9eSsam setm(&asp->ap_modem, A_DTR, AUTO);
7779f1eda9eSsam seti(&asp->ap_intena, A_DCD);
7789f1eda9eSsam } else {
7799f1eda9eSsam setm(&asp->ap_modem, 0, DROP);
7809f1eda9eSsam seti(&asp->ap_intena, 0);
7819f1eda9eSsam }
7829f1eda9eSsam }
7839f1eda9eSsam
7849f1eda9eSsam /*
7859f1eda9eSsam * Set up the modem control structure according to mask.
7869f1eda9eSsam * Each set bit in the mask means assert the corresponding
7879f1eda9eSsam * modem control line, otherwise, it will be dropped.
7889f1eda9eSsam * RTS is special since it can either be asserted, dropped
7899f1eda9eSsam * or put in auto mode for auto modem control.
7909f1eda9eSsam */
7919f1eda9eSsam static
setm(mc,mask,rts)7929f1eda9eSsam setm(mc, mask, rts)
7939f1eda9eSsam register struct mdmctl *mc;
7949f1eda9eSsam register int mask;
7959f1eda9eSsam {
7969f1eda9eSsam
7979f1eda9eSsam mc->mc_rngdsr = (mask & A_RNGDSR) ? ASSERT : DROP;
7989f1eda9eSsam mc->mc_rate = (mask & A_RATE) ? ASSERT : DROP;
7999f1eda9eSsam mc->mc_dcd = (mask & A_DCD) ? ASSERT : DROP;
8009f1eda9eSsam mc->mc_sectx = (mask & A_SECTX) ? ASSERT : DROP;
8019f1eda9eSsam mc->mc_cts = (mask & A_CTS) ? ASSERT : DROP;
8029f1eda9eSsam mc->mc_secrx = (mask & A_SECRX) ? ASSERT : DROP;
8039f1eda9eSsam mc->mc_dtr = (mask & A_DTR) ? ASSERT : DROP;
8049f1eda9eSsam mc->mc_rts = rts;
8059f1eda9eSsam }
8069f1eda9eSsam
8079f1eda9eSsam /*
8089f1eda9eSsam * Set up the status change enable field from mask.
8099f1eda9eSsam * When a signal is enabled in this structure and
8109f1eda9eSsam * and a change in state on a corresponding modem
8119f1eda9eSsam * control line occurs, a status change event will
8129f1eda9eSsam * be delivered to the host.
8139f1eda9eSsam */
8149f1eda9eSsam static
seti(mc,mask)8159f1eda9eSsam seti(mc, mask)
8169f1eda9eSsam register struct mdmctl *mc;
8179f1eda9eSsam register int mask;
8189f1eda9eSsam {
8199f1eda9eSsam
8209f1eda9eSsam mc->mc_rngdsr = (mask & A_RNGDSR) ? MDM_ON : MDM_OFF;
8219f1eda9eSsam mc->mc_rate = (mask & A_RATE) ? MDM_ON : MDM_OFF;
8229f1eda9eSsam mc->mc_dcd = (mask & A_DCD) ? MDM_ON : MDM_OFF;
8239f1eda9eSsam mc->mc_sectx = (mask & A_SECTX) ? MDM_ON : MDM_OFF;
8249f1eda9eSsam mc->mc_cts = (mask & A_CTS) ? MDM_ON : MDM_OFF;
8259f1eda9eSsam mc->mc_secrx = (mask & A_SECRX) ? MDM_ON : MDM_OFF;
8269f1eda9eSsam mc->mc_dtr = (mask & A_DTR) ? MDM_ON : MDM_OFF;
8279f1eda9eSsam mc->mc_rts = (mask & A_RTS) ? MDM_ON : MDM_OFF;
8289f1eda9eSsam }
8299f1eda9eSsam
8309f1eda9eSsam mpcleanport(mb, port)
8319f1eda9eSsam struct mblok *mb;
8329f1eda9eSsam int port;
8339f1eda9eSsam {
8349f1eda9eSsam register struct mpport *mp;
8359f1eda9eSsam register struct tty *tp;
8369f1eda9eSsam
8379f1eda9eSsam mp = &mb->mb_port[port];
8389f1eda9eSsam if (mp->mp_proto == MPPROTO_ASYNC) {
8399f1eda9eSsam mp->mp_flags = MP_REMBSY;
840b092cf00Skarels /* signal loss of carrier and close */
8419f1eda9eSsam tp = &mp_tty[mb->mb_unit*MPCHUNK+port];
8429f1eda9eSsam ttyflush(tp, FREAD|FWRITE);
843b092cf00Skarels (void) (*linesw[tp->t_line].l_modem)(tp, 0);
8449f1eda9eSsam }
8459f1eda9eSsam }
8469f1eda9eSsam
mpclean(mb,port)8479f1eda9eSsam mpclean(mb, port)
8489f1eda9eSsam register struct mblok *mb;
8499f1eda9eSsam int port;
8509f1eda9eSsam {
8519f1eda9eSsam register struct mpport *mp;
8529f1eda9eSsam register struct mpevent *ev;
8539f1eda9eSsam register int i;
854b092cf00Skarels u_char list[2];
8559f1eda9eSsam int unit;
8569f1eda9eSsam
8579f1eda9eSsam mp = &mb->mb_port[port];
8589f1eda9eSsam unit = mb->mb_unit;
8599f1eda9eSsam for (i = mp->mp_off; i != mp->mp_on; i = (i+1 % MPINSET)) {
8609f1eda9eSsam ev = &mp->mp_recvq[i];
8619f1eda9eSsam ev->ev_error = ENXIO;
8629f1eda9eSsam ev->ev_status = EVSTATUS_DONE;
8639f1eda9eSsam }
8649f1eda9eSsam list[0] = port, list[1] = MPPORT_EOL;
8659f1eda9eSsam mpxintr(unit, list);
8669f1eda9eSsam mprintr(unit, list);
8679f1eda9eSsam /* Clear async for port */
8689f1eda9eSsam mp->mp_proto = MPPROTO_UNUSED;
8699f1eda9eSsam mp->mp_flags = 0;
8709f1eda9eSsam mp->mp_on = 0;
8719f1eda9eSsam mp->mp_off = 0;
8729f1eda9eSsam mp->mp_nextrcv = 0;
8739f1eda9eSsam
8749f1eda9eSsam mp_tty[unit*MPCHUNK + port].t_state = 0;
8759f1eda9eSsam for (ev = &mp->mp_sendq[0]; ev < &mp->mp_sendq[MPOUTSET]; ev++) {
8769f1eda9eSsam ev->ev_status = EVSTATUS_FREE;
8779f1eda9eSsam ev->ev_cmd = 0;
8789f1eda9eSsam ev->ev_error = 0;
8799f1eda9eSsam ev->ev_un.rcvblk = 0;
8809f1eda9eSsam ev->ev_params = 0;
8819f1eda9eSsam }
8829f1eda9eSsam for (ev = &mp->mp_recvq[0]; ev < &mp->mp_recvq[MPINSET]; ev++) {
8839f1eda9eSsam ev->ev_status = EVSTATUS_FREE;
8849f1eda9eSsam ev->ev_cmd = 0;
8859f1eda9eSsam ev->ev_error = 0;
8869f1eda9eSsam ev->ev_params = 0;
8879f1eda9eSsam }
8889f1eda9eSsam }
8899f1eda9eSsam
8909f1eda9eSsam /*
8919f1eda9eSsam * MPCC interrupt handler.
8929f1eda9eSsam */
mpintr(mpcc)8939f1eda9eSsam mpintr(mpcc)
8949f1eda9eSsam int mpcc;
8959f1eda9eSsam {
8969f1eda9eSsam register struct mblok *mb;
8979f1eda9eSsam register struct his *his;
8989f1eda9eSsam
8999f1eda9eSsam mb = mp_softc[mpcc].ms_mb;
9009f1eda9eSsam if (mb == 0) {
9019f1eda9eSsam printf("mp%d: stray interrupt\n", mpcc);
9029f1eda9eSsam return;
9039f1eda9eSsam }
9049f1eda9eSsam his = &mb->mb_hostint;
9059f1eda9eSsam his->semaphore &= ~MPSEMA_AVAILABLE;
9069f1eda9eSsam /*
9079f1eda9eSsam * Check for events to be processed.
9089f1eda9eSsam */
9099f1eda9eSsam if (his->proto[MPPROTO_ASYNC].outbdone[0] != MPPORT_EOL)
9109f1eda9eSsam mprintr(mpcc, his->proto[MPPROTO_ASYNC].outbdone);
9119f1eda9eSsam if (his->proto[MPPROTO_ASYNC].inbdone[0] != MPPORT_EOL)
9129f1eda9eSsam mpxintr(mpcc, his->proto[MPPROTO_ASYNC].inbdone);
9139f1eda9eSsam if (mb->mb_harderr || mb->mb_softerr)
9149f1eda9eSsam mperror(mb, mpcc);
9159f1eda9eSsam his->semaphore |= MPSEMA_AVAILABLE;
9169f1eda9eSsam }
9179f1eda9eSsam
9189f1eda9eSsam /*
9199f1eda9eSsam * Handler for processing completion of transmitted events.
9209f1eda9eSsam */
mpxintr(unit,list)9219f1eda9eSsam mpxintr(unit, list)
922b092cf00Skarels register u_char *list;
9239f1eda9eSsam {
9249f1eda9eSsam register struct mpport *mp;
9259f1eda9eSsam register struct mpevent *ev;
9269f1eda9eSsam register struct mblok *mb;
9279f1eda9eSsam register struct tty *tp;
9289f1eda9eSsam register struct asyncparam *ap;
9299f1eda9eSsam struct mpsoftc *ms;
9309f1eda9eSsam int port, i, j;
9317c9a9841Sbostic # define nextevent(mp) &mp->mp_recvq[mp->mp_off]
9329f1eda9eSsam
9339f1eda9eSsam ms = &mp_softc[unit];
9349f1eda9eSsam mb = mp_softc[unit].ms_mb;
9359f1eda9eSsam for (j = 0; j < MPMAXPORT && ((port = *list++) != MPPORT_EOL); j++) {
9369f1eda9eSsam /*
9379f1eda9eSsam * Process each completed entry in the inbound queue.
9389f1eda9eSsam */
9399f1eda9eSsam mp = &mb->mb_port[port];
9409f1eda9eSsam tp = &mp_tty[unit*MPCHUNK + port];
9419f1eda9eSsam ev = nextevent(mp);
9429f1eda9eSsam for (; ev->ev_status & EVSTATUS_DONE; ev = nextevent(mp)) {
9439f1eda9eSsam /* YUCK */
9449f1eda9eSsam ap = &ms->ms_async[port][mp->mp_off];
945b092cf00Skarels mppurge((caddr_t)ap, (int)sizeof (*ap));
9469f1eda9eSsam switch (ev->ev_cmd) {
9479f1eda9eSsam case EVCMD_OPEN:
9489f1eda9eSsam /*
9499f1eda9eSsam * Open completion, start all reads and
9509f1eda9eSsam * assert modem status information.
9519f1eda9eSsam */
9529f1eda9eSsam for (i = 0; i < MPOUTSET; i++)
9539f1eda9eSsam mp->mp_sendq[i].ev_status = EVSTATUS_GO;
9549f1eda9eSsam (*linesw[tp->t_line].l_modem)
9559f1eda9eSsam (tp, ap->ap_modem.mc_dcd == ASSERT);
9567c9a9841Sbostic mp_freein(ev);
9577c9a9841Sbostic adjptr(mp->mp_off, MPINSET);
9587c9a9841Sbostic mp->mp_proto = MPPROTO_ASYNC; /* XXX */
9597c9a9841Sbostic wakeup((caddr_t)&tp->t_canq);
9609f1eda9eSsam break;
9619f1eda9eSsam case EVCMD_CLOSE:
9629f1eda9eSsam /*
9639f1eda9eSsam * Close completion, flush all pending
9649f1eda9eSsam * transmissions, free resources, and
9659f1eda9eSsam * cleanup mpcc port state.
9669f1eda9eSsam */
9679f1eda9eSsam for (i = 0; i < MPOUTSET; i++) {
9689f1eda9eSsam mp->mp_sendq[i].ev_status =
9699f1eda9eSsam EVSTATUS_FREE;
9709f1eda9eSsam mp->mp_sendq[i].ev_un.rcvblk = 0;
9719f1eda9eSsam mp->mp_sendq[i].ev_params = 0;
9729f1eda9eSsam }
9737c9a9841Sbostic mp_freein(ev);
9747c9a9841Sbostic adjptr(mp->mp_off, MPINSET);
9757c9a9841Sbostic tp->t_state &= ~(TS_CARR_ON|TS_BUSY|TS_FLUSH);
9769f1eda9eSsam mp->mp_on = mp->mp_off = mp->mp_nextrcv = 0;
9779f1eda9eSsam mp->mp_flags &= ~MP_PROGRESS;
9789f1eda9eSsam mp->mp_proto = MPPROTO_UNUSED;
97920eaab23Skarels wakeup((caddr_t)&tp->t_canq);
9807c9a9841Sbostic break;
9819f1eda9eSsam case EVCMD_IOCTL:
9827c9a9841Sbostic mp_freein(ev);
9837c9a9841Sbostic adjptr(mp->mp_off, MPINSET);
9847c9a9841Sbostic mp->mp_flags &= ~MP_IOCTL;
9857c9a9841Sbostic wakeup((caddr_t)&tp->t_canq);
9869f1eda9eSsam break;
9879f1eda9eSsam case EVCMD_WRITE:
9889f1eda9eSsam /*
9899f1eda9eSsam * Transmission completed, update tty
9909f1eda9eSsam * state and restart output.
9919f1eda9eSsam */
9927c9a9841Sbostic if (ev->ev_opts != A_FLUSH) {
9939f1eda9eSsam tp->t_state &= ~TS_BUSY;
99420eaab23Skarels if (tp->t_state & TS_FLUSH)
9959f1eda9eSsam tp->t_state &= ~TS_FLUSH;
99620eaab23Skarels else {
997b092cf00Skarels register int cc = 0, n;
9989f1eda9eSsam struct hxmtl *hxp;
9999f1eda9eSsam
10009f1eda9eSsam hxp = &ms->ms_hxl[port];
1001b092cf00Skarels for (n=0;n < ev->ev_count; n++)
1002b092cf00Skarels cc += hxp->size[n];
10039f1eda9eSsam ndflush(&tp->t_outq, cc);
10049f1eda9eSsam }
10057c9a9841Sbostic }
10069f1eda9eSsam switch (ev->ev_error) {
10079f1eda9eSsam case A_SIZERR: /*# error in xmt data size */
10089f1eda9eSsam mplog(unit, port, A_XSIZE, 0);
10099f1eda9eSsam break;
10109f1eda9eSsam case A_NXBERR: /*# no more xmt evt buffers */
10119f1eda9eSsam mplog(unit, port, A_NOXBUF, 0);
10129f1eda9eSsam break;
10139f1eda9eSsam }
10147c9a9841Sbostic mp_freein(ev);
10157c9a9841Sbostic adjptr(mp->mp_off, MPINSET);
10169f1eda9eSsam mpstart(tp);
10179f1eda9eSsam break;
10189f1eda9eSsam default:
1019b092cf00Skarels mplog(unit, port, A_INVCMD, (int)ev->ev_cmd);
10207c9a9841Sbostic mp_freein(ev);
10217c9a9841Sbostic adjptr(mp->mp_off, MPINSET);
10229f1eda9eSsam break;
10239f1eda9eSsam }
10247c9a9841Sbostic }
10257c9a9841Sbostic }
10267c9a9841Sbostic #undef nextevent
10277c9a9841Sbostic }
10287c9a9841Sbostic
mp_freein(ev)10297c9a9841Sbostic mp_freein(ev)
10307c9a9841Sbostic register struct mpevent *ev;
10317c9a9841Sbostic {
10329f1eda9eSsam /* re-init all values in this entry */
10339f1eda9eSsam ev->ev_cmd = 0;
10349f1eda9eSsam ev->ev_opts = 0;
10359f1eda9eSsam ev->ev_error = 0;
10369f1eda9eSsam ev->ev_flags = 0;
10379f1eda9eSsam ev->ev_count = 0;
10389f1eda9eSsam /* show this entry is available for use */
10399f1eda9eSsam ev->ev_status = EVSTATUS_FREE;
10409f1eda9eSsam }
10419f1eda9eSsam
10429f1eda9eSsam /*
10439f1eda9eSsam * Handler for processing received events.
10449f1eda9eSsam */
mprintr(unit,list)10459f1eda9eSsam mprintr(unit, list)
1046b092cf00Skarels u_char *list;
10479f1eda9eSsam {
10489f1eda9eSsam register struct tty *tp;
10499f1eda9eSsam register struct mpport *mp;
10509f1eda9eSsam register struct mpevent *ev;
10519f1eda9eSsam struct mblok *mb;
10529f1eda9eSsam register int cc;
10539f1eda9eSsam register char *cp;
10549f1eda9eSsam struct mpsoftc *ms;
10559f1eda9eSsam caddr_t ptr;
10569f1eda9eSsam char *rcverr;
10579f1eda9eSsam int port, i;
10589f1eda9eSsam
10599f1eda9eSsam ms = &mp_softc[unit];
10609f1eda9eSsam mb = mp_softc[unit].ms_mb;
10619f1eda9eSsam for (i = 0; i < MPMAXPORT && (port = *list++) != MPPORT_EOL; i++) {
10629f1eda9eSsam tp = &mp_tty[unit*MPCHUNK + port];
10639f1eda9eSsam mp = &mb->mb_port[port];
10649f1eda9eSsam ev = &mp->mp_sendq[mp->mp_nextrcv];
10659f1eda9eSsam while (ev->ev_status & EVSTATUS_DONE) {
10667c9a9841Sbostic switch(ev->ev_cmd) {
10677c9a9841Sbostic case EVCMD_STATUS:
10689f1eda9eSsam /*
10699f1eda9eSsam * Status change, look for carrier changes.
10709f1eda9eSsam */
10717c9a9841Sbostic switch(ev->ev_opts) {
10727c9a9841Sbostic case DCDASRT:
10737c9a9841Sbostic (*linesw[tp->t_line].l_modem)(tp, 1);
10747c9a9841Sbostic wakeup((caddr_t)&tp->t_canq);
10757c9a9841Sbostic break;
10767c9a9841Sbostic case DCDDROP:
10777c9a9841Sbostic (*linesw[tp->t_line].l_modem)(tp, 0);
10787c9a9841Sbostic wakeup((caddr_t)&tp->t_canq);
10797c9a9841Sbostic break;
10807c9a9841Sbostic case NORBUF:
10817c9a9841Sbostic case NOEBUF:
10827c9a9841Sbostic mplog(unit, port,
10837c9a9841Sbostic "out of receive events", 0);
10847c9a9841Sbostic break;
10857c9a9841Sbostic default:
10869f1eda9eSsam mplog(unit, port,
10879f1eda9eSsam "unexpect status command",
1088b092cf00Skarels (int)ev->ev_opts);
10897c9a9841Sbostic break;
10909f1eda9eSsam }
10917c9a9841Sbostic break;
10927c9a9841Sbostic case EVCMD_READ:
10939f1eda9eSsam /*
10949f1eda9eSsam * Process received data.
10959f1eda9eSsam */
10967c9a9841Sbostic if ((tp->t_state & TS_ISOPEN) == 0) {
10977c9a9841Sbostic wakeup((caddr_t)&tp->t_rawq);
10987c9a9841Sbostic break;
10997c9a9841Sbostic }
11007c9a9841Sbostic if ((cc = ev->ev_count) == 0)
11017c9a9841Sbostic break;
11029f1eda9eSsam cp = ms->ms_cbuf[port][mp->mp_nextrcv];
11039f1eda9eSsam mppurge(cp, CBSIZE);
11049f1eda9eSsam while (cc-- > 0) {
11059f1eda9eSsam /*
11067c9a9841Sbostic * A null character is inserted,
11077c9a9841Sbostic * potentially when a break or framing
11087c9a9841Sbostic * error occurs. If we're not in raw
11097c9a9841Sbostic * mode, substitute the interrupt
11107c9a9841Sbostic * character.
11119f1eda9eSsam */
1112ea54ad41Smarc /*** XXX - FIXUP ***/
11139f1eda9eSsam if (*cp == 0 &&
11149f1eda9eSsam (ev->ev_error == BRKASRT ||
11159f1eda9eSsam ev->ev_error == FRAMERR))
11169f1eda9eSsam if ((tp->t_flags&RAW) == 0)
1117ea54ad41Smarc ;
1118ea54ad41Smarc /* XXX was break */
11199f1eda9eSsam (*linesw[tp->t_line].l_rint)(*cp++, tp);
11209f1eda9eSsam }
11219f1eda9eSsam /* setup for next read */
11229f1eda9eSsam ptr = (caddr_t)&mp_softc[unit].ms_cbuf[port][mp->mp_nextrcv][0];
1123b092cf00Skarels ev->ev_un.rcvblk = (u_char *)kvtophys(ptr);
1124b092cf00Skarels ev->ev_params = (caddr_t) kvtophys(ptr);
11259f1eda9eSsam switch(ev->ev_error) {
11267c9a9841Sbostic case RCVDTA:
11277c9a9841Sbostic /* Normal (good) rcv data do not
11287c9a9841Sbostic * report the following they are
11297c9a9841Sbostic * "normal" errors
11307c9a9841Sbostic */
11317c9a9841Sbostic case FRAMERR:
11327c9a9841Sbostic /* frame error */
11337c9a9841Sbostic case BRKASRT:
11347c9a9841Sbostic /* Break condition */
11357c9a9841Sbostic case PARERR:
11367c9a9841Sbostic /* parity error */
1137a5db3554Sbostic rcverr = (char *)0;
11389f1eda9eSsam break;
11397c9a9841Sbostic case OVRNERR:
11407c9a9841Sbostic /* Overrun error */
11419f1eda9eSsam rcverr = "overrun error";
11429f1eda9eSsam break;
11437c9a9841Sbostic case OVFERR:
11447c9a9841Sbostic /* Overflow error */
11459f1eda9eSsam rcverr = "overflow error";
11469f1eda9eSsam break;
11479f1eda9eSsam default:
11489f1eda9eSsam rcverr = "undefined rcv error";
11497c9a9841Sbostic break;
11509f1eda9eSsam }
11519f1eda9eSsam if (rcverr != (char *)0)
11527c9a9841Sbostic mplog(unit, port, rcverr,
11537c9a9841Sbostic (int)ev->ev_error);
11547c9a9841Sbostic break;
11557c9a9841Sbostic default:
11567c9a9841Sbostic mplog(unit, port, "unexpected command",
11577c9a9841Sbostic (int)ev->ev_cmd);
11587c9a9841Sbostic break;
11597c9a9841Sbostic }
11609f1eda9eSsam ev->ev_cmd = 0;
11619f1eda9eSsam ev->ev_opts = 0;
11629f1eda9eSsam ev->ev_error = 0;
11639f1eda9eSsam ev->ev_flags = 0;
11647c9a9841Sbostic ev->ev_count = 0;
11659f1eda9eSsam ev->ev_status = EVSTATUS_GO; /* start next read */
11669f1eda9eSsam adjptr(mp->mp_nextrcv, MPOUTSET);
11679f1eda9eSsam ev = &mp->mp_sendq[mp->mp_nextrcv];
11689f1eda9eSsam }
11699f1eda9eSsam }
11709f1eda9eSsam }
11719f1eda9eSsam
11729f1eda9eSsam /*
11739f1eda9eSsam * Log an mpcc diagnostic.
11749f1eda9eSsam */
mplog(unit,port,cp,flags)11759f1eda9eSsam mplog(unit, port, cp, flags)
11769f1eda9eSsam char *cp;
11779f1eda9eSsam {
11789f1eda9eSsam
11799f1eda9eSsam if (flags)
11809f1eda9eSsam log(LOG_ERR, "mp%d: port%d, %s (%d)\n",
11819f1eda9eSsam unit, port, cp, flags);
11829f1eda9eSsam else
11839f1eda9eSsam log(LOG_ERR, "mp%d: port%d, %s\n", unit, port, cp);
11849f1eda9eSsam }
11859f1eda9eSsam
11869f1eda9eSsam int MPHOSTINT = 1;
11879f1eda9eSsam
mptimeint(mb)11889f1eda9eSsam mptimeint(mb)
11899f1eda9eSsam register struct mblok *mb;
11909f1eda9eSsam {
11919f1eda9eSsam
11929f1eda9eSsam mb->mb_mpintcnt = 0;
11939f1eda9eSsam mb->mb_mpintclk = (caddr_t)0;
11949f1eda9eSsam *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2;
11959f1eda9eSsam }
11969f1eda9eSsam
11979f1eda9eSsam /*
11989f1eda9eSsam * Interupt mpcc
11999f1eda9eSsam */
mpintmpcc(mb,port)12009f1eda9eSsam mpintmpcc(mb, port)
12019f1eda9eSsam register struct mblok *mb;
12029f1eda9eSsam {
12039f1eda9eSsam
12049f1eda9eSsam mb->mb_intr[port] |= MPSEMA_WORK;
12059f1eda9eSsam if (++mb->mb_mpintcnt == MPHOSTINT) {
12069f1eda9eSsam mb->mb_mpintcnt = 0;
12079f1eda9eSsam *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2;
12089f1eda9eSsam if (mb->mb_mpintclk) {
1209b092cf00Skarels untimeout(mptimeint, (caddr_t)mb);
12109f1eda9eSsam mb->mb_mpintclk = 0;
12119f1eda9eSsam }
12129f1eda9eSsam } else {
12139f1eda9eSsam if (mb->mb_mpintclk == 0) {
1214b092cf00Skarels timeout(mptimeint, (caddr_t)mb, 4);
12159f1eda9eSsam mb->mb_mpintclk = (caddr_t)1;
12169f1eda9eSsam }
12179f1eda9eSsam }
12189f1eda9eSsam }
12199f1eda9eSsam
12209f1eda9eSsam static char *mpherrmsg[] = {
12219f1eda9eSsam "",
12229f1eda9eSsam "Bus error", /* MPBUSERR */
12239f1eda9eSsam "Address error", /* ADDRERR */
12249f1eda9eSsam "Undefined ecc interrupt", /* UNDECC */
12259f1eda9eSsam "Undefined interrupt", /* UNDINT */
12269f1eda9eSsam "Power failure occurred", /* PWRFL */
12279f1eda9eSsam "Stray transmit done interrupt", /* NOXENTRY */
12289f1eda9eSsam "Two fast timers on one port", /* TWOFTMRS */
12299f1eda9eSsam "Interrupt queue full", /* INTQFULL */
12309f1eda9eSsam "Interrupt queue ack error", /* INTQERR */
12319f1eda9eSsam "Uncorrectable dma parity error", /* CBPERR */
12329f1eda9eSsam "32 port ACAP failed power up", /* ACPDEAD */
12339f1eda9eSsam };
12349f1eda9eSsam #define NHERRS (sizeof (mpherrmsg) / sizeof (mpherrmsg[0]))
12359f1eda9eSsam
mperror(mb,unit)12369f1eda9eSsam mperror(mb, unit)
12379f1eda9eSsam register struct mblok *mb;
12389f1eda9eSsam int unit;
12399f1eda9eSsam {
12409f1eda9eSsam register char *cp;
12419f1eda9eSsam register int i;
12429f1eda9eSsam
12439f1eda9eSsam if (mb->mb_softerr) {
12449f1eda9eSsam switch (mb->mb_softerr) {
12459f1eda9eSsam case DMAPERR: /* dma parity error */
12469f1eda9eSsam cp = "dma parity error";
12479f1eda9eSsam break;
12489f1eda9eSsam case ECCERR:
12499f1eda9eSsam cp = "local memory ecc error";
12509f1eda9eSsam break;
12519f1eda9eSsam default:
12529f1eda9eSsam cp = "unknown error";
12539f1eda9eSsam break;
12549f1eda9eSsam }
12559f1eda9eSsam log(LOG_ERR, "mp%d: soft error, %s", unit, cp);
12569f1eda9eSsam mb->mb_softerr = 0;
12579f1eda9eSsam }
12589f1eda9eSsam if (mb->mb_harderr) {
12599f1eda9eSsam if (mb->mb_harderr < NHERRS)
12609f1eda9eSsam cp = mpherrmsg[mb->mb_harderr];
12619f1eda9eSsam else
12629f1eda9eSsam cp = "unknown error";
12639f1eda9eSsam log(LOG_ERR, "mp%d: hard error, %s", unit, cp);
12649f1eda9eSsam if (mb->mb_status == MP_OPOPEN) {
12659f1eda9eSsam for (i = 0; i < MPMAXPORT; i++) {
12669f1eda9eSsam mpcleanport(mb, i);
12679f1eda9eSsam mb->mb_proto[i] = MPPROTO_UNUSED;
12689f1eda9eSsam }
12699f1eda9eSsam }
12709f1eda9eSsam mb->mb_harderr = 0;
12719f1eda9eSsam mb->mb_status = 0;
12729f1eda9eSsam }
12739f1eda9eSsam }
12749f1eda9eSsam
mppurge(addr,cc)12759f1eda9eSsam mppurge(addr, cc)
12769f1eda9eSsam register caddr_t addr;
12779f1eda9eSsam register int cc;
12789f1eda9eSsam {
12799f1eda9eSsam
12809f1eda9eSsam for (; cc >= 0; addr += NBPG, cc -= NBPG)
12819f1eda9eSsam mtpr(P1DC, addr);
12829f1eda9eSsam }
12839f1eda9eSsam
12849f1eda9eSsam /*
12859f1eda9eSsam * MPCC Download Pseudo-device.
12869f1eda9eSsam */
12879f1eda9eSsam char mpdlbuf[MPDLBUFSIZE];
12889f1eda9eSsam int mpdlbusy; /* interlock on download buffer */
12899f1eda9eSsam int mpdlerr;
12909f1eda9eSsam
mpdlopen(dev)12919f1eda9eSsam mpdlopen(dev)
12929f1eda9eSsam dev_t dev;
12939f1eda9eSsam {
12949f1eda9eSsam int unit, mpu;
12959f1eda9eSsam struct vba_device *vi;
12969f1eda9eSsam
12979f1eda9eSsam unit = minor(dev);
12989f1eda9eSsam mpu = MPUNIT(unit);
12999f1eda9eSsam if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0)
13009f1eda9eSsam return (ENODEV);
13019f1eda9eSsam return (0);
13029f1eda9eSsam }
13039f1eda9eSsam
mpdlwrite(dev,uio)13049f1eda9eSsam mpdlwrite(dev, uio)
13059f1eda9eSsam dev_t dev;
13069f1eda9eSsam struct uio *uio;
13079f1eda9eSsam {
13089f1eda9eSsam register struct mpsoftc *ms = &mp_softc[MPUNIT(minor(dev))];
13099f1eda9eSsam register struct mpdl *dl;
13109f1eda9eSsam int error;
13119f1eda9eSsam
13129f1eda9eSsam if (ms->ms_mb == 0 || ms->ms_mb->mb_status != MP_DLOPEN)
13139f1eda9eSsam return (EFAULT);
13149f1eda9eSsam dl = &ms->ms_mb->mb_dl;
13159f1eda9eSsam dl->mpdl_count = uio->uio_iov->iov_len;
1316b092cf00Skarels dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf);
1317f569d90eSmckusick if (error = uiomove(mpdlbuf, (int)dl->mpdl_count, uio))
13189f1eda9eSsam return (error);
13199f1eda9eSsam uio->uio_resid -= dl->mpdl_count; /* set up return from write */
13209f1eda9eSsam dl->mpdl_cmd = MPDLCMD_NORMAL;
13219f1eda9eSsam error = mpdlwait(dl);
13229f1eda9eSsam return (error);
13239f1eda9eSsam }
13249f1eda9eSsam
mpdlclose(dev)13259f1eda9eSsam mpdlclose(dev)
13269f1eda9eSsam dev_t dev;
13279f1eda9eSsam {
13289f1eda9eSsam register struct mblok *mb = mp_softc[MPUNIT(minor(dev))].ms_mb;
13299f1eda9eSsam
13309f1eda9eSsam if (mb == 0 || mb->mb_status != MP_DLDONE) {
13319f1eda9eSsam mpbogus.status = 0;
13329f1eda9eSsam if (mpbogus.mb == mpbogus.mbloks[MPUNIT(minor(dev))])
13339f1eda9eSsam mpdlbusy--;
13349f1eda9eSsam return (EEXIST);
13359f1eda9eSsam }
13369f1eda9eSsam mb->mb_status = MP_OPOPEN;
13379f1eda9eSsam mpbogus.status = 0;
13389f1eda9eSsam /* set to dead, for board handshake */
13399f1eda9eSsam mb->mb_hostint.imok = MPIMOK_DEAD;
13409f1eda9eSsam return (0);
13419f1eda9eSsam }
13429f1eda9eSsam
1343b092cf00Skarels /* ARGSUSED */
mpdlioctl(dev,cmd,data,flag)13449f1eda9eSsam mpdlioctl(dev, cmd, data, flag)
13459f1eda9eSsam dev_t dev;
13469f1eda9eSsam caddr_t data;
13479f1eda9eSsam {
13489f1eda9eSsam register struct mblok *mb;
13499f1eda9eSsam register struct mpdl *dl;
1350da918786Skarels int unit, error = 0, s, i;
13519f1eda9eSsam
13529f1eda9eSsam mb = mp_softc[unit=MPUNIT(minor(dev))].ms_mb;
13539f1eda9eSsam if (mb == 0)
13549f1eda9eSsam return (EEXIST);
13559f1eda9eSsam dl = &mb->mb_dl;
13569f1eda9eSsam error = 0;
13579f1eda9eSsam switch (cmd) {
13589f1eda9eSsam case MPIOPORTMAP:
13599f1eda9eSsam bcopy(data, (caddr_t)mb->mb_proto, sizeof (mb->mb_proto));
13609f1eda9eSsam break;
13619f1eda9eSsam case MPIOHILO:
13629f1eda9eSsam bcopy(data, (caddr_t)&mb->mb_hiport, 2*(sizeof(mb->mb_hiport)));
13639f1eda9eSsam break;
13649f1eda9eSsam case MPIOENDDL:
13659f1eda9eSsam dl->mpdl_count = 0;
13669f1eda9eSsam dl->mpdl_data = 0;
13679f1eda9eSsam dl->mpdl_cmd = MPIOENDDL&IOCPARM_MASK;
13689f1eda9eSsam error = mpdlwait(dl);
13699f1eda9eSsam mpccinit(unit);
13709f1eda9eSsam mb->mb_status = MP_DLDONE;
13719f1eda9eSsam mpdlbusy--;
13729f1eda9eSsam break;
13739f1eda9eSsam case MPIOENDCODE:
13749f1eda9eSsam dl->mpdl_count = 0;
13759f1eda9eSsam dl->mpdl_data = 0;
13769f1eda9eSsam dl->mpdl_cmd = MPIOENDCODE&IOCPARM_MASK;
13779f1eda9eSsam error = mpdlwait(dl);
13789f1eda9eSsam break;
13799f1eda9eSsam case MPIOASYNCNF:
13809f1eda9eSsam bcopy(data, mpdlbuf, sizeof (struct abdcf));
1381b092cf00Skarels dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf);
13829f1eda9eSsam dl->mpdl_count = sizeof (struct abdcf);
13839f1eda9eSsam dl->mpdl_cmd = MPIOASYNCNF&IOCPARM_MASK;
13849f1eda9eSsam error = mpdlwait(dl);
13859f1eda9eSsam break;
13869f1eda9eSsam case MPIOSTARTDL:
1387da918786Skarels s = spl8();
13889f1eda9eSsam while (mpdlbusy)
1389da918786Skarels if (error = tsleep((caddr_t)&mpdlbusy,
1390da918786Skarels (PZERO+1) | PCATCH, devioc, 0))
1391da918786Skarels break;
1392da918786Skarels splx(s);
1393da918786Skarels if (error)
1394da918786Skarels break;
13959f1eda9eSsam mpdlbusy++;
13969f1eda9eSsam /* initialize the downloading interface */
13979f1eda9eSsam mpbogus.magic = MPMAGIC;
13989f1eda9eSsam mpbogus.mb = mpbogus.mbloks[unit];
13999f1eda9eSsam mpbogus.status = 1;
14009f1eda9eSsam dl->mpdl_status = EVSTATUS_FREE;
14019f1eda9eSsam dl->mpdl_count = 0;
14029f1eda9eSsam dl->mpdl_cmd = 0;
14039f1eda9eSsam dl->mpdl_data = (char *) 0;
14049f1eda9eSsam mpdlerr = 0;
14059f1eda9eSsam mb->mb_magic = MPMAGIC;
14069f1eda9eSsam mb->mb_ivec = mp_softc[unit].ms_ivec+1; /* download vector */
14079f1eda9eSsam mb->mb_status = MP_DLPEND;
14089f1eda9eSsam mb->mb_diagswitch[0] = 'A';
14099f1eda9eSsam mb->mb_diagswitch[1] = 'P';
14109f1eda9eSsam s = spl8();
14119f1eda9eSsam *(u_short *)mpinfo[unit]->ui_addr = 2;
1412da918786Skarels error = tsleep((caddr_t)&mb->mb_status, (PZERO+1) | PCATCH,
1413da918786Skarels devio, 30*hz);
14149f1eda9eSsam splx(s);
1415da918786Skarels if (error == EWOULDBLOCK)
14169f1eda9eSsam error = ETIMEDOUT;
1417da918786Skarels if (error)
14189f1eda9eSsam mpbogus.status = 0;
1419b092cf00Skarels bzero((caddr_t)mb->mb_port, sizeof (mb->mb_port));
14209f1eda9eSsam break;
14219f1eda9eSsam case MPIORESETBOARD:
14229f1eda9eSsam s = spl8();
14239f1eda9eSsam if (mb->mb_imokclk)
14249f1eda9eSsam mb->mb_imokclk = 0;
14259f1eda9eSsam *(u_short *)mpinfo[unit]->ui_addr = 0x100;
14269f1eda9eSsam if (mb->mb_status == MP_DLOPEN || mb->mb_status == MP_DLDONE) {
14279f1eda9eSsam mpdlerr = MP_DLERROR;
14289f1eda9eSsam dl->mpdl_status = EVSTATUS_FREE;
14299f1eda9eSsam wakeup((caddr_t)&dl->mpdl_status);
14309f1eda9eSsam mpbogus.status = 0;
14319f1eda9eSsam }
14329f1eda9eSsam for (i = 0; i < MPMAXPORT; i++) {
14339f1eda9eSsam if (mb->mb_harderr || mb->mb_softerr)
14349f1eda9eSsam mperror(mb, i);
14359f1eda9eSsam mpcleanport(mb, i);
14369f1eda9eSsam mb->mb_proto[i] = MPPROTO_UNUSED;
14379f1eda9eSsam }
14389f1eda9eSsam mb->mb_status = 0;
14399f1eda9eSsam splx(s);
14409f1eda9eSsam break;
14419f1eda9eSsam default:
14429f1eda9eSsam error = EINVAL;
14439f1eda9eSsam break;
14449f1eda9eSsam }
14459f1eda9eSsam return (error);
14469f1eda9eSsam }
14479f1eda9eSsam
mpccinit(unit)14489f1eda9eSsam mpccinit(unit)
14499f1eda9eSsam int unit;
14509f1eda9eSsam {
14519f1eda9eSsam register struct mblok *mb = mp_softc[unit].ms_mb;
14529f1eda9eSsam register struct his *his;
14539f1eda9eSsam register int i, j;
14549f1eda9eSsam
14559f1eda9eSsam mb->mb_status = MP_DLDONE;
14569f1eda9eSsam mb->mb_ivec = mp_softc[unit].ms_ivec;
14579f1eda9eSsam mb->mb_magic = MPMAGIC;
14589f1eda9eSsam /* Init host interface structure */
14599f1eda9eSsam his = &mb->mb_hostint;
14609f1eda9eSsam his->semaphore = MPSEMA_AVAILABLE;
14619f1eda9eSsam for (i = 0; i < NMPPROTO; i++)
14629f1eda9eSsam for (j = 0; j < MPMAXPORT; j++) {
14639f1eda9eSsam his->proto[i].inbdone[j] = MPPORT_EOL;
14649f1eda9eSsam his->proto[i].outbdone[j] = MPPORT_EOL;
14659f1eda9eSsam }
14669f1eda9eSsam mb->mb_unit = unit;
14679f1eda9eSsam }
14689f1eda9eSsam
mpdlintr(mpcc)14699f1eda9eSsam mpdlintr(mpcc)
14709f1eda9eSsam int mpcc;
14719f1eda9eSsam {
14729f1eda9eSsam register struct mblok *mb;
14739f1eda9eSsam register struct mpdl *dl;
14749f1eda9eSsam
14759f1eda9eSsam mb = mp_softc[mpcc].ms_mb;
14769f1eda9eSsam if (mb == 0) {
14779f1eda9eSsam printf("mp%d: stray download interrupt\n", mpcc);
14789f1eda9eSsam return;
14799f1eda9eSsam }
14809f1eda9eSsam dl = &mb->mb_dl;
14819f1eda9eSsam switch (mb->mb_status) {
14829f1eda9eSsam case MP_DLOPEN:
14839f1eda9eSsam if (dl->mpdl_status != EVSTATUS_DONE)
14849f1eda9eSsam mpdlerr = MP_DLERROR;
14859f1eda9eSsam dl->mpdl_status = EVSTATUS_FREE;
14869f1eda9eSsam wakeup((caddr_t)&dl->mpdl_status);
14879f1eda9eSsam return;
14889f1eda9eSsam case MP_DLPEND:
14899f1eda9eSsam mb->mb_status = MP_DLOPEN;
1490b092cf00Skarels wakeup((caddr_t)&mb->mb_status);
14919f1eda9eSsam /* fall thru... */
14929f1eda9eSsam case MP_DLTIME:
14939f1eda9eSsam return;
14949f1eda9eSsam case MP_OPOPEN:
14959f1eda9eSsam if (mb->mb_imokclk)
14969f1eda9eSsam mb->mb_imokclk = 0;
14979f1eda9eSsam mb->mb_nointcnt = 0; /* reset no interrupt count */
14989f1eda9eSsam mb->mb_hostint.imok = MPIMOK_DEAD;
14999f1eda9eSsam mb->mb_imokclk = (caddr_t)1;
15009f1eda9eSsam break;
15019f1eda9eSsam default:
15029f1eda9eSsam log(LOG_ERR, "mp%d: mpdlintr, status %x\n",
15039f1eda9eSsam mpcc, mb->mb_status);
15049f1eda9eSsam break;
15059f1eda9eSsam }
15069f1eda9eSsam }
15079f1eda9eSsam
15089f1eda9eSsam /*
15099f1eda9eSsam * Wait for a transfer to complete or a timeout to occur.
15109f1eda9eSsam */
mpdlwait(dl)15119f1eda9eSsam mpdlwait(dl)
15129f1eda9eSsam register struct mpdl *dl;
15139f1eda9eSsam {
15149f1eda9eSsam int s, error = 0;
15159f1eda9eSsam
15169f1eda9eSsam s = spl8();
15179f1eda9eSsam dl->mpdl_status = EVSTATUS_GO;
15189f1eda9eSsam while (dl->mpdl_status != EVSTATUS_FREE) {
1519da918786Skarels error = tsleep((caddr_t)&dl->mpdl_status, (PZERO+1) | PCATCH,
1520da918786Skarels devout, 0);
15219f1eda9eSsam if (mpdlerr == MP_DLERROR)
15229f1eda9eSsam error = EIO;
1523da918786Skarels if (error)
1524da918786Skarels break;
15259f1eda9eSsam }
15269f1eda9eSsam splx(s);
15279f1eda9eSsam return (error);
15289f1eda9eSsam }
15299f1eda9eSsam #endif
1530