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