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