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: * @(#)dz.c 7.1 (Berkeley) 6/5/86 7: */ 8: 9: #include "dz.h" 10: #if NDZ > 0 11: /* 12: * DZ-11/DZ-32 Driver 13: * 14: * This driver mimics dh.c; see it for explanation of common code. 15: */ 16: #include "bk.h" 17: 18: #include "../machine/pte.h" 19: 20: #include "param.h" 21: #include "systm.h" 22: #include "ioctl.h" 23: #include "tty.h" 24: #include "dir.h" 25: #include "user.h" 26: #include "proc.h" 27: #include "map.h" 28: #include "buf.h" 29: #include "vm.h" 30: #include "conf.h" 31: #include "bkmac.h" 32: #include "file.h" 33: #include "uio.h" 34: #include "kernel.h" 35: #include "syslog.h" 36: 37: #include "pdma.h" 38: #include "ubavar.h" 39: #include "dzreg.h" 40: 41: /* 42: * Driver information for auto-configuration stuff. 43: */ 44: int dzprobe(), dzattach(), dzrint(); 45: struct uba_device *dzinfo[NDZ]; 46: u_short dzstd[] = { 0 }; 47: struct uba_driver dzdriver = 48: { dzprobe, 0, dzattach, 0, dzstd, "dz", dzinfo }; 49: 50: #define NDZLINE (NDZ*8) 51: #define FASTTIMER (hz/30) /* rate to drain silos, when in use */ 52: 53: int dzstart(), dzxint(), dzdma(); 54: int ttrstrt(); 55: struct tty dz_tty[NDZLINE]; 56: int dz_cnt = { NDZLINE }; 57: int dzact; 58: int dzsilos; /* mask of dz's with silo in use */ 59: int dzchars[NDZ]; /* recent input count */ 60: int dzrate[NDZ]; /* smoothed input count */ 61: int dztimerintvl; /* time interval for dztimer */ 62: int dzhighrate = 100; /* silo on if dzchars > dzhighrate */ 63: int dzlowrate = 75; /* silo off if dzrate < dzlowrate */ 64: 65: #define dzwait(x) while (((x)->dzlcs & DZ_ACK) == 0) 66: 67: /* 68: * Software copy of dzbrk since it isn't readable 69: */ 70: char dz_brk[NDZ]; 71: char dzsoftCAR[NDZ]; 72: char dz_lnen[NDZ]; /* saved line enable bits for DZ32 */ 73: 74: /* 75: * The dz11 doesn't interrupt on carrier transitions, so 76: * we have to use a timer to watch it. 77: */ 78: char dz_timer; /* timer started? */ 79: 80: /* 81: * Pdma structures for fast output code 82: */ 83: struct pdma dzpdma[NDZLINE]; 84: 85: char dz_speeds[] = 86: { 0,020,021,022,023,024,0,025,026,027,030,032,034,036,037,0 }; 87: 88: #ifndef PORTSELECTOR 89: #define ISPEED B9600 90: #define IFLAGS (EVENP|ODDP|ECHO) 91: #else 92: #define ISPEED B4800 93: #define IFLAGS (EVENP|ODDP) 94: #endif 95: 96: dzprobe(reg) 97: caddr_t reg; 98: { 99: register int br, cvec; 100: register struct dzdevice *dzaddr = (struct dzdevice *)reg; 101: 102: #ifdef lint 103: br = 0; cvec = br; br = cvec; 104: dzrint(0); dzxint((struct tty *)0); 105: #endif 106: dzaddr->dzcsr = DZ_TIE|DZ_MSE|DZ_32; 107: if (dzaddr->dzcsr & DZ_32) 108: dzaddr->dzlnen = 1; 109: else 110: dzaddr->dztcr = 1; /* enable any line */ 111: DELAY(100000); 112: dzaddr->dzcsr = DZ_CLR|DZ_32; /* reset everything */ 113: if (cvec && cvec != 0x200) 114: cvec -= 4; 115: return (sizeof (struct dzdevice)); 116: } 117: 118: dzattach(ui) 119: register struct uba_device *ui; 120: { 121: register struct pdma *pdp = &dzpdma[ui->ui_unit*8]; 122: register struct tty *tp = &dz_tty[ui->ui_unit*8]; 123: register int cntr; 124: extern dzscan(); 125: 126: for (cntr = 0; cntr < 8; cntr++) { 127: pdp->p_addr = (struct dzdevice *)ui->ui_addr; 128: pdp->p_arg = (int)tp; 129: pdp->p_fcn = dzxint; 130: pdp++, tp++; 131: } 132: dzsoftCAR[ui->ui_unit] = ui->ui_flags; 133: if (dz_timer == 0) { 134: dz_timer++; 135: timeout(dzscan, (caddr_t)0, hz); 136: dztimerintvl = FASTTIMER; 137: } 138: } 139: 140: /*ARGSUSED*/ 141: dzopen(dev, flag) 142: dev_t dev; 143: { 144: register struct tty *tp; 145: register int unit; 146: 147: unit = minor(dev); 148: if (unit >= dz_cnt || dzpdma[unit].p_addr == 0) 149: return (ENXIO); 150: tp = &dz_tty[unit]; 151: tp->t_addr = (caddr_t)&dzpdma[unit]; 152: tp->t_oproc = dzstart; 153: if ((tp->t_state & TS_ISOPEN) == 0) { 154: ttychars(tp); 155: #ifndef PORTSELECTOR 156: if (tp->t_ispeed == 0) { 157: #else 158: tp->t_state |= TS_HUPCLS; 159: #endif PORTSELECTOR 160: tp->t_ispeed = ISPEED; 161: tp->t_ospeed = ISPEED; 162: tp->t_flags = IFLAGS; 163: #ifndef PORTSELECTOR 164: } 165: #endif PORTSELECTOR 166: dzparam(unit); 167: } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 168: return (EBUSY); 169: (void) dzmctl(dev, DZ_ON, DMSET); 170: (void) spl5(); 171: while ((tp->t_state & TS_CARR_ON) == 0) { 172: tp->t_state |= TS_WOPEN; 173: sleep((caddr_t)&tp->t_rawq, TTIPRI); 174: } 175: (void) spl0(); 176: return ((*linesw[tp->t_line].l_open)(dev, tp)); 177: } 178: 179: /*ARGSUSED*/ 180: dzclose(dev, flag) 181: dev_t dev; 182: { 183: register struct tty *tp; 184: register int unit; 185: register struct dzdevice *dzaddr; 186: int dz; 187: 188: unit = minor(dev); 189: dz = unit >> 3; 190: tp = &dz_tty[unit]; 191: (*linesw[tp->t_line].l_close)(tp); 192: dzaddr = dzpdma[unit].p_addr; 193: if (dzaddr->dzcsr&DZ_32) 194: (void) dzmctl(dev, DZ_BRK, DMBIC); 195: else 196: dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07))); 197: if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN) == 0) 198: (void) dzmctl(dev, DZ_OFF, DMSET); 199: ttyclose(tp); 200: } 201: 202: dzread(dev, uio) 203: dev_t dev; 204: struct uio *uio; 205: { 206: register struct tty *tp; 207: 208: tp = &dz_tty[minor(dev)]; 209: return ((*linesw[tp->t_line].l_read)(tp, uio)); 210: } 211: 212: dzwrite(dev, uio) 213: dev_t dev; 214: struct uio *uio; 215: { 216: register struct tty *tp; 217: 218: tp = &dz_tty[minor(dev)]; 219: return ((*linesw[tp->t_line].l_write)(tp, uio)); 220: } 221: 222: /*ARGSUSED*/ 223: dzrint(dz) 224: int dz; 225: { 226: register struct tty *tp; 227: register int c; 228: register struct dzdevice *dzaddr; 229: register struct tty *tp0; 230: register int unit; 231: int overrun = 0; 232: 233: if ((dzact & (1<<dz)) == 0) 234: return; 235: unit = dz * 8; 236: dzaddr = dzpdma[unit].p_addr; 237: tp0 = &dz_tty[unit]; 238: dzaddr->dzcsr &= ~(DZ_RIE|DZ_MIE); /* the manual says this song */ 239: dzaddr->dzcsr |= DZ_RIE|DZ_MIE; /* and dance is necessary */ 240: while (dzaddr->dzcsr & DZ_MSC) { /* DZ32 modem change interrupt */ 241: c = dzaddr->dzmtsr; 242: tp = tp0 + (c&7); 243: if (tp >= &dz_tty[dz_cnt]) 244: break; 245: dzaddr->dzlcs = c&7; /* get status of modem lines */ 246: dzwait(dzaddr); /* wait for them */ 247: if (c & DZ_CD) /* carrier status change? */ 248: if (dzaddr->dzlcs & DZ_CD) { /* carrier up? */ 249: /* carrier present */ 250: (void)(*linesw[tp->t_line].l_modem)(tp, 1); 251: } else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 252: dzaddr->dzlcs = DZ_ACK|(c&7); 253: } 254: while ((c = dzaddr->dzrbuf) < 0) { /* char present */ 255: dzchars[dz]++; 256: tp = tp0 + ((c>>8)&07); 257: if (tp >= &dz_tty[dz_cnt]) 258: continue; 259: if ((tp->t_state & TS_ISOPEN) == 0) { 260: wakeup((caddr_t)&tp->t_rawq); 261: #ifdef PORTSELECTOR 262: if ((tp->t_state&TS_WOPEN) == 0) 263: #endif 264: continue; 265: } 266: if (c&DZ_FE) 267: if (tp->t_flags & RAW) 268: c = 0; 269: else 270: c = tp->t_intrc; 271: if (c&DZ_DO && overrun == 0) { 272: log(LOG_WARNING, "dz%d,%d: silo overflow\n", dz, (c>>8)&7); 273: overrun = 1; 274: } 275: if (c&DZ_PE) 276: if (((tp->t_flags & (EVENP|ODDP)) == EVENP) 277: || ((tp->t_flags & (EVENP|ODDP)) == ODDP)) 278: continue; 279: #if NBK > 0 280: if (tp->t_line == NETLDISC) { 281: c &= 0177; 282: BKINPUT(c, tp); 283: } else 284: #endif 285: (*linesw[tp->t_line].l_rint)(c, tp); 286: } 287: } 288: 289: /*ARGSUSED*/ 290: dzioctl(dev, cmd, data, flag) 291: dev_t dev; 292: caddr_t data; 293: { 294: register struct tty *tp; 295: register int unit = minor(dev); 296: register int dz = unit >> 3; 297: register struct dzdevice *dzaddr; 298: int error; 299: 300: tp = &dz_tty[unit]; 301: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 302: if (error >= 0) 303: return (error); 304: error = ttioctl(tp, cmd, data, flag); 305: if (error >= 0) { 306: if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || 307: cmd == TIOCLBIC || cmd == TIOCLSET) 308: dzparam(unit); 309: return (error); 310: } 311: switch (cmd) { 312: 313: case TIOCSBRK: 314: dzaddr = ((struct pdma *)(tp->t_addr))->p_addr; 315: if (dzaddr->dzcsr&DZ_32) 316: (void) dzmctl(dev, DZ_BRK, DMBIS); 317: else 318: dzaddr->dzbrk = (dz_brk[dz] |= 1 << (unit&07)); 319: break; 320: 321: case TIOCCBRK: 322: dzaddr = ((struct pdma *)(tp->t_addr))->p_addr; 323: if (dzaddr->dzcsr&DZ_32) 324: (void) dzmctl(dev, DZ_BRK, DMBIC); 325: else 326: dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07))); 327: break; 328: 329: case TIOCSDTR: 330: (void) dzmctl(dev, DZ_DTR|DZ_RTS, DMBIS); 331: break; 332: 333: case TIOCCDTR: 334: (void) dzmctl(dev, DZ_DTR|DZ_RTS, DMBIC); 335: break; 336: 337: case TIOCMSET: 338: (void) dzmctl(dev, dmtodz(*(int *)data), DMSET); 339: break; 340: 341: case TIOCMBIS: 342: (void) dzmctl(dev, dmtodz(*(int *)data), DMBIS); 343: break; 344: 345: case TIOCMBIC: 346: (void) dzmctl(dev, dmtodz(*(int *)data), DMBIC); 347: break; 348: 349: case TIOCMGET: 350: *(int *)data = dztodm(dzmctl(dev, 0, DMGET)); 351: break; 352: 353: default: 354: return (ENOTTY); 355: } 356: return (0); 357: } 358: 359: dmtodz(bits) 360: register int bits; 361: { 362: register int b; 363: 364: b = (bits >>1) & 0370; 365: if (bits & DML_ST) b |= DZ_ST; 366: if (bits & DML_RTS) b |= DZ_RTS; 367: if (bits & DML_DTR) b |= DZ_DTR; 368: if (bits & DML_LE) b |= DZ_LE; 369: return(b); 370: } 371: 372: dztodm(bits) 373: register int bits; 374: { 375: register int b; 376: 377: b = (bits << 1) & 0360; 378: if (bits & DZ_DSR) b |= DML_DSR; 379: if (bits & DZ_DTR) b |= DML_DTR; 380: if (bits & DZ_ST) b |= DML_ST; 381: if (bits & DZ_RTS) b |= DML_RTS; 382: return(b); 383: } 384: 385: dzparam(unit) 386: register int unit; 387: { 388: register struct tty *tp; 389: register struct dzdevice *dzaddr; 390: register int lpr; 391: 392: tp = &dz_tty[unit]; 393: dzaddr = dzpdma[unit].p_addr; 394: if (dzsilos & (1 << (unit >> 3))) 395: dzaddr->dzcsr = DZ_IEN | DZ_SAE; 396: else 397: dzaddr->dzcsr = DZ_IEN; 398: dzact |= (1<<(unit>>3)); 399: if (tp->t_ispeed == 0) { 400: (void) dzmctl(unit, DZ_OFF, DMSET); /* hang up line */ 401: return; 402: } 403: lpr = (dz_speeds[tp->t_ispeed]<<8) | (unit & 07); 404: if (tp->t_flags & (RAW|LITOUT|PASS8)) 405: lpr |= BITS8; 406: else 407: lpr |= (BITS7|PENABLE); 408: if ((tp->t_flags & EVENP) == 0) 409: lpr |= OPAR; 410: if (tp->t_ispeed == B110) 411: lpr |= TWOSB; 412: dzaddr->dzlpr = lpr; 413: } 414: 415: dzxint(tp) 416: register struct tty *tp; 417: { 418: register struct pdma *dp; 419: register dz, unit; 420: 421: dp = (struct pdma *)tp->t_addr; 422: tp->t_state &= ~TS_BUSY; 423: if (tp->t_state & TS_FLUSH) 424: tp->t_state &= ~TS_FLUSH; 425: else { 426: ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf); 427: dp->p_end = dp->p_mem = tp->t_outq.c_cf; 428: } 429: if (tp->t_line) 430: (*linesw[tp->t_line].l_start)(tp); 431: else 432: dzstart(tp); 433: dz = minor(tp->t_dev) >> 3; 434: unit = minor(tp->t_dev) & 7; 435: if (tp->t_outq.c_cc == 0 || (tp->t_state&TS_BUSY)==0) 436: if (dp->p_addr->dzcsr & DZ_32) 437: dp->p_addr->dzlnen = (dz_lnen[dz] &= ~(1<<unit)); 438: else 439: dp->p_addr->dztcr &= ~(1<<unit); 440: } 441: 442: dzstart(tp) 443: register struct tty *tp; 444: { 445: register struct pdma *dp; 446: register struct dzdevice *dzaddr; 447: register int cc; 448: int s, dz, unit; 449: 450: dp = (struct pdma *)tp->t_addr; 451: dzaddr = dp->p_addr; 452: s = spl5(); 453: if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 454: goto out; 455: if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 456: if (tp->t_state&TS_ASLEEP) { 457: tp->t_state &= ~TS_ASLEEP; 458: wakeup((caddr_t)&tp->t_outq); 459: } 460: if (tp->t_wsel) { 461: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 462: tp->t_wsel = 0; 463: tp->t_state &= ~TS_WCOLL; 464: } 465: } 466: if (tp->t_outq.c_cc == 0) 467: goto out; 468: if (tp->t_flags & (RAW|LITOUT)) 469: cc = ndqb(&tp->t_outq, 0); 470: else { 471: cc = ndqb(&tp->t_outq, 0200); 472: if (cc == 0) { 473: cc = getc(&tp->t_outq); 474: timeout(ttrstrt, (caddr_t)tp, (cc&0x7f) + 6); 475: tp->t_state |= TS_TIMEOUT; 476: goto out; 477: } 478: } 479: tp->t_state |= TS_BUSY; 480: dp->p_end = dp->p_mem = tp->t_outq.c_cf; 481: dp->p_end += cc; 482: dz = minor(tp->t_dev) >> 3; 483: unit = minor(tp->t_dev) & 7; 484: if (dzaddr->dzcsr & DZ_32) 485: dzaddr->dzlnen = (dz_lnen[dz] |= (1<<unit)); 486: else 487: dzaddr->dztcr |= (1<<unit); 488: out: 489: splx(s); 490: } 491: 492: /* 493: * Stop output on a line. 494: */ 495: /*ARGSUSED*/ 496: dzstop(tp, flag) 497: register struct tty *tp; 498: { 499: register struct pdma *dp; 500: register int s; 501: 502: dp = (struct pdma *)tp->t_addr; 503: s = spl5(); 504: if (tp->t_state & TS_BUSY) { 505: dp->p_end = dp->p_mem; 506: if ((tp->t_state&TS_TTSTOP)==0) 507: tp->t_state |= TS_FLUSH; 508: } 509: splx(s); 510: } 511: 512: dzmctl(dev, bits, how) 513: dev_t dev; 514: int bits, how; 515: { 516: register struct dzdevice *dzaddr; 517: register int unit, mbits; 518: int b, s; 519: 520: unit = minor(dev); 521: b = 1<<(unit&7); 522: dzaddr = dzpdma[unit].p_addr; 523: s = spl5(); 524: if (dzaddr->dzcsr & DZ_32) { 525: dzwait(dzaddr) 526: DELAY(100); /* IS 100 TOO MUCH? */ 527: dzaddr->dzlcs = unit&7; 528: DELAY(100); 529: dzwait(dzaddr) 530: DELAY(100); 531: mbits = dzaddr->dzlcs; 532: mbits &= 0177770; 533: } else { 534: mbits = (dzaddr->dzdtr & b) ? DZ_DTR : 0; 535: mbits |= (dzaddr->dzmsr & b) ? DZ_CD : 0; 536: mbits |= (dzaddr->dztbuf & b) ? DZ_RI : 0; 537: } 538: switch (how) { 539: case DMSET: 540: mbits = bits; 541: break; 542: 543: case DMBIS: 544: mbits |= bits; 545: break; 546: 547: case DMBIC: 548: mbits &= ~bits; 549: break; 550: 551: case DMGET: 552: (void) splx(s); 553: return(mbits); 554: } 555: if (dzaddr->dzcsr & DZ_32) { 556: mbits |= DZ_ACK|(unit&7); 557: dzaddr->dzlcs = mbits; 558: } else { 559: if (mbits & DZ_DTR) 560: dzaddr->dzdtr |= b; 561: else 562: dzaddr->dzdtr &= ~b; 563: } 564: (void) splx(s); 565: return(mbits); 566: } 567: 568: int dztransitions, dzfasttimers; /*DEBUG*/ 569: dzscan() 570: { 571: register i; 572: register struct dzdevice *dzaddr; 573: register bit; 574: register struct tty *tp; 575: register car; 576: int olddzsilos = dzsilos; 577: int dztimer(); 578: 579: for (i = 0; i < dz_cnt ; i++) { 580: dzaddr = dzpdma[i].p_addr; 581: if (dzaddr == 0) 582: continue; 583: tp = &dz_tty[i]; 584: bit = 1<<(i&07); 585: car = 0; 586: if (dzsoftCAR[i>>3]&bit) 587: car = 1; 588: else if (dzaddr->dzcsr & DZ_32) { 589: dzaddr->dzlcs = i&07; 590: dzwait(dzaddr); 591: car = dzaddr->dzlcs & DZ_CD; 592: } else 593: car = dzaddr->dzmsr&bit; 594: if (car) { 595: /* carrier present */ 596: if ((tp->t_state & TS_CARR_ON) == 0) 597: (void)(*linesw[tp->t_line].l_modem)(tp, 1); 598: } else if ((tp->t_state&TS_CARR_ON) && 599: (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 600: dzaddr->dzdtr &= ~bit; 601: } 602: for (i = 0; i < NDZ; i++) { 603: ave(dzrate[i], dzchars[i], 8); 604: if (dzchars[i] > dzhighrate && ((dzsilos & (1 << i)) == 0)) { 605: dzpdma[i << 3].p_addr->dzcsr = DZ_IEN | DZ_SAE; 606: dzsilos |= (1 << i); 607: dztransitions++; /*DEBUG*/ 608: } else if ((dzsilos & (1 << i)) && (dzrate[i] < dzlowrate)) { 609: dzpdma[i << 3].p_addr->dzcsr = DZ_IEN; 610: dzsilos &= ~(1 << i); 611: } 612: dzchars[i] = 0; 613: } 614: if (dzsilos && !olddzsilos) 615: timeout(dztimer, (caddr_t)0, dztimerintvl); 616: timeout(dzscan, (caddr_t)0, hz); 617: } 618: 619: dztimer() 620: { 621: register int dz; 622: register int s; 623: 624: if (dzsilos == 0) 625: return; 626: s = spl5(); 627: dzfasttimers++; /*DEBUG*/ 628: for (dz = 0; dz < NDZ; dz++) 629: if (dzsilos & (1 << dz)) 630: dzrint(dz); 631: splx(s); 632: timeout(dztimer, (caddr_t) 0, dztimerintvl); 633: } 634: 635: /* 636: * Reset state of driver if UBA reset was necessary. 637: * Reset parameters and restart transmission on open lines. 638: */ 639: dzreset(uban) 640: int uban; 641: { 642: register int unit; 643: register struct tty *tp; 644: register struct uba_device *ui; 645: 646: for (unit = 0; unit < NDZLINE; unit++) { 647: ui = dzinfo[unit >> 3]; 648: if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0) 649: continue; 650: if (unit%8 == 0) 651: printf(" dz%d", unit>>3); 652: tp = &dz_tty[unit]; 653: if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 654: dzparam(unit); 655: (void) dzmctl(unit, DZ_ON, DMSET); 656: tp->t_state &= ~TS_BUSY; 657: dzstart(tp); 658: } 659: } 660: } 661: #endif