|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: * ! 6: * %W% (Berkeley) %G% ! 7: */ ! 8: ! 9: /* ! 10: * Common code for DMF32 and DMZ32 drivers ! 11: */ ! 12: #include "dmf.h" ! 13: #include "dmz.h" ! 14: #if NDMF + NDMZ > 0 ! 15: ! 16: #include "../machine/pte.h" ! 17: ! 18: #include "bk.h" ! 19: #include "uba.h" ! 20: #include "param.h" ! 21: #include "conf.h" ! 22: #include "dir.h" ! 23: #include "user.h" ! 24: #include "proc.h" ! 25: #include "ioctl.h" ! 26: #include "tty.h" ! 27: #include "map.h" ! 28: #include "buf.h" ! 29: #include "vm.h" ! 30: #include "bkmac.h" ! 31: #include "clist.h" ! 32: #include "file.h" ! 33: #include "uio.h" ! 34: #include "kernel.h" ! 35: #include "syslog.h" ! 36: ! 37: #include "dmx.h" ! 38: #include "ubareg.h" ! 39: #include "ubavar.h" ! 40: #include "dmxreg.h" ! 41: #include "dmreg.h" ! 42: ! 43: #ifndef PORTSELECTOR ! 44: #define ISPEED B9600 ! 45: #define IFLAGS (EVENP|ODDP|ECHO) ! 46: #else ! 47: #define ISPEED B4800 ! 48: #define IFLAGS (EVENP|ODDP) ! 49: #endif ! 50: ! 51: #ifndef DMX_TIMEOUT ! 52: #define DMX_TIMEOUT 10 ! 53: #endif ! 54: int dmx_timeout = DMX_TIMEOUT; /* silo timeout, in ms */ ! 55: int dmx_mindma = 4; /* don't dma below this point */ ! 56: ! 57: char dmx_speeds[] = ! 58: { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 }; ! 59: ! 60: /* ! 61: * The clist space is mapped by the drivers onto each UNIBUS. ! 62: * The UBACVT macro converts a clist space address for unibus uban ! 63: * into an I/O space address for the DMA routine. ! 64: */ ! 65: int cbase[NUBA]; /* base address in unibus map */ ! 66: #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) ! 67: ! 68: int ttrstrt(); ! 69: ! 70: /* ! 71: * DMF/DMZ open common code ! 72: */ ! 73: dmxopen(tp, sc) ! 74: register struct tty *tp; ! 75: register struct dmx_softc *sc; ! 76: { ! 77: int s, unit; ! 78: ! 79: s = spltty(); ! 80: if ((sc->dmx_flags & DMX_ACTIVE) == 0) { ! 81: sc->dmx_octet->csr |= DMF_IE; ! 82: sc->dmx_flags |= DMX_ACTIVE; ! 83: sc->dmx_octet->rsp = dmx_timeout; ! 84: } ! 85: splx(s); ! 86: if (tp->t_state & TS_XCLUDE && u.u_uid != 0) ! 87: return (EBUSY); ! 88: /* ! 89: * If this is first open, initialize tty state to default. ! 90: */ ! 91: if ((tp->t_state&TS_ISOPEN) == 0) { ! 92: ttychars(tp); ! 93: #ifndef PORTSELECTOR ! 94: if (tp->t_ispeed == 0) { ! 95: #else ! 96: tp->t_state |= TS_HUPCLS; ! 97: #endif PORTSELECTOR ! 98: tp->t_ispeed = ISPEED; ! 99: tp->t_ospeed = ISPEED; ! 100: tp->t_flags = IFLAGS; ! 101: #ifndef PORTSELECTOR ! 102: } ! 103: #endif PORTSELECTOR ! 104: } ! 105: dmxparam(tp); ! 106: ! 107: unit = minor(tp->t_dev) & 07; ! 108: /* ! 109: * Wait for carrier, then process line discipline specific open. ! 110: */ ! 111: s = spltty(); ! 112: for (;;) { ! 113: if ((dmxmctl(tp, DMF_ON, DMSET) & DMF_CAR) || ! 114: (sc->dmx_softCAR & (1 << unit))) ! 115: tp->t_state |= TS_CARR_ON; ! 116: if (tp->t_state & TS_CARR_ON) ! 117: break; ! 118: tp->t_state |= TS_WOPEN; ! 119: sleep((caddr_t)&tp->t_rawq, TTIPRI); ! 120: } ! 121: splx(s); ! 122: return ((*linesw[tp->t_line].l_open)(tp->t_dev, tp)); ! 123: } ! 124: ! 125: dmxclose(tp) ! 126: register struct tty *tp; ! 127: { ! 128: ! 129: (*linesw[tp->t_line].l_close)(tp); ! 130: (void) dmxmctl(tp, DMF_BRK, DMBIC); ! 131: if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) ! 132: (void) dmxmctl(tp, DMF_OFF, DMSET); ! 133: ttyclose(tp); ! 134: } ! 135: ! 136: dmxrint(sc) ! 137: register struct dmx_softc *sc; ! 138: { ! 139: register c; ! 140: register struct tty *tp; ! 141: register struct dmx_octet *addr; ! 142: int unit; ! 143: int overrun = 0; ! 144: ! 145: addr = (struct dmx_octet *)sc->dmx_octet; ! 146: /* ! 147: * Loop fetching characters from the silo for this ! 148: * octet until there are no more in the silo. ! 149: */ ! 150: while ((c = addr->rbuf) < 0) { ! 151: ! 152: unit = (c >> 8) & 07; ! 153: tp = sc->dmx_tty + unit; ! 154: if (c & DMF_DSC) { ! 155: addr->csr = DMF_IE | DMFIR_RMSTSC | unit; ! 156: if (addr->rmstsc & DMF_CAR) ! 157: (void)(*linesw[tp->t_line].l_modem)(tp, 1); ! 158: else if ((sc->dmx_softCAR & (1 << unit)) == 0 && ! 159: (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { ! 160: addr->csr = DMF_IE | DMFIR_LCR | unit; ! 161: addr->lctms = DMF_ENA; ! 162: } ! 163: continue; ! 164: } ! 165: if ((tp->t_state&TS_ISOPEN) == 0) { ! 166: wakeup((caddr_t)&tp->t_rawq); ! 167: #ifdef PORTSELECTOR ! 168: if ((tp->t_state & TS_WOPEN) == 0) ! 169: #endif ! 170: continue; ! 171: } ! 172: if (c & (DMF_PE|DMF_DO|DMF_FE)) { ! 173: if (c & DMF_PE) ! 174: if ((tp->t_flags & (EVENP|ODDP)) == EVENP ! 175: || (tp->t_flags & (EVENP|ODDP)) == ODDP) ! 176: continue; ! 177: if ((c & DMF_DO) && overrun == 0) { ! 178: log(LOG_WARNING, ! 179: "dm%c%d: silo overflow, line %d\n", ! 180: sc->dmx_type, sc->dmx_unit, ! 181: sc->dmx_unit0 + unit); ! 182: overrun = 1; ! 183: } ! 184: if (c & DMF_FE) ! 185: /* ! 186: * At framing error (break) generate ! 187: * a null (in raw mode, for getty), or an ! 188: * interrupt (in cooked/cbreak mode). ! 189: */ ! 190: if (tp->t_flags & RAW) ! 191: c = 0; ! 192: else ! 193: c = tp->t_intrc; ! 194: } ! 195: (*linesw[tp->t_line].l_rint)(c, tp); ! 196: } ! 197: } ! 198: ! 199: dmxioctl(tp, cmd, data, flag) ! 200: register struct tty *tp; ! 201: caddr_t data; ! 202: { ! 203: int error; ! 204: ! 205: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); ! 206: if (error >= 0) ! 207: return (error); ! 208: error = ttioctl(tp, cmd, data, flag); ! 209: if (error >= 0) { ! 210: if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || ! 211: cmd == TIOCLBIC || cmd == TIOCLSET) ! 212: dmxparam(tp); ! 213: return (error); ! 214: } ! 215: switch (cmd) { ! 216: ! 217: case TIOCSBRK: ! 218: (void) dmxmctl(tp, DMF_BRK, DMBIS); ! 219: break; ! 220: ! 221: case TIOCCBRK: ! 222: (void) dmxmctl(tp, DMF_BRK, DMBIC); ! 223: break; ! 224: ! 225: case TIOCSDTR: ! 226: (void) dmxmctl(tp, DMF_DTR|DMF_RTS, DMBIS); ! 227: break; ! 228: ! 229: case TIOCCDTR: ! 230: (void) dmxmctl(tp, DMF_DTR|DMF_RTS, DMBIC); ! 231: break; ! 232: ! 233: case TIOCMSET: ! 234: (void) dmxmctl(tp, dmtodmx(*(int *)data), DMSET); ! 235: break; ! 236: ! 237: case TIOCMBIS: ! 238: (void) dmxmctl(tp, dmtodmx(*(int *)data), DMBIS); ! 239: break; ! 240: ! 241: case TIOCMBIC: ! 242: (void) dmxmctl(tp, dmtodmx(*(int *)data), DMBIC); ! 243: break; ! 244: ! 245: case TIOCMGET: ! 246: *(int *)data = dmxmctl(tp, 0, DMGET); ! 247: break; ! 248: ! 249: default: ! 250: return (ENOTTY); ! 251: } ! 252: return (0); ! 253: } ! 254: ! 255: /* ! 256: * modem control ! 257: * "bits" are dmf/dmz lcr format; ! 258: * return of DMGET is DM11 format. ! 259: */ ! 260: dmxmctl(tp, bits, how) ! 261: struct tty *tp; ! 262: int bits, how; ! 263: { ! 264: register struct dmx_octet *addr; ! 265: register int unit, mbits, lcr; ! 266: int s; ! 267: ! 268: unit = minor(tp->t_dev) & 07; ! 269: addr = (struct dmx_octet *)(tp->t_addr); ! 270: ! 271: s = spltty(); ! 272: addr->csr = DMF_IE | DMFIR_RMSTSC | unit; ! 273: mbits = addr->rmstsc & 0xff00; ! 274: addr->csr = DMF_IE | DMFIR_LCR | unit; ! 275: lcr = addr->lctms; ! 276: ! 277: switch (how) { ! 278: case DMSET: ! 279: lcr = bits; ! 280: break; ! 281: ! 282: case DMBIS: ! 283: lcr |= bits; ! 284: break; ! 285: ! 286: case DMBIC: ! 287: lcr &= ~bits; ! 288: break; ! 289: ! 290: case DMGET: ! 291: splx(s); ! 292: return (dmxtodm(mbits, lcr)); ! 293: } ! 294: addr->lctms = lcr; ! 295: (void) splx(s); ! 296: return (mbits); ! 297: } ! 298: ! 299: /* ! 300: * Routine to convert modem status from dm to dmf/dmz lctmr format. ! 301: */ ! 302: dmtodmx(bits) ! 303: register int bits; ! 304: { ! 305: register int lcr = DMF_ENA; ! 306: ! 307: if (bits & DML_DTR) ! 308: lcr |= DMF_DTR; ! 309: if (bits & DML_RTS) ! 310: lcr |= DMF_RTS; ! 311: if (bits & DML_ST) ! 312: lcr |= DMF_SRTS; ! 313: if (bits & DML_USR) ! 314: lcr |= DMF_USRW; ! 315: return (lcr); ! 316: } ! 317: ! 318: /* ! 319: * Routine to convert modem status from dmf/dmz receive modem status ! 320: * and line control register to dm format. ! 321: * If dmf/dmz user modem read bit set, set DML_USR. ! 322: */ ! 323: dmxtodm(mstat, lcr) ! 324: register int mstat, lcr; ! 325: { ! 326: ! 327: mstat = ((mstat & (DMF_DSR|DMF_RNG|DMF_CAR|DMF_CTS|DMF_SR)) >> 7) | ! 328: ((mstat & DMF_USRR) >> 1) | DML_LE; ! 329: if (lcr & DMF_DTR) ! 330: mstat |= DML_DTR; ! 331: if (lcr & DMF_SRTS) ! 332: mstat |= DML_ST; ! 333: if (lcr & DMF_RTS) ! 334: mstat |= DML_RTS; ! 335: return (mstat); ! 336: } ! 337: ! 338: ! 339: /* ! 340: * Set parameters from open or ioctl into the hardware registers. ! 341: */ ! 342: dmxparam(tp) ! 343: register struct tty *tp; ! 344: { ! 345: register struct dmx_octet *addr; ! 346: register int lpar, lcr; ! 347: int s, unit; ! 348: ! 349: addr = (struct dmx_octet *)tp->t_addr; ! 350: unit = minor(tp->t_dev) & 07; ! 351: /* ! 352: * Block interrupts so parameters will be set ! 353: * before the line interrupts. ! 354: */ ! 355: s = spltty(); ! 356: addr->csr = unit | DMFIR_LCR | DMF_IE; ! 357: if (tp->t_ispeed == 0) { ! 358: tp->t_state |= TS_HUPCLS; ! 359: (void) dmxmctl(tp, DMF_OFF, DMSET); ! 360: splx(s); ! 361: return; ! 362: } ! 363: lpar = (dmx_speeds[tp->t_ospeed]<<12) | (dmx_speeds[tp->t_ispeed]<<8); ! 364: lcr = DMF_ENA; ! 365: if ((tp->t_ispeed) == B134) ! 366: lpar |= BITS6|PENABLE; ! 367: else if (tp->t_flags & (RAW|LITOUT|PASS8)) ! 368: lpar |= BITS8; ! 369: else { ! 370: lpar |= BITS7|PENABLE; ! 371: /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */ ! 372: } ! 373: if (tp->t_flags&EVENP) ! 374: lpar |= EPAR; ! 375: if ((tp->t_ospeed) == B110) ! 376: lpar |= TWOSB; ! 377: lpar |= (unit&07); ! 378: addr->lpr = lpar; ! 379: addr->lctms = (addr->lctms &~ 0xff) | lcr; ! 380: splx(s); ! 381: } ! 382: ! 383: /* ! 384: * Process a transmit interrupt on an octet. ! 385: */ ! 386: dmxxint(sc) ! 387: register struct dmx_softc *sc; ! 388: { ! 389: register struct tty *tp; ! 390: register struct dmx_octet *addr; ! 391: register int t; ! 392: ! 393: addr = (struct dmx_octet *)sc->dmx_octet; ! 394: while ((t = addr->csr) & DMF_TI) { ! 395: if (t & DMF_NXM) ! 396: /* SHOULD RESTART OR SOMETHING... */ ! 397: printf("dm%c%d: NXM line %d\n", sc->dmx_type, ! 398: sc->dmx_unit, sc->dmx_unit0 + (t >> 8 & 7)); ! 399: t = t >> 8 & 7; ! 400: tp = sc->dmx_tty + t; ! 401: tp->t_state &= ~TS_BUSY; ! 402: if (tp->t_state & TS_FLUSH) ! 403: tp->t_state &= ~TS_FLUSH; ! 404: #define new ! 405: #ifndef new ! 406: else if (sc->dmx_dmacount[t]) { ! 407: short cntr; ! 408: ! 409: /* ! 410: * Do arithmetic in a short to make up ! 411: * for lost 16&17 bits. ! 412: */ ! 413: addr->csr = DMFIR_TBA | DMF_IE | t; ! 414: cntr = addr->tba - ! 415: UBACVT(tp->t_outq.c_cf, sc->dmx_ubanum); ! 416: ndflush(&tp->t_outq, (int)cntr); ! 417: } ! 418: #else ! 419: else if (sc->dmx_dmacount[t]) ! 420: ndflush(&tp->t_outq, sc->dmx_dmacount[t]); ! 421: sc->dmx_dmacount[t] = 0; ! 422: #endif ! 423: (*linesw[tp->t_line].l_start)(tp); ! 424: } ! 425: } ! 426: ! 427: dmxstart(tp, sc) ! 428: register struct tty *tp; ! 429: struct dmx_softc *sc; ! 430: { ! 431: register struct dmx_octet *addr; ! 432: register int unit, nch; ! 433: int s; ! 434: ! 435: unit = minor(tp->t_dev) & 07; ! 436: addr = (struct dmx_octet *)tp->t_addr; ! 437: ! 438: /* ! 439: * Must hold interrupts in following code to prevent ! 440: * state of the tp from changing. ! 441: */ ! 442: s = spltty(); ! 443: /* ! 444: * If it's currently active, or delaying, no need to do anything. ! 445: */ ! 446: if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) ! 447: goto out; ! 448: /* ! 449: * If there are still characters to dma or in the silo, ! 450: * just reenable the transmitter. ! 451: */ ! 452: addr->csr = DMF_IE | DMFIR_TBUF | unit; ! 453: #ifdef new ! 454: if (addr->tsc || sc->dmx_dmacount[unit]) { ! 455: #else ! 456: if (addr->tsc) { ! 457: #endif ! 458: addr->csr = DMF_IE | DMFIR_LCR | unit; ! 459: addr->lctms = addr->lctms | DMF_TE; ! 460: tp->t_state |= TS_BUSY; ! 461: goto out; ! 462: } ! 463: /* ! 464: * If there are sleepers, and output has drained below low ! 465: * water mark, wake up the sleepers. ! 466: */ ! 467: if (tp->t_outq.c_cc <= TTLOWAT(tp)) { ! 468: if (tp->t_state & TS_ASLEEP) { ! 469: tp->t_state &= ~TS_ASLEEP; ! 470: wakeup((caddr_t)&tp->t_outq); ! 471: } ! 472: if (tp->t_wsel) { ! 473: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); ! 474: tp->t_wsel = 0; ! 475: tp->t_state &= ~TS_WCOLL; ! 476: } ! 477: } ! 478: /* ! 479: * Now restart transmission unless the output queue is ! 480: * empty. ! 481: */ ! 482: if (tp->t_outq.c_cc == 0) ! 483: goto out; ! 484: if (tp->t_flags & (RAW|LITOUT)) ! 485: nch = ndqb(&tp->t_outq, 0); ! 486: else { ! 487: if ((nch = ndqb(&tp->t_outq, 0200)) == 0) { ! 488: /* ! 489: * If first thing on queue is a delay process it. ! 490: */ ! 491: nch = getc(&tp->t_outq); ! 492: timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); ! 493: tp->t_state |= TS_TIMEOUT; ! 494: goto out; ! 495: } ! 496: } ! 497: /* ! 498: * If characters to transmit, restart transmission. ! 499: */ ! 500: if (nch >= dmx_mindma) { ! 501: register car; ! 502: ! 503: sc->dmx_dmacount[unit] = nch; ! 504: addr->csr = DMF_IE | DMFIR_LCR | unit; ! 505: addr->lctms = addr->lctms | DMF_TE; ! 506: car = UBACVT(tp->t_outq.c_cf, sc->dmx_ubanum); ! 507: addr->csr = DMF_IE | DMFIR_TBA | unit; ! 508: addr->tba = car; ! 509: addr->tcc = ((car >> 2) & 0xc000) | nch; ! 510: tp->t_state |= TS_BUSY; ! 511: } else if (nch) { ! 512: register char *cp = tp->t_outq.c_cf; ! 513: register int i; ! 514: ! 515: #ifndef new ! 516: sc->dmx_dmacount[unit] = 0; ! 517: #endif ! 518: nch = MIN(nch, DMF_SILOCNT); ! 519: addr->csr = DMF_IE | DMFIR_LCR | unit; ! 520: addr->lctms = addr->lctms | DMF_TE; ! 521: addr->csr = DMF_IE | DMFIR_TBUF | unit; ! 522: for (i = 0; i < nch; i++) ! 523: addr->tbuf = *cp++; ! 524: ndflush(&tp->t_outq, nch); ! 525: tp->t_state |= TS_BUSY; ! 526: } ! 527: out: ! 528: splx(s); ! 529: } ! 530: ! 531: dmxstop(tp, sc, flag) ! 532: register struct tty *tp; ! 533: struct dmx_softc *sc; ! 534: { ! 535: register struct dmx_octet *addr; ! 536: register unit = minor(tp->t_dev) & 7; ! 537: int s; ! 538: ! 539: addr = (struct dmx_octet *)tp->t_addr; ! 540: /* ! 541: * Block input/output interrupts while messing with state. ! 542: */ ! 543: s = spltty(); ! 544: if (flag) { ! 545: addr->csr = DMF_IE | DMFIR_TBUF | unit; ! 546: if (addr->tsc) { ! 547: /* ! 548: * Flush regardless of whether we're transmitting ! 549: * (TS_BUSY), if the silo contains untransmitted ! 550: * characters. ! 551: */ ! 552: addr->csr = DMFIR_LCR | unit | DMF_IE; ! 553: addr->lctms = addr->lctms | DMF_TE | DMF_FLUSH; ! 554: /* this will interrupt so let dmxxint handle the rest */ ! 555: tp->t_state |= TS_FLUSH|TS_BUSY; ! 556: } ! 557: /*#ifdef new*/ ! 558: sc->dmx_dmacount[unit] = 0; ! 559: /*#endif*/ ! 560: } else { ! 561: /* ! 562: * Stop transmission by disabling ! 563: * the transmitter. We'll pick up where we ! 564: * left off by reenabling in dmxstart. ! 565: */ ! 566: addr->csr = DMFIR_LCR | unit | DMF_IE; ! 567: addr->lctms = addr->lctms &~ DMF_TE; ! 568: /* no interrupt here */ ! 569: tp->t_state &= ~TS_BUSY; ! 570: } ! 571: splx(s); ! 572: } ! 573: #endif NDMF + NDMZ
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.