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