xref: /original-bsd/sys/tahoe/vba/mp.c (revision 3760269a)
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