1: /* 2: * Copyright (c) 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: * @(#)dh.c 1.5 (2.11BSD GTE) 1997/6/12 7: */ 8: 9: /* 10: * DH11, DM11 device drivers 11: */ 12: 13: #include "dh.h" 14: #if NDH > 0 15: /* 16: * DH-11/DM-11 driver 17: */ 18: #include "param.h" 19: #include "conf.h" 20: #include "user.h" 21: #include "file.h" 22: #include "ioctl.h" 23: #include "tty.h" 24: #include "dhreg.h" 25: #include "dmreg.h" 26: #include "map.h" 27: #include "uba.h" 28: #include "ubavar.h" 29: #include "clist.h" 30: #include "systm.h" 31: #include "vm.h" 32: #include "kernel.h" 33: #include "syslog.h" 34: #include "proc.h" 35: 36: int dhtimer(); 37: struct uba_device dhinfo[NDH]; 38: struct uba_device dminfo[NDH]; 39: 40: #define IFLAGS (EVENP|ODDP|ECHO) 41: 42: /* 43: * Use 2 ticks rather than doing a divide of 'hz' by 30. The old method 44: * would produce a scan rate of 1 tick if the lineclock was 50hz but 2 ticks 45: * if the lineclock was 60hz. 46: */ 47: #define FASTTIMER 2 /* scan rate with silos on */ 48: 49: /* 50: * Local variables for the driver 51: */ 52: short dhsar[NDH]; /* software copy of last bar */ 53: 54: struct tty dh11[NDH*16]; 55: u_int dh_overrun[NDH*16]; /* count of silo overruns, cleared on 56: * close. 57: */ 58: int ndh11 = NDH*16; 59: int dhact; /* mask of active dh's */ 60: int dhsilos; /* mask of dh's with silo in use */ 61: int dhchars[NDH]; /* recent input count */ 62: int dhrate[NDH]; /* smoothed input count */ 63: int dhhighrate = 100; /* silo on if dhchars > dhhighrate */ 64: int dhlowrate = 75; /* silo off if dhrate < dhlowrate */ 65: static short timerstarted; 66: int dhstart(); 67: static int dmtodh(), dhtodm(); 68: 69: #if defined(UCB_CLIST) 70: extern ubadr_t clstaddr; 71: #define cpaddr(x) (clstaddr + (ubadr_t)((x) - (char *)cfree)) 72: #else 73: #define cpaddr(x) (x) 74: #endif 75: 76: #define UNIT(x) (x & 0x3f) 77: #define SOFTCAR 0x80 78: #define HWFLOW 0x40 79: 80: /* 81: * Routine called to attach a dh. 82: */ 83: dhattach(addr, unit) 84: register caddr_t addr; 85: register u_int unit; 86: { 87: register struct uba_device *ui; 88: 89: if (addr && unit < NDH && !dhinfo[unit].ui_addr) { 90: ui = &dhinfo[unit]; 91: ui->ui_unit = unit; 92: ui->ui_addr = addr; 93: ui->ui_alive = 1; 94: return (1); 95: } 96: return (0); 97: } 98: 99: /*ARGSUSED*/ 100: dmattach(addr, unit) 101: register caddr_t addr; 102: register u_int unit; 103: { 104: register struct uba_device *ui; 105: 106: if (addr && unit < NDH && !dminfo[unit].ui_addr) { 107: ui = &dminfo[unit]; 108: ui->ui_unit = unit; 109: ui->ui_addr = addr; 110: ui->ui_alive = 1; 111: return (1); 112: } 113: return (0); 114: } 115: 116: /* 117: * Open a DH11 line. Turn on this dh if this is 118: * the first use of it. 119: */ 120: /*ARGSUSED*/ 121: dhopen(dev, flag) 122: dev_t dev; 123: { 124: register struct tty *tp; 125: register struct dhdevice *addr; 126: register int unit; 127: struct uba_device *ui; 128: int dh, s, error; 129: 130: unit = UNIT(dev); 131: dh = unit >> 4; 132: if (unit >= NDH*16 || (ui = &dhinfo[dh])->ui_alive == 0) 133: return(ENXIO); 134: tp = &dh11[unit]; 135: addr = (struct dhdevice *)ui->ui_addr; 136: tp->t_addr = (caddr_t)addr; 137: tp->t_oproc = dhstart; 138: 139: if (timerstarted == 0) 140: { 141: timerstarted++; 142: timeout(dhtimer, (caddr_t) 0, hz); 143: } 144: if ((dhact&(1<<dh)) == 0) 145: { 146: addr->un.dhcsr |= DH_IE; 147: dhact |= (1<<dh); 148: addr->dhsilo = 0; 149: } 150: s = spltty(); 151: if ((tp->t_state & TS_ISOPEN) == 0) 152: { 153: tp->t_state |= TS_WOPEN; 154: if (tp->t_ispeed == 0) 155: { 156: tp->t_state |= TS_HUPCLS; 157: tp->t_ispeed = B9600; 158: tp->t_ospeed = B9600; 159: tp->t_flags = IFLAGS; 160: } 161: ttychars(tp); 162: tp->t_dev = dev; 163: if (dev & HWFLOW) 164: tp->t_flags |= RTSCTS; 165: else 166: tp->t_flags &= ~RTSCTS; 167: dhparam(unit); 168: } 169: else if ((tp->t_state & TS_XCLUDE) && u.u_uid) 170: { 171: error = EBUSY; 172: goto out; 173: } 174: dmopen(dev); 175: if ((dmctl(unit, 0, DMGET) & DML_CAR) || (dev & SOFTCAR)) 176: tp->t_state |= TS_CARR_ON; 177: while ((tp->t_state & TS_CARR_ON) == 0 && !(flag & O_NONBLOCK)) 178: { 179: tp->t_state |= TS_WOPEN; 180: sleep((caddr_t)&tp->t_rawq, TTIPRI); 181: } 182: error = (*linesw[tp->t_line].l_open)(dev, tp); 183: out: 184: splx(s); 185: return(error); 186: } 187: 188: /* 189: * Close a DH line, turning off the DM11. 190: */ 191: dhclose(dev, flag) 192: dev_t dev; 193: int flag; 194: { 195: register struct tty *tp; 196: register int unit; 197: 198: unit = UNIT(dev); 199: tp = &dh11[unit]; 200: if ((tp->t_state & (TS_WOPEN | TS_ISOPEN)) == 0) 201: return(EBADF); /* XXX */ 202: (*linesw[tp->t_line].l_close)(tp, flag); 203: ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 204: dmctl(unit, DML_OFF, DMSET); 205: ttyclose(tp); 206: if (dh_overrun[unit]) 207: { 208: log(LOG_NOTICE, "dh%d %d overruns\n", dh_overrun[unit]); 209: dh_overrun[unit] = 0; 210: } 211: return(0); 212: } 213: 214: dhselect(dev, rw) 215: dev_t dev; 216: int rw; 217: { 218: return(ttyselect(&dh11[UNIT(dev)], rw)); 219: } 220: 221: dhread(dev, uio, flag) 222: dev_t dev; 223: struct uio *uio; 224: int flag; 225: { 226: register struct tty *tp = &dh11[UNIT(dev)]; 227: 228: return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 229: } 230: 231: dhwrite(dev, uio, flag) 232: dev_t dev; 233: struct uio *uio; 234: { 235: register struct tty *tp = &dh11[UNIT(dev)]; 236: 237: return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 238: } 239: 240: /* 241: * DH11 receiver interrupt. 242: */ 243: dhrint(dh) 244: int dh; 245: { 246: register struct tty *tp; 247: register int c; 248: register struct dhdevice *addr; 249: struct tty *tp0; 250: int line, p; 251: 252: addr = (struct dhdevice *)dhinfo[dh].ui_addr; 253: if (addr == 0) /* Can't happen? */ 254: return; 255: tp0 = &dh11[dh<<4]; 256: /* 257: * Loop fetching characters from the silo for this 258: * dh until there are no more in the silo. 259: */ 260: while ((c = addr->dhrcr) < 0) { 261: line = (c >> 8) & 0xf; 262: tp = tp0 + line; 263: dhchars[dh]++; 264: if ((tp->t_state&TS_ISOPEN)==0) { 265: wakeup((caddr_t)&tp->t_rawq); 266: continue; 267: } 268: if (c & DH_PE) 269: { 270: p = tp->t_flags & (EVENP|ODDP); 271: if (p == EVENP || p == ODDP) 272: continue; 273: } 274: if (c & DH_DO) 275: { 276: dh_overrun[(dh << 4) + line]++; 277: continue; 278: } 279: if (c & DH_FE) 280: /* 281: * At framing error (break) generate 282: * a null (in raw mode, for getty), or an 283: * interrupt (in cooked/cbreak mode). 284: */ 285: if (tp->t_flags & RAW) 286: c = 0; 287: else 288: #ifdef OLDWAY 289: c = tp->t_intrc; 290: #else 291: c = tp->t_brkc; /* why have brkc if not used? */ 292: #endif 293: #if NBK > 0 294: if (tp->t_line == NETLDISC) { 295: c &= 0177; 296: BKINPUT(c, tp); 297: } else 298: #endif 299: (*linesw[tp->t_line].l_rint)(c, tp); 300: } 301: } 302: 303: /* 304: * Ioctl for DH11. 305: */ 306: /*ARGSUSED*/ 307: dhioctl(dev, cmd, data, flag) 308: dev_t dev; 309: u_int cmd; 310: caddr_t data; 311: int flag; 312: { 313: register struct tty *tp; 314: register unit = UNIT(dev); 315: int error, brkline; 316: 317: tp = &dh11[unit]; 318: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 319: if (error >= 0) 320: return(error); 321: error = ttioctl(tp, cmd, data, flag); 322: if (error >= 0) 323: { 324: if (cmd == TIOCSETP || cmd == TIOCSETN || 325: cmd == TIOCLBIS || cmd == TIOCLBIC || cmd == TIOCLSET) 326: dhparam(unit); 327: return(error); 328: } 329: brkline = 1 << (unit & 0xf); 330: switch (cmd) 331: { 332: case TIOCSBRK: 333: ((struct dhdevice *)(tp->t_addr))->dhbreak |= brkline; 334: break; 335: case TIOCCBRK: 336: ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~brkline; 337: break; 338: case TIOCSDTR: 339: (void)dmctl(unit, DML_DTR|DML_RTS, DMBIS); 340: break; 341: case TIOCCDTR: 342: (void)dmctl(unit, DML_DTR|DML_RTS, DMBIC); 343: break; 344: case TIOCMSET: 345: (void)dmctl(unit, dmtodh(*(int *)data, DMSET)); 346: break; 347: case TIOCMBIS: 348: (void)dmctl(unit, dmtodh(*(int *)data, DMBIS)); 349: break; 350: case TIOCMBIC: 351: (void)dmctl(unit, dmtodh(*(int *)data, DMBIC)); 352: break; 353: case TIOCMGET: 354: *(int *)data = dhtodm(dmctl(unit, 0, DMGET)); 355: break; 356: default: 357: return(ENOTTY); 358: } 359: return(0); 360: } 361: 362: static int 363: dmtodh(bits) 364: register int bits; 365: { 366: register int b = 0; 367: 368: if (bits & TIOCM_RTS) b |= DML_RTS; 369: if (bits & TIOCM_DTR) b |= DML_DTR; 370: if (bits & TIOCM_LE) b |= DML_LE; 371: return(b); 372: } 373: 374: static int 375: dhtodm(bits) 376: register int bits; 377: { 378: register int b = 0; 379: 380: if (bits & DML_RNG) b |= TIOCM_RNG; 381: if (bits & DML_CAR) b |= TIOCM_CAR; 382: if (bits & DML_CTS) b |= TIOCM_CTS; 383: if (bits & DML_RTS) b |= TIOCM_RTS; 384: if (bits & DML_DTR) b |= TIOCM_DTR; 385: if (bits & DML_LE) b |= TIOCM_LE; 386: return(b); 387: } 388: 389: /* 390: * Set parameters from open or stty into the DH hardware 391: * registers. 392: */ 393: dhparam(unit) 394: register int unit; 395: { 396: register struct tty *tp; 397: register struct dhdevice *addr; 398: register int lpar; 399: int s; 400: 401: tp = &dh11[unit]; 402: addr = (struct dhdevice *)tp->t_addr; 403: /* 404: * Block interrupts so parameters will be set 405: * before the line interrupts. 406: */ 407: s = spltty(); 408: addr->un.dhcsrl = (unit&0xf)|DH_IE; 409: if ((tp->t_ispeed)==0) 410: { 411: tp->t_state |= TS_HUPCLS; 412: dmctl(unit, DML_OFF, DMSET); 413: goto out; 414: } 415: lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); 416: if ((tp->t_ispeed) == B134) 417: lpar |= BITS6|PENABLE|HDUPLX; 418: else if (tp->t_flags & (RAW|LITOUT|PASS8)) 419: lpar |= BITS8; 420: else 421: lpar |= BITS7|PENABLE; 422: if ((tp->t_flags&EVENP) == 0) 423: lpar |= OPAR; 424: if ((tp->t_ospeed) == B110) 425: lpar |= TWOSB; 426: addr->dhlpr = lpar; 427: out: 428: splx(s); 429: return(0); 430: } 431: 432: /* 433: * DH transmitter interrupt. 434: * Restart each line which used to be active but has 435: * terminated transmission since the last interrupt. 436: */ 437: dhxint(dh) 438: int dh; 439: { 440: register struct tty *tp; 441: register struct dhdevice *addr; 442: short ttybit, bar, *sbar; 443: register int unit; 444: u_short cntr; 445: ubadr_t car; 446: struct dmdevice *dmaddr; 447: 448: addr = (struct dhdevice *)dhinfo[dh].ui_addr; 449: if (addr->un.dhcsr & DH_NXM) { 450: addr->un.dhcsr |= DH_CNI; 451: log(LOG_NOTICE, "dh%d NXM\n", dh); 452: } 453: sbar = &dhsar[dh]; 454: bar = *sbar & ~addr->dhbar; 455: unit = dh * 16; ttybit = 1; 456: addr->un.dhcsr &= (short)~DH_TI; 457: for(; bar; unit++, ttybit <<= 1) { 458: if(bar & ttybit) { 459: *sbar &= ~ttybit; 460: bar &= ~ttybit; 461: tp = &dh11[unit]; 462: tp->t_state &= ~TS_BUSY; 463: if (tp->t_state&TS_FLUSH) 464: tp->t_state &= ~TS_FLUSH; 465: else { 466: addr->un.dhcsrl = (unit&017)|DH_IE; 467: /* 468: * Clists are either: 469: * 1) in kernel virtual space, 470: * which in turn lies in the 471: * first 64K of physical memory or 472: * 2) at UNIBUS virtual address 0. 473: * 474: * In either case, the extension bits are 0. 475: */ 476: car = (ubadr_t)addr->dhcar; 477: if (!ubmap) { 478: #if defined(CS02) 479: dmaddr = (struct dmdevice *)dminfo[dh].ui_addr; 480: 481: car |= ((ubadr_t)(dmaddr->dmlst_h&077) << 16); 482: #else 483: car |= (ubadr_t)((addr->dhsilo & 0300) << 10); 484: #endif 485: } 486: cntr = car - cpaddr(tp->t_outq.c_cf); 487: ndflush(&tp->t_outq, cntr); 488: } 489: if (tp->t_line) 490: (*linesw[tp->t_line].l_start)(tp); 491: else 492: dhstart(tp); 493: } 494: } 495: } 496: 497: /* 498: * Start (restart) transmission on the given DH11 line. 499: */ 500: dhstart(tp) 501: register struct tty *tp; 502: { 503: register struct dhdevice *addr; 504: register int dh, unit, nch; 505: int s, csrl; 506: ubadr_t uba; 507: struct dmdevice *dmaddr; 508: 509: unit = UNIT(tp->t_dev); 510: dh = unit >> 4; 511: unit &= 0xf; 512: addr = (struct dhdevice *)tp->t_addr; 513: 514: /* 515: * Must hold interrupts in following code to prevent 516: * state of the tp from changing. 517: */ 518: s = spltty(); 519: /* 520: * If it's currently active, or delaying, no need to do anything. 521: */ 522: if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 523: goto out; 524: ttyowake(tp); /* Wake up any sleepers */ 525: /* 526: * Now restart transmission unless the output queue is 527: * empty. 528: */ 529: if (tp->t_outq.c_cc == 0) 530: goto out; 531: /* 532: * This is where any per character delay handling would be done if ever 533: * implemented again. See the comments in dhv.c and dhu.c 534: */ 535: nch = ndqb(&tp->t_outq, 0); 536: /* 537: * If characters to transmit, restart transmission. 538: */ 539: if (nch) { 540: uba = cpaddr(tp->t_outq.c_cf); 541: csrl = (unit&017) | DH_IE; 542: if (ubmap) 543: addr->un.dhcsrl = (char)csrl; 544: else { 545: #if defined(CS02) 546: dmaddr = (struct dmdevice *)dminfo[dh].ui_addr; 547: addr->un.dhcsrl = csrl; 548: dmaddr->dmlst_h = hiint(uba) & 077; 549: #else 550: addr->un.dhcsrl = csrl | DH_IE | ((hiint(uba)<<4)&060); 551: #endif 552: } 553: addr->dhcar = loint(uba); 554: 555: { short word = 1 << unit; 556: dhsar[dh] |= word; 557: addr->dhbcr = -nch; 558: addr->dhbar |= word; 559: } 560: tp->t_state |= TS_BUSY; 561: } 562: out: 563: splx(s); 564: } 565: 566: 567: /* 568: * Stop output on a line, e.g. for ^S/^Q or output flush. 569: */ 570: /*ARGSUSED*/ 571: dhstop(tp, flag) 572: register struct tty *tp; 573: { 574: register struct dhdevice *addr; 575: register int unit, s; 576: 577: addr = (struct dhdevice *)tp->t_addr; 578: /* 579: * Block input/output interrupts while messing with state. 580: */ 581: s = spltty(); 582: if (tp->t_state & TS_BUSY) { 583: /* 584: * Device is transmitting; stop output 585: * by selecting the line and setting the byte 586: * count to -1. We will clean up later 587: * by examining the address where the dh stopped. 588: */ 589: unit = UNIT(tp->t_dev); 590: addr->un.dhcsrl = (unit&017) | DH_IE; 591: if ((tp->t_state & TS_TTSTOP) == 0) { 592: tp->t_state |= TS_FLUSH; 593: } 594: addr->dhbcr = -1; 595: } 596: splx(s); 597: } 598: 599: int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ 600: /* 601: * At software clock interrupt time, check status. 602: * Empty all the dh silos that are in use, and decide whether 603: * to turn any silos off or on. 604: */ 605: dhtimer() 606: { 607: register int dh, s; 608: static int timercalls; 609: 610: if (dhsilos) { 611: dhfasttimers++; /*DEBUG*/ 612: timercalls++; 613: s = spltty(); 614: for (dh = 0; dh < NDH; dh++) 615: if (dhsilos & (1 << dh)) 616: dhrint(dh); 617: splx(s); 618: } 619: if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { 620: dhslowtimers++; /*DEBUG*/ 621: timercalls = 0; 622: for (dh = 0; dh < NDH; dh++) { 623: ave(dhrate[dh], dhchars[dh], 8); 624: if ((dhchars[dh] > dhhighrate) && 625: ((dhsilos & (1 << dh)) == 0)) { 626: ((struct dhdevice *)(dhinfo[dh].ui_addr))->dhsilo = 627: (dhchars[dh] > 500? 32 : 16); 628: dhsilos |= (1 << dh); 629: dhtransitions++; /*DEBUG*/ 630: } else if ((dhsilos & (1 << dh)) && 631: (dhrate[dh] < dhlowrate)) { 632: ((struct dhdevice *)(dhinfo[dh].ui_addr))->dhsilo = 0; 633: dhsilos &= ~(1 << dh); 634: } 635: dhchars[dh] = 0; 636: } 637: } 638: timeout(dhtimer, (caddr_t) 0, dhsilos ? FASTTIMER : hz); 639: } 640: 641: /* 642: * Turn on the line associated with dh dev. 643: */ 644: dmopen(dev) 645: dev_t dev; 646: { 647: register struct tty *tp; 648: register struct dmdevice *addr; 649: register int unit; 650: int dm; 651: 652: unit = UNIT(dev); 653: dm = unit >> 4; 654: tp = &dh11[unit]; 655: if (dm >= NDH || dminfo[dm].ui_alive == 0) 656: { 657: tp->t_state |= TS_CARR_ON; 658: return; 659: } 660: (void)dmctl(unit, DML_ON, DMSET); 661: } 662: 663: /* 664: * Dump control bits into the DM registers. 665: */ 666: dmctl(unit, bits, how) 667: int unit; 668: int bits, how; 669: { 670: register struct dmdevice *addr; 671: register int s, mbits; 672: int dm; 673: 674: dm = unit >> 4; 675: addr = (struct dmdevice *)dminfo[dm].ui_addr; 676: if (!addr) 677: return(0); 678: s = spltty(); 679: addr->dmcsr &= ~DM_SE; 680: while (addr->dmcsr & DM_BUSY) 681: ; 682: addr->dmcsr = unit & 0xf; 683: mbits = addr->dmlstat; 684: 685: switch (how) 686: { 687: case DMGET: 688: break; /* go re-enable scan */ 689: case DMSET: 690: mbits = bits; 691: break; 692: case DMBIS: 693: mbits |= bits; 694: break; 695: case DMBIC: 696: mbits &= ~bits; 697: break; 698: } 699: addr->dmlstat = mbits; 700: addr->dmcsr = DM_IE|DM_SE; 701: splx(s); 702: return(mbits); 703: } 704: 705: /* 706: * DM interrupt; deal with carrier transitions. 707: */ 708: dmintr(dm) 709: int dm; 710: { 711: register struct uba_device *ui; 712: register struct tty *tp; 713: register struct dmdevice *addr; 714: int unit; 715: 716: ui = &dminfo[dm]; 717: addr = (struct dmdevice *)ui->ui_addr; 718: if (addr->dmcsr&DM_DONE == 0) 719: return; 720: unit = addr->dmcsr & 0xf; 721: tp = &dh11[(dm << 4) + unit]; 722: if (addr->dmcsr & DM_CF) 723: { 724: if (addr->dmlstat & DML_CAR) 725: (void)(*linesw[tp->t_line].l_modem)(tp, 1); 726: else if (!(tp->t_dev & SOFTCAR) && 727: (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 728: addr->dmlstat = 0; 729: } 730: if (addr->dmcsr & DM_CTS) 731: { 732: if (tp->t_flags & RTSCTS) 733: { 734: if (addr->dmlstat & DML_CTS) 735: { 736: tp->t_state &= ~TS_TTSTOP; 737: ttstart(tp); 738: } 739: else 740: { 741: tp->t_state |= TS_TTSTOP; 742: dhstop(tp, 0); 743: } 744: } 745: } 746: addr->dmcsr = DM_IE|DM_SE; 747: } 748: #endif