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