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