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