1: /* 2: * SCCS id @(#)dh.c 2.1 (Berkeley) 11/20/83 3: */ 4: 5: #include "dh.h" 6: #if NDH > 0 7: #include "param.h" 8: #include <sys/conf.h> 9: #include <sys/systm.h> 10: #include <sys/dir.h> 11: #include <sys/user.h> 12: #include <sys/file.h> 13: #include <sys/tty.h> 14: #include <sys/dhreg.h> 15: #include <sys/uba.h> 16: 17: #define q3 tp->t_outq 18: 19: #if defined (UNIBUS_MAP) || defined (UCB_CLIST) 20: extern ubadr_t clstaddr; 21: #ifdef UCB_CLIST 22: extern struct cblock *cfree; 23: #else UCB_CLIST 24: extern struct cblock cfree[]; 25: #endif UCB_CLIST 26: #define cpaddr(x) (clstaddr + (ubadr_t)((x) - cfree)) 27: 28: #else defined (UNIBUS_MAP) || defined (UCB_CLIST) 29: #define cpaddr(x) (x) 30: #endif defined (UNIBUS_MAP) || defined (UCB_CLIST) 31: 32: #ifdef DH_SOFTCAR 33: #define DHLINE(dev) (minor(dev) & 0177) 34: #else 35: #define DHLINE(dev) minor(dev) 36: #endif 37: 38: #define NDHLINE (NDH * 16) 39: struct tty dh11[NDHLINE]; 40: int ndh11 = NDHLINE; /* only for pstat */ 41: int dhlowdm = LOWDM; 42: int dhndm = NDM * 16; 43: int dhstart(); 44: int ttrstrt(); 45: #ifdef DH_SILO 46: #define SILOSCANRATE (hz / 10) 47: int dhchars[NDH]; 48: void dhtimer(); 49: #endif DH_SILO 50: 51: struct dhdevice *dh_addr[NDH]; 52: #if NDM > 0 53: struct dmdevice *dm_addr[NDM]; 54: #endif NDM 55: 56: /* 57: * Software copy of last dhbar 58: */ 59: int dhsar[NDH]; 60: 61: dhattach(addr, unit) 62: struct dhdevice *addr; 63: { 64: if ((unsigned) unit >= NDH) 65: return 0; 66: dh_addr[unit] = addr; 67: return 1; 68: } 69: 70: /* 71: * Open a DH line. Turn on this dh if this is 72: * the first use of it. Also do a dmopen to wait for carrier. 73: */ 74: /*ARGSUSED*/ 75: dhopen(dev, flag) 76: dev_t dev; 77: { 78: register struct tty *tp; 79: register unit; 80: register struct dhdevice *addr; 81: #ifdef DH_SILO 82: static dh_timer; 83: #endif DH_SILO 84: 85: unit = DHLINE(dev); 86: if ((unit >= NDHLINE) || ((addr = dh_addr[unit >> 4]) == 0)) { 87: u.u_error = ENXIO; 88: return; 89: } 90: tp = &dh11[unit]; 91: if (tp->t_state & XCLUDE && u.u_uid != 0) { 92: u.u_error = EBUSY; 93: return; 94: } 95: tp->t_addr = (caddr_t) addr; 96: tp->t_oproc = dhstart; 97: tp->t_iproc = NULL; 98: tp->t_state |= WOPEN; 99: 100: #ifdef DH_SILO 101: if (!dh_timer) { 102: dh_timer++; 103: timeout(dhtimer, (caddr_t) 0, SILOSCANRATE); 104: } 105: #endif DH_SILO 106: 107: addr->un.dhcsr |= DH_IE; 108: /* 109: * If this is first open, initialize tty state to default. 110: */ 111: if ((tp->t_state & ISOPEN) == 0) { 112: ttychars(tp); 113: if (tp->t_ispeed == 0) { 114: tp->t_ispeed = B300; 115: tp->t_ospeed = B300; 116: tp->t_flags = ODDP | EVENP | ECHO; 117: } 118: tp->t_line = DFLT_LDISC; 119: dhparam(unit); 120: } 121: #if NDM > 0 122: dmopen(dev); 123: #else 124: tp->t_state |= CARR_ON; 125: #endif 126: ttyopen(dev,tp); 127: } 128: 129: /* 130: * Close a DH line, turning off the DM11. 131: */ 132: /*ARGSUSED*/ 133: dhclose(dev, flag) 134: dev_t dev; 135: int flag; 136: { 137: register struct tty *tp; 138: register unit; 139: 140: unit = DHLINE(dev); 141: tp = &dh11[unit]; 142: ((struct dhdevice *) (tp->t_addr))->dhbreak &= ~(1 << (unit & 017)); 143: #if NDM > 0 144: if (tp->t_state & HUPCLS) 145: dmctl(unit, DML_OFF, DMSET); 146: #endif 147: ttyclose(tp); 148: } 149: 150: /* 151: * Read from a DH line. 152: */ 153: dhread(dev) 154: dev_t dev; 155: { 156: register struct tty *tp; 157: 158: tp = &dh11[DHLINE(dev)]; 159: (void) (*linesw[tp->t_line].l_read)(tp); 160: } 161: 162: /* 163: * Write on a DH line. 164: */ 165: dhwrite(dev) 166: { 167: register struct tty *tp; 168: 169: tp = &dh11[DHLINE(dev)]; 170: (void) (*linesw[tp->t_line].l_write)(tp); 171: } 172: 173: /* 174: * DH11 receiver interrupt. 175: */ 176: dhrint(dh) 177: int dh; 178: { 179: register struct tty *tp; 180: register int c; 181: register struct dhdevice *addr; 182: struct tty *tp0; 183: int overrun = 0; 184: 185: addr = dh_addr[dh]; 186: tp0 = &dh11[dh << 4]; 187: /* 188: * Loop fetching characters from the silo for this 189: * dh until there are no more in the silo. 190: */ 191: while ((c = addr->dhrcr) < 0) { 192: tp = tp0 + ((c >> 8) & 017); 193: if (tp >= &dh11[NDHLINE]) 194: continue; 195: if((tp->t_state & ISOPEN) == 0) { 196: wakeup((caddr_t)tp); 197: continue; 198: } 199: #ifdef DH_SILO 200: dhchars[dh]++; 201: #endif DH_SILO 202: #ifdef TEXAS_AUTOBAUD 203: if (image_mode(tp)) 204: c &= ~(DH_PE|DH_FE); 205: #endif 206: if (c & DH_PE) 207: if ((tp->t_flags & (EVENP | ODDP)) == EVENP 208: || (tp->t_flags & (EVENP | ODDP)) == ODDP) 209: continue; 210: if ((c & DH_DO) && overrun == 0) { 211: printf("dh%d: silo overflow\n", dh); 212: overrun = 1; 213: } 214: if (c & DH_FE) 215: /* 216: * At framing error (break) generate 217: * a null (in raw mode, for getty), or an 218: * interrupt (in cooked/cbreak mode). 219: */ 220: if (tp->t_flags & RAW) 221: c = 0; 222: else 223: c = tun.t_intrc; 224: (*linesw[tp->t_line].l_input)(c,tp); 225: } 226: } 227: 228: /* 229: * Ioctl for DH11. 230: */ 231: dhioctl(dev, cmd, addr, flag) 232: dev_t dev; 233: caddr_t addr; 234: { 235: register struct tty *tp; 236: register unit = DHLINE(dev); 237: 238: tp = &dh11[unit]; 239: switch (ttioctl(tp, cmd, addr, flag)) { 240: case TIOCSETP: 241: case TIOCSETN: 242: dhparam(unit); 243: break; 244: #ifdef DH_IOCTL 245: case TIOCSBRK: 246: ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1 << (unit & 017); 247: break; 248: case TIOCCBRK: 249: ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); 250: break; 251: #if NDM > 0 252: case TIOCSDTR: 253: dmctl (unit, DML_DTR | DML_RTS, DMBIS); 254: break; 255: case TIOCCDTR: 256: dmctl (unit, DML_DTR | DML_RTS, DMBIC); 257: break; 258: #endif 259: #endif DH_IOCTL 260: case 0: 261: break; 262: default: 263: u.u_error = ENOTTY; 264: } 265: } 266: 267: /* 268: * Set parameters from open or stty into the DH hardware 269: * registers. 270: */ 271: dhparam(unit) 272: int unit; 273: { 274: register struct tty *tp; 275: register struct dhdevice *addr; 276: int s; 277: register lpar; 278: 279: tp = &dh11[unit]; 280: addr = (struct dhdevice *) tp->t_addr; 281: /* 282: * Block interrupts so parameters will be set 283: * before the line interrupts. 284: */ 285: s = spl5(); 286: addr->un.dhcsrl = (unit & 017) | DH_IE; 287: if ((tp->t_ispeed) == 0) { 288: tp->t_state |= HUPCLS; 289: #if NDM > 0 290: dmctl(unit, DML_OFF, DMSET); 291: #endif 292: return; 293: } 294: lpar = ((tp->t_ospeed) << 10) | ((tp->t_ispeed) << 6); 295: if ((tp->t_ispeed) == B134) 296: lpar |= BITS6 | PENABLE | HDUPLX; 297: else 298: #ifdef UCB_NTTY 299: if ((tp->t_flags & RAW) || (tp->t_local & LLITOUT)) 300: #else 301: if (tp->t_flags & RAW) 302: #endif 303: lpar |= BITS8; 304: else 305: lpar |= BITS7 | PENABLE; 306: if ((tp->t_flags & EVENP) == 0) 307: lpar |= OPAR; 308: if (tp->t_ospeed == B110) /* 110 baud */ 309: lpar |= TWOSB; 310: addr->dhlpr = lpar; 311: splx(s); 312: } 313: 314: /* 315: * DH transmitter interrupt. 316: * Restart each line which used to be active but has 317: * terminated transmission since the last interrupt. 318: */ 319: dhxint(dh) 320: int dh; 321: { 322: register struct tty *tp; 323: register struct dhdevice *addr; 324: register unit; 325: int ttybit, bar, *sbar; 326: 327: addr = dh_addr[dh]; 328: if (addr->un.dhcsr & DH_NXM) { 329: addr->un.dhcsr |= DH_CNI; 330: printf("dh%d: NXM\n", dh); 331: } 332: sbar = &dhsar[dh]; 333: bar = *sbar & ~addr->dhbar; 334: unit = dh << 4; ttybit = 1; 335: addr->un.dhcsr &= ~DH_TI; 336: 337: for(; bar; unit++, ttybit <<= 1) { 338: if(bar & ttybit) { 339: *sbar &= ~ttybit; 340: bar &= ~ttybit; 341: tp = &dh11[unit]; 342: tp->t_state &= ~BUSY; 343: if (tp->t_state & FLUSH) 344: tp->t_state &= ~FLUSH; 345: else { 346: #if !defined(UCB_CLIST) || defined (UNIBUS_MAP) 347: /* 348: * Clists are either: 349: * 1) in kernel virtual space, 350: * which in turn lies in the 351: * first 64K of physical memory or 352: * 2) at UNIBUS virtual address 0. 353: * 354: * In either case, the extension bits are 0. 355: */ 356: addr->un.dhcsrl = (unit & 017) | DH_IE; 357: ndflush(&q3, 358: (short)(addr->dhcar - cpaddr(q3.c_cf))); 359: #else /* defined(UCB_CLIST) && !defined(UNIBUS_MAP) */ 360: ubadr_t car; 361: int count; 362: 363: addr->un.dhcsrl = (unit & 017) | DH_IE; 364: car = (ubadr_t) addr->dhcar 365: | (ubadr_t)(addr->dhsilo & 0300) << 10; 366: count = car - cpaddr(q3.c_cf); 367: ndflush(&q3, count); 368: #endif 369: } 370: dhstart(tp); 371: } 372: } 373: } 374: 375: /* 376: * Start (restart) transmission on the given DH line. 377: */ 378: dhstart(tp) 379: register struct tty *tp; 380: { 381: register struct dhdevice *addr; 382: register nch; 383: int s, unit; 384: 385: unit = (int) (tp - dh11); 386: addr = (struct dhdevice *) tp->t_addr; 387: 388: /* 389: * Must hold interrupts in following code to prevent 390: * state of the tp from changing. 391: */ 392: s = spl5(); 393: 394: /* 395: * If it's currently active, or delaying, no need to do anything. 396: */ 397: if (tp->t_state & (TIMEOUT | BUSY | TTSTOP)) 398: goto out; 399: /* 400: * If there are sleepers, and the output has drained below low 401: * water mark, wake up the sleepers. 402: */ 403: if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 404: if (tp->t_state&ASLEEP) { 405: tp->t_state &= ~ASLEEP; 406: #ifdef MPX_FILS 407: if (tp->t_chan) 408: mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 409: else 410: #endif 411: wakeup((caddr_t)&tp->t_outq); 412: } 413: #ifdef UCB_NET 414: if (tp->t_wsel) { 415: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 416: tp->t_wsel = 0; 417: tp->t_state &= ~TS_WCOLL; 418: } 419: #endif 420: } 421: 422: /* 423: * Now restart transmission unless the output queue is 424: * empty. 425: */ 426: if (tp->t_outq.c_cc == 0) 427: goto out; 428: #ifdef UCB_NTTY 429: if ((tp->t_flags & RAW) || (tp->t_local & LLITOUT)) 430: #else 431: if (tp->t_flags & RAW) 432: #endif 433: nch = ndqb(&tp->t_outq, 0); 434: else { 435: nch = ndqb(&tp->t_outq, 0200); 436: /* 437: * If first thing on queue is a delay, process it. 438: */ 439: if (nch == 0) { 440: nch = getc(&tp->t_outq); 441: timeout(ttrstrt, (caddr_t) tp, (nch & 0177) + 6); 442: tp->t_state |= TIMEOUT; 443: goto out; 444: } 445: } 446: /* 447: * If characters to transmit, restart transmission. 448: */ 449: if (nch) { 450: #if !defined(UCB_CLIST) || defined (UNIBUS_MAP) 451: addr->un.dhcsrl = (unit & 017) | DH_IE; 452: addr->dhcar = (short)cpaddr(tp->t_outq.c_cf); 453: #else /* defined(UCB_CLIST) && !defined(UNIBUS_MAP) */ 454: ubadr_t uba; 455: 456: uba = cpaddr(tp->t_outq.c_cf); 457: addr->un.dhcsrl = (unit&017) | DH_IE | ((hiint(uba) << 4) & 060); 458: addr->dhcar = loint(uba); 459: #endif 460: addr->dhbcr = -nch; 461: nch = 1 << (unit & 017); 462: addr->dhbar |= nch; 463: dhsar[unit >> 4] |= nch; 464: tp->t_state |= BUSY; 465: } 466: out: 467: splx(s); 468: } 469: 470: 471: /* 472: * Stop output on a line, e.g. for ^S/^Q or output flush. 473: */ 474: /*ARGSUSED*/ 475: dhstop(tp, flag) 476: register struct tty *tp; 477: { 478: register struct dhdevice *addr; 479: register unit; 480: int s; 481: 482: addr = (struct dhdevice *)tp->t_addr; 483: /* 484: * Block input/output interrupts while messing with state. 485: */ 486: s = spl6(); 487: if (tp->t_state & BUSY) { 488: /* 489: * Device is transmitting; stop output 490: * by selecting the line and setting the byte 491: * count to -1. We will clean up later 492: * by examining the address where the dh stopped. 493: */ 494: unit = DHLINE(tp->t_dev); 495: addr->un.dhcsrl = (unit & 017) | DH_IE; 496: if ((tp->t_state & TTSTOP) == 0) { 497: tp->t_state |= FLUSH; 498: } 499: addr->dhbcr = -1; 500: } 501: splx(s); 502: } 503: 504: #ifdef DH_SILO 505: void 506: dhtimer(dev) 507: dev_t dev; 508: { 509: register dh, cc; 510: register struct dhdevice *addr; 511: 512: dh = 0; 513: do { 514: addr = dh_addr[dh]; 515: cc = dhchars[dh]; 516: dhchars[dh] = 0; 517: if (cc > 50) 518: cc = 32; 519: else 520: if (cc > 16) 521: cc = 16; 522: else 523: cc = 0; 524: addr->dhsilo = cc; 525: dhrint(dh++); 526: } while (dh < NDH); 527: timeout(dhtimer, (caddr_t) 0, SILOSCANRATE); 528: } 529: #endif DH_SILO 530: 531: #if NDM > 0 532: 533: dmattach(addr, unit) 534: struct device *addr; 535: { 536: if ((unsigned) unit >= NDM) 537: return 0; 538: dm_addr[unit] = addr; 539: return 1; 540: } 541: 542: /* 543: * Turn on the line associated with the dh device dev. 544: */ 545: dmopen(dev) 546: dev_t dev; 547: { 548: register struct tty *tp; 549: register struct dmdevice *addr; 550: register unit; 551: int s; 552: 553: unit = DHLINE(dev); 554: tp = &dh11[unit]; 555: if ((unit < dhlowdm) || (unit >= dhlowdm + dhndm) 556: || ((addr = dm_addr[(unit - dhlowdm) >> 4]) == 0) 557: #ifdef DH_SOFTCAR 558: || (dev & 0200) 559: #endif 560: ) { 561: tp->t_state |= CARR_ON; 562: return; 563: } 564: s = spl5(); 565: addr->dmcsr &= ~DM_SE; 566: while (addr->dmcsr & DM_BUSY) 567: ; 568: addr->dmcsr = unit & 017; 569: addr->dmlstat = DML_ON; 570: if (addr->dmlstat & DML_CAR) 571: tp->t_state |= CARR_ON; 572: addr->dmcsr = DM_IE | DM_SE; 573: while ((tp->t_state & CARR_ON)==0) 574: sleep((caddr_t) &tp->t_rawq, TTIPRI); 575: addr->dmcsr = unit & 017; 576: if (addr->dmlstat & DML_SR) { 577: tp->t_ispeed = B1200; 578: tp->t_ospeed = B1200; 579: dhparam(unit); 580: } 581: addr->dmcsr = DM_IE | DM_SE; 582: splx(s); 583: } 584: 585: /* 586: * Dump control bits into the DM registers. 587: */ 588: dmctl(unit, bits, how) 589: register unit; 590: { 591: register struct dmdevice *addr; 592: register s; 593: 594: if(unit < dhlowdm || unit >= dhlowdm + dhndm) 595: return; 596: addr = dm_addr[(unit - dhlowdm) >> 4]; 597: s = spl5(); 598: addr->dmcsr &= ~DM_SE; 599: while (addr->dmcsr & DM_BUSY) 600: ; 601: addr->dmcsr = unit & 017; 602: switch (how) { 603: case DMSET: 604: addr->dmlstat = bits; 605: break; 606: case DMBIS: 607: addr->dmlstat |= bits; 608: break; 609: case DMBIC: 610: addr->dmlstat &= ~bits; 611: break; 612: } 613: addr->dmcsr = DM_IE | DM_SE; 614: splx(s); 615: } 616: 617: /* 618: * DM interrupt; deal with carrier transitions. 619: */ 620: dmintr(dm) 621: register dm; 622: { 623: register struct tty *tp; 624: register struct dmdevice *addr; 625: 626: addr = dm_addr[dm]; 627: if (addr->dmcsr & DM_DONE) { 628: if (addr->dmcsr & DM_CF) { 629: tp = &dh11[(dm << 4) + (addr->dmcsr & 017)]; 630: tp += dhlowdm; 631: if (tp < &dh11[dhlowdm + dhndm]) { 632: wakeup((caddr_t)&tp->t_rawq); 633: #ifdef UCB_NTTY 634: if ((tp->t_state & WOPEN) == 0 635: && (tp->t_local & LMDMBUF)) { 636: if ((addr->dmlstat & DML_CAR)) { 637: tp->t_state &= ~TTSTOP; 638: ttstart(tp); 639: } else if ((tp->t_state&TTSTOP) == 0) { 640: tp->t_state |= TTSTOP; 641: dhstop(tp, 0); 642: } 643: } else 644: #endif 645: if ((addr->dmlstat & DML_CAR) == 0) { 646: if ((tp->t_state & WOPEN)==0 647: #ifdef UCB_NTTY 648: && (tp->t_local & LNOHANG)==0 649: #endif 650: #ifdef DH_SOFTCAR 651: && (tp->t_dev & 0200)==0 652: #endif 653: ) { 654: gsignal(tp->t_pgrp, SIGHUP); 655: addr->dmlstat = 0; 656: flushtty(tp, FREAD|FWRITE); 657: } 658: tp->t_state &= ~CARR_ON; 659: } else 660: tp->t_state |= CARR_ON; 661: } 662: } 663: addr->dmcsr = DM_IE | DM_SE; 664: } 665: } 666: #endif NDM 667: #endif NDH