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