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