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