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