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