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