|
|
1.1 root 1: /*
2: * Copyright (c) 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Computer Consoles Inc.
7: *
8: * Redistribution and use in source and binary forms are permitted
9: * provided that the above copyright notice and this paragraph are
10: * duplicated in all such forms and that any documentation,
11: * advertising materials, and other materials related to such
12: * distribution and use acknowledge that the software was developed
13: * by the University of California, Berkeley. The name of the
14: * University may not be used to endorse or promote products derived
15: * from this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)mp.c 7.6 (Berkeley) 7/9/88
21: */
22:
23: #include "mp.h"
24: #if NMP > 0
25: /*
26: * Multi Protocol Communications Controller (MPCC).
27: * Asynchronous Terminal Protocol Support.
28: */
29: #include "param.h"
30: #include "ioctl.h"
31: #include "tty.h"
32: #include "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:
45: #include "../machine/pte.h"
46: #include "../machine/mtpr.h"
47:
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: */
58: int mpprobe(), mpattach(), mpintr();
59: struct vba_device *mpinfo[NMP];
60: long mpstd[] = { 0 };
61: struct vba_driver mpdriver =
62: { mpprobe, 0, mpattach, 0, mpstd, "mp", mpinfo };
63:
64: int mpstart();
65: struct mpevent *mpparam();
66: struct 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: */
76: struct 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: */
88: struct 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:
98: struct tty mp_tty[NMP*MPCHUNK];
99: #ifndef lint
100: int nmp = NMP*MPCHUNK;
101: #endif
102:
103: int ttrstrt();
104:
105: mpprobe(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);
115: mpdlintr(0);
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 */
131: return (sizeof (*reg));
132: }
133:
134: mpattach(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: */
153: /* ARGSUSED */
154: mpopen(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);
182: tp->t_state |= TS_WOPEN;
183: tp->t_addr = (caddr_t)ms;
184: tp->t_oproc = mpstart;
185: tp->t_dev = dev;
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);
207: }
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);
211: done:
212: splx(s);
213: /* wakeup anyone waiting for open to complete */
214: wakeup((caddr_t)&tp->t_canq);
215:
216: return (error);
217: bad:
218: tp->t_state &= ~TS_WOPEN;
219: goto done;
220: }
221:
222: /*
223: * Close an mpcc port.
224: */
225: /* ARGSUSED */
226: mpclose(dev, flag)
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();
241: if (mp->mp_flags & MP_PROGRESS) { /* close in progress??? */
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);
253: ev = mp_getevent(mp, unit);
254: if (ev == 0) {
255: error = ENOBUFS;
256: mp->mp_flags &= ~MP_PROGRESS;
257: goto out;
258: }
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);
263: mpcmd(ev, EVCMD_CLOSE, 0, mb, port);
264: ttyclose(tp);
265: out:
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: */
275: mpread(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: */
288: mpwrite(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: */
301: mpioctl(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 ||
322: cmd == TIOCLBIC || cmd == TIOCLSET || cmd == TIOCSETC) {
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:
358: struct mpevent *
359: mpparam(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];
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;
386: asp->ap_xany = ((tp->t_flags & DECCTQ) ? MPA_DIS : MPA_ENA);
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:
419: mpstart(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: }
471: hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf);
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: */
495: ndadvance(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: }
528: out:
529: splx(s);
530: }
531:
532: /*
533: * Stop output on a line, e.g. for ^S/^Q or output flush.
534: */
535: /* ARGSUSED */
536: mpstop(tp, rw)
537: register struct tty *tp;
538: int rw;
539: {
540: int s;
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: */
554: mpportinit(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;
574: ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]);
575: ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]);
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];
587: ev->ev_un.rcvblk = (u_char *)kvtophys(ptr);
588: ev->ev_params = (caddr_t) kvtophys(ptr);
589: }
590: return (0);
591: }
592:
593: /*
594: * Send an event to an mpcc.
595: */
596: mpcmd(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: */
615: struct mpevent *
616: mp_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: */
631: if ((mp->mp_flags & MP_PROGRESS) == 0) {
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);
646: bad:
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:
652: mpmodem(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;
658: register struct asyncparam *asp;
659:
660: mp = &ms->ms_mb->mb_port[port];
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: }
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: */
681: static
682: setm(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: */
704: static
705: seti(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:
720: mpcleanport(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;
730: /* signal loss of carrier and close */
731: tp = &mp_tty[mb->mb_unit*MPCHUNK+port];
732: ttyflush(tp, FREAD|FWRITE);
733: (void) (*linesw[tp->t_line].l_modem)(tp, 0);
734: (void) mpclose(tp->t_dev, 0);
735: }
736: }
737:
738: mpclean(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;
745: u_char list[2];
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: */
784: mpintr(mpcc)
785: int mpcc;
786: {
787: register struct mblok *mb;
788: register struct his *his;
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: */
812: mpxintr(unit, list)
813: register u_char *list;
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];
836: mppurge((caddr_t)ap, (int)sizeof (*ap));
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;
864: wakeup((caddr_t)&tp->t_canq);
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;
877: if (tp->t_state & TS_FLUSH)
878: tp->t_state &= ~TS_FLUSH;
879: else {
880: register int cc = 0, n;
881: struct hxmtl *hxp;
882:
883: hxp = &ms->ms_hxl[port];
884: for(n = 0; n < ev->ev_count; n++)
885: cc += hxp->size[n];
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:
899: mplog(unit, port, A_INVCMD, (int)ev->ev_cmd);
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: }
913: done:
914: ;
915: }
916: }
917:
918: /*
919: * Handler for processing received events.
920: */
921: mprintr(unit, list)
922: u_char *list;
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",
945: (int)ev->ev_cmd);
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",
959: (int)ev->ev_opts);
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];
989: ev->ev_un.rcvblk = (u_char *)kvtophys(ptr);
990: ev->ev_params = (caddr_t) kvtophys(ptr);
991: switch(ev->ev_error) {
992: case RCVDTA: /* Normal (good) rcv data */
993: /* do not report the following */
994: /* they are "normal" errors */
995: case FRAMERR: /* frame error */
996: case BRKASRT: /* Break condition */
997: case PARERR: /* parity error */
998: rcverr = (char *)0;
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)
1010: mplog(unit, port, rcverr, (int)ev->ev_error);
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: */
1026: mplog(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:
1037: int MPHOSTINT = 1;
1038:
1039: mptimeint(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: */
1051: mpintmpcc(mb, port)
1052: register struct mblok *mb;
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) {
1060: untimeout(mptimeint, (caddr_t)mb);
1061: mb->mb_mpintclk = 0;
1062: }
1063: } else {
1064: if (mb->mb_mpintclk == 0) {
1065: timeout(mptimeint, (caddr_t)mb, 4);
1066: mb->mb_mpintclk = (caddr_t)1;
1067: }
1068: }
1069: }
1070:
1071: static 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:
1087: mperror(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:
1126: mppurge(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: */
1138: char mpdlbuf[MPDLBUFSIZE];
1139: int mpdlbusy; /* interlock on download buffer */
1140: int mpdlerr;
1141:
1142: mpdlopen(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:
1155: mpdlwrite(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;
1167: dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf);
1168: if (error = uiomove(mpdlbuf, (int)dl->mpdl_count, UIO_WRITE, uio))
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:
1176: mpdlclose(dev)
1177: dev_t dev;
1178: {
1179: register struct mblok *mb = mp_softc[MPUNIT(minor(dev))].ms_mb;
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:
1194: int mpdltimeout();
1195:
1196: /* ARGSUSED */
1197: mpdlioctl(dev, cmd, data, flag)
1198: dev_t dev;
1199: caddr_t data;
1200: {
1201: register struct mblok *mb;
1202: register struct mpdl *dl;
1203: int unit, error, s, i;
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));
1234: dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf);
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;
1259: timeout(mpdltimeout, (caddr_t)mb, 30*hz);
1260: sleep((caddr_t)&mb->mb_status, PZERO+1);
1261: splx(s);
1262: if (mb->mb_status == MP_DLOPEN) {
1263: untimeout(mpdltimeout, (caddr_t)mb);
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: }
1273: bzero((caddr_t)mb->mb_port, sizeof (mb->mb_port));
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:
1302: mpccinit(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:
1323: mpdlintr(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;
1344: wakeup((caddr_t)&mb->mb_status);
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:
1362: mpdltimeout(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: */
1373: mpdlwait(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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.