|
|
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.