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