|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)dca.c 7.7 (Berkeley) 6/30/90 ! 21: */ ! 22: ! 23: #include "dca.h" ! 24: #if NDCA > 0 ! 25: /* ! 26: * 98626/98644/internal serial interface ! 27: */ ! 28: #include "param.h" ! 29: #include "systm.h" ! 30: #include "ioctl.h" ! 31: #include "tty.h" ! 32: #include "user.h" ! 33: #include "conf.h" ! 34: #include "file.h" ! 35: #include "uio.h" ! 36: #include "kernel.h" ! 37: #include "syslog.h" ! 38: ! 39: #include "device.h" ! 40: #include "dcareg.h" ! 41: #include "machine/cpu.h" ! 42: #include "machine/isr.h" ! 43: ! 44: int dcaprobe(); ! 45: struct driver dcadriver = { ! 46: dcaprobe, "dca", ! 47: }; ! 48: ! 49: int dcastart(), dcaparam(), dcaintr(); ! 50: int dcasoftCAR; ! 51: int dca_active; ! 52: int ndca = NDCA; ! 53: int dcaconsole = -1; ! 54: int dcadefaultrate = TTYDEF_SPEED; ! 55: struct dcadevice *dca_addr[NDCA]; ! 56: struct tty dca_tty[NDCA]; ! 57: struct isr dcaisr[NDCA]; ! 58: ! 59: struct speedtab dcaspeedtab[] = { ! 60: 0, 0, ! 61: 50, DCABRD(50), ! 62: 75, DCABRD(75), ! 63: 110, DCABRD(110), ! 64: 134, DCABRD(134), ! 65: 150, DCABRD(150), ! 66: 200, DCABRD(200), ! 67: 300, DCABRD(300), ! 68: 600, DCABRD(600), ! 69: 1200, DCABRD(1200), ! 70: 1800, DCABRD(1800), ! 71: 2400, DCABRD(2400), ! 72: 4800, DCABRD(4800), ! 73: 9600, DCABRD(9600), ! 74: 19200, DCABRD(19200), ! 75: 38400, DCABRD(38400), ! 76: -1, -1 ! 77: }; ! 78: ! 79: extern struct tty *constty; ! 80: #ifdef KGDB ! 81: extern int kgdb_dev; ! 82: extern int kgdb_rate; ! 83: extern int kgdb_debug_init; ! 84: #endif ! 85: ! 86: #define UNIT(x) minor(x) ! 87: ! 88: dcaprobe(hd) ! 89: register struct hp_device *hd; ! 90: { ! 91: register struct dcadevice *dca; ! 92: register int unit; ! 93: ! 94: dca = (struct dcadevice *)hd->hp_addr; ! 95: if (dca->dca_irid != DCAID0 && ! 96: dca->dca_irid != DCAREMID0 && ! 97: dca->dca_irid != DCAID1 && ! 98: dca->dca_irid != DCAREMID1) ! 99: return (0); ! 100: unit = hd->hp_unit; ! 101: if (unit == dcaconsole) ! 102: DELAY(100000); ! 103: dca->dca_irid = 0xFF; ! 104: DELAY(100); ! 105: ! 106: hd->hp_ipl = DCAIPL(dca->dca_ic); ! 107: dcaisr[unit].isr_ipl = hd->hp_ipl; ! 108: dcaisr[unit].isr_arg = unit; ! 109: dcaisr[unit].isr_intr = dcaintr; ! 110: dca_addr[unit] = dca; ! 111: dca_active |= 1 << unit; ! 112: dcasoftCAR = hd->hp_flags; ! 113: isrlink(&dcaisr[unit]); ! 114: #ifdef KGDB ! 115: if (kgdb_dev == makedev(1, unit)) { ! 116: if (dcaconsole == unit) ! 117: kgdb_dev = -1; /* can't debug over console port */ ! 118: else { ! 119: (void) dcainit(unit); ! 120: dcaconsole = -2; /* XXX */ ! 121: if (kgdb_debug_init) { ! 122: printf("dca%d: kgdb waiting...", unit); ! 123: /* trap into kgdb */ ! 124: asm("trap #15;"); ! 125: printf("connected.\n"); ! 126: } else ! 127: printf("dca%d: kgdb enabled\n", unit); ! 128: } ! 129: } ! 130: #endif ! 131: dca->dca_ic = IC_IE; ! 132: /* ! 133: * Need to reset baud rate, etc. of next print so reset dcaconsole. ! 134: * Also make sure console is always "hardwired" ! 135: */ ! 136: if (unit == dcaconsole) { ! 137: dcaconsole = -1; ! 138: dcasoftCAR |= (1 << unit); ! 139: } ! 140: return (1); ! 141: } ! 142: ! 143: dcaopen(dev, flag) ! 144: dev_t dev; ! 145: { ! 146: register struct tty *tp; ! 147: register int unit; ! 148: int error = 0; ! 149: ! 150: unit = UNIT(dev); ! 151: if (unit >= NDCA || (dca_active & (1 << unit)) == 0) ! 152: return (ENXIO); ! 153: tp = &dca_tty[unit]; ! 154: tp->t_oproc = dcastart; ! 155: tp->t_param = dcaparam; ! 156: tp->t_dev = dev; ! 157: if ((tp->t_state & TS_ISOPEN) == 0) { ! 158: tp->t_state |= TS_WOPEN; ! 159: ttychars(tp); ! 160: tp->t_iflag = TTYDEF_IFLAG; ! 161: tp->t_oflag = TTYDEF_OFLAG; ! 162: tp->t_cflag = TTYDEF_CFLAG; ! 163: tp->t_lflag = TTYDEF_LFLAG; ! 164: tp->t_ispeed = tp->t_ospeed = dcadefaultrate; ! 165: dcaparam(tp, &tp->t_termios); ! 166: ttsetwater(tp); ! 167: } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) ! 168: return (EBUSY); ! 169: (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET); ! 170: if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD)) ! 171: tp->t_state |= TS_CARR_ON; ! 172: (void) spltty(); ! 173: while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && ! 174: (tp->t_state & TS_CARR_ON) == 0) { ! 175: tp->t_state |= TS_WOPEN; ! 176: if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ! 177: ttopen, 0)) ! 178: break; ! 179: } ! 180: (void) spl0(); ! 181: if (error == 0) ! 182: error = (*linesw[tp->t_line].l_open)(dev, tp); ! 183: return (error); ! 184: } ! 185: ! 186: /*ARGSUSED*/ ! 187: dcaclose(dev, flag) ! 188: dev_t dev; ! 189: { ! 190: register struct tty *tp; ! 191: register struct dcadevice *dca; ! 192: register int unit; ! 193: ! 194: unit = UNIT(dev); ! 195: dca = dca_addr[unit]; ! 196: tp = &dca_tty[unit]; ! 197: (*linesw[tp->t_line].l_close)(tp); ! 198: dca->dca_cfcr &= ~CFCR_SBREAK; ! 199: #ifdef KGDB ! 200: /* do not disable interrupts if debugging */ ! 201: if (kgdb_dev != makedev(1, unit)) ! 202: #endif ! 203: dca->dca_ier = 0; ! 204: if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || ! 205: (tp->t_state&TS_ISOPEN) == 0) ! 206: (void) dcamctl(dev, 0, DMSET); ! 207: ttyclose(tp); ! 208: return(0); ! 209: } ! 210: ! 211: dcaread(dev, uio, flag) ! 212: dev_t dev; ! 213: struct uio *uio; ! 214: { ! 215: register struct tty *tp = &dca_tty[UNIT(dev)]; ! 216: ! 217: return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); ! 218: } ! 219: ! 220: dcawrite(dev, uio, flag) ! 221: dev_t dev; ! 222: struct uio *uio; ! 223: { ! 224: int unit = UNIT(dev); ! 225: register struct tty *tp = &dca_tty[unit]; ! 226: ! 227: /* ! 228: * (XXX) We disallow virtual consoles if the physical console is ! 229: * a serial port. This is in case there is a display attached that ! 230: * is not the console. In that situation we don't need/want the X ! 231: * server taking over the console. ! 232: */ ! 233: if (constty && unit == dcaconsole) ! 234: constty = NULL; ! 235: return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); ! 236: } ! 237: ! 238: dcaintr(unit) ! 239: register int unit; ! 240: { ! 241: register struct dcadevice *dca; ! 242: register u_char code; ! 243: register struct tty *tp; ! 244: ! 245: dca = dca_addr[unit]; ! 246: if ((dca->dca_ic & IC_IR) == 0) ! 247: return(0); ! 248: while (1) { ! 249: code = dca->dca_iir; ! 250: switch (code) { ! 251: case IIR_NOPEND: ! 252: return (1); ! 253: case IIR_RXRDY: ! 254: /* do time-critical read in-line */ ! 255: tp = &dca_tty[unit]; ! 256: code = dca->dca_data; ! 257: if ((tp->t_state & TS_ISOPEN) == 0) { ! 258: #ifdef KGDB ! 259: if (kgdb_dev == makedev(1, unit) && ! 260: code == '!') { ! 261: printf("kgdb trap from dca%d\n", unit); ! 262: /* trap into kgdb */ ! 263: asm("trap #15;"); ! 264: } ! 265: #endif ! 266: } else ! 267: (*linesw[tp->t_line].l_rint)(code, tp); ! 268: break; ! 269: case IIR_TXRDY: ! 270: tp = &dca_tty[unit]; ! 271: tp->t_state &=~ (TS_BUSY|TS_FLUSH); ! 272: if (tp->t_line) ! 273: (*linesw[tp->t_line].l_start)(tp); ! 274: else ! 275: dcastart(tp); ! 276: break; ! 277: case IIR_RLS: ! 278: dcaeint(unit, dca); ! 279: break; ! 280: default: ! 281: if (code & IIR_NOPEND) ! 282: return (1); ! 283: log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n", ! 284: unit, code); ! 285: /* fall through */ ! 286: case IIR_MLSC: ! 287: dcamint(unit, dca); ! 288: break; ! 289: } ! 290: } ! 291: } ! 292: ! 293: dcaeint(unit, dca) ! 294: register int unit; ! 295: register struct dcadevice *dca; ! 296: { ! 297: register struct tty *tp; ! 298: register int stat, c; ! 299: ! 300: tp = &dca_tty[unit]; ! 301: stat = dca->dca_lsr; ! 302: c = dca->dca_data; ! 303: if ((tp->t_state & TS_ISOPEN) == 0) { ! 304: #ifdef KGDB ! 305: /* we don't care about parity errors */ ! 306: if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && ! 307: kgdb_dev == makedev(1, unit) && c == '!') { ! 308: printf("kgdb trap from dca%d\n", unit); ! 309: /* trap into kgdb */ ! 310: asm("trap #15;"); ! 311: } ! 312: #endif ! 313: return; ! 314: } ! 315: if (stat & (LSR_BI | LSR_FE)) ! 316: c |= TTY_FE; ! 317: else if (stat & LSR_PE) ! 318: c |= TTY_PE; ! 319: else if (stat & LSR_OE) ! 320: log(LOG_WARNING, "dca%d: silo overflow\n", unit); ! 321: (*linesw[tp->t_line].l_rint)(c, tp); ! 322: } ! 323: ! 324: dcamint(unit, dca) ! 325: register int unit; ! 326: register struct dcadevice *dca; ! 327: { ! 328: register struct tty *tp; ! 329: register int stat; ! 330: ! 331: tp = &dca_tty[unit]; ! 332: stat = dca->dca_msr; ! 333: if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) { ! 334: if (stat & MSR_DCD) ! 335: (void)(*linesw[tp->t_line].l_modem)(tp, 1); ! 336: else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) ! 337: dca->dca_mcr &= ~(MCR_DTR | MCR_RTS); ! 338: } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) && ! 339: (tp->t_flags & CRTSCTS)) { ! 340: /* the line is up and we want to do rts/cts flow control */ ! 341: if (stat & MSR_CTS) { ! 342: tp->t_state &=~ TS_TTSTOP; ! 343: ttstart(tp); ! 344: } else ! 345: tp->t_state |= TS_TTSTOP; ! 346: } ! 347: } ! 348: ! 349: dcaioctl(dev, cmd, data, flag) ! 350: dev_t dev; ! 351: caddr_t data; ! 352: { ! 353: register struct tty *tp; ! 354: register int unit = UNIT(dev); ! 355: register struct dcadevice *dca; ! 356: register int error; ! 357: ! 358: tp = &dca_tty[unit]; ! 359: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); ! 360: if (error >= 0) ! 361: return (error); ! 362: error = ttioctl(tp, cmd, data, flag); ! 363: if (error >= 0) ! 364: return (error); ! 365: ! 366: dca = dca_addr[unit]; ! 367: switch (cmd) { ! 368: ! 369: case TIOCSBRK: ! 370: dca->dca_cfcr |= CFCR_SBREAK; ! 371: break; ! 372: ! 373: case TIOCCBRK: ! 374: dca->dca_cfcr &= ~CFCR_SBREAK; ! 375: break; ! 376: ! 377: case TIOCSDTR: ! 378: (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS); ! 379: break; ! 380: ! 381: case TIOCCDTR: ! 382: (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC); ! 383: break; ! 384: ! 385: case TIOCMSET: ! 386: (void) dcamctl(dev, *(int *)data, DMSET); ! 387: break; ! 388: ! 389: case TIOCMBIS: ! 390: (void) dcamctl(dev, *(int *)data, DMBIS); ! 391: break; ! 392: ! 393: case TIOCMBIC: ! 394: (void) dcamctl(dev, *(int *)data, DMBIC); ! 395: break; ! 396: ! 397: case TIOCMGET: ! 398: *(int *)data = dcamctl(dev, 0, DMGET); ! 399: break; ! 400: ! 401: default: ! 402: return (ENOTTY); ! 403: } ! 404: return (0); ! 405: } ! 406: ! 407: dcaparam(tp, t) ! 408: register struct tty *tp; ! 409: register struct termios *t; ! 410: { ! 411: register struct dcadevice *dca; ! 412: register int cfcr, cflag = t->c_cflag; ! 413: int unit = UNIT(tp->t_dev); ! 414: int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab); ! 415: ! 416: /* check requested parameters */ ! 417: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) ! 418: return(EINVAL); ! 419: /* and copy to tty */ ! 420: tp->t_ispeed = t->c_ispeed; ! 421: tp->t_ospeed = t->c_ospeed; ! 422: tp->t_cflag = cflag; ! 423: ! 424: dca = dca_addr[unit]; ! 425: dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC; ! 426: if (ospeed == 0) { ! 427: (void) dcamctl(unit, 0, DMSET); /* hang up line */ ! 428: return(0); ! 429: } ! 430: dca->dca_cfcr |= CFCR_DLAB; ! 431: dca->dca_data = ospeed & 0xFF; ! 432: dca->dca_ier = ospeed >> 8; ! 433: switch (cflag&CSIZE) { ! 434: case CS5: ! 435: cfcr = CFCR_5BITS; break; ! 436: case CS6: ! 437: cfcr = CFCR_6BITS; break; ! 438: case CS7: ! 439: cfcr = CFCR_7BITS; break; ! 440: case CS8: ! 441: cfcr = CFCR_8BITS; break; ! 442: } ! 443: if (cflag&PARENB) { ! 444: cfcr |= CFCR_PENAB; ! 445: if ((cflag&PARODD) == 0) ! 446: cfcr |= CFCR_PEVEN; ! 447: } ! 448: if (cflag&CSTOPB) ! 449: cfcr |= CFCR_STOPB; ! 450: dca->dca_cfcr = cfcr; ! 451: return(0); ! 452: } ! 453: ! 454: dcastart(tp) ! 455: register struct tty *tp; ! 456: { ! 457: register struct dcadevice *dca; ! 458: int s, unit, c; ! 459: ! 460: unit = UNIT(tp->t_dev); ! 461: dca = dca_addr[unit]; ! 462: s = spltty(); ! 463: if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) ! 464: goto out; ! 465: if (tp->t_outq.c_cc <= tp->t_lowat) { ! 466: if (tp->t_state&TS_ASLEEP) { ! 467: tp->t_state &= ~TS_ASLEEP; ! 468: wakeup((caddr_t)&tp->t_outq); ! 469: } ! 470: if (tp->t_wsel) { ! 471: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); ! 472: tp->t_wsel = 0; ! 473: tp->t_state &= ~TS_WCOLL; ! 474: } ! 475: } ! 476: if (tp->t_outq.c_cc == 0) ! 477: goto out; ! 478: if (dca->dca_lsr & LSR_TXRDY) { ! 479: c = getc(&tp->t_outq); ! 480: tp->t_state |= TS_BUSY; ! 481: dca->dca_data = c; ! 482: } ! 483: out: ! 484: splx(s); ! 485: } ! 486: ! 487: /* ! 488: * Stop output on a line. ! 489: */ ! 490: /*ARGSUSED*/ ! 491: dcastop(tp, flag) ! 492: register struct tty *tp; ! 493: { ! 494: register int s; ! 495: ! 496: s = spltty(); ! 497: if (tp->t_state & TS_BUSY) { ! 498: if ((tp->t_state&TS_TTSTOP)==0) ! 499: tp->t_state |= TS_FLUSH; ! 500: } ! 501: splx(s); ! 502: } ! 503: ! 504: dcamctl(dev, bits, how) ! 505: dev_t dev; ! 506: int bits, how; ! 507: { ! 508: register struct dcadevice *dca; ! 509: register int unit; ! 510: int s; ! 511: ! 512: unit = UNIT(dev); ! 513: dca = dca_addr[unit]; ! 514: s = spltty(); ! 515: switch (how) { ! 516: ! 517: case DMSET: ! 518: dca->dca_mcr = bits; ! 519: break; ! 520: ! 521: case DMBIS: ! 522: dca->dca_mcr |= bits; ! 523: break; ! 524: ! 525: case DMBIC: ! 526: dca->dca_mcr &= ~bits; ! 527: break; ! 528: ! 529: case DMGET: ! 530: bits = dca->dca_msr; ! 531: break; ! 532: } ! 533: (void) splx(s); ! 534: return(bits); ! 535: } ! 536: ! 537: /* ! 538: * Following are all routines needed for DCA to act as console ! 539: */ ! 540: #include "machine/cons.h" ! 541: ! 542: dcacnprobe(cp) ! 543: struct consdev *cp; ! 544: { ! 545: int unit, i; ! 546: extern int dcaopen(); ! 547: ! 548: /* XXX: ick */ ! 549: unit = CONUNIT; ! 550: dca_addr[CONUNIT] = CONADDR; ! 551: ! 552: /* make sure hardware exists */ ! 553: if (badaddr((short *)dca_addr[unit])) { ! 554: cp->cn_pri = CN_DEAD; ! 555: return; ! 556: } ! 557: ! 558: /* locate the major number */ ! 559: for (i = 0; i < nchrdev; i++) ! 560: if (cdevsw[i].d_open == dcaopen) ! 561: break; ! 562: ! 563: /* initialize required fields */ ! 564: cp->cn_dev = makedev(i, unit); ! 565: cp->cn_tp = &dca_tty[unit]; ! 566: switch (dca_addr[unit]->dca_irid) { ! 567: case DCAID0: ! 568: case DCAID1: ! 569: cp->cn_pri = CN_NORMAL; ! 570: break; ! 571: case DCAREMID0: ! 572: case DCAREMID1: ! 573: cp->cn_pri = CN_REMOTE; ! 574: break; ! 575: default: ! 576: cp->cn_pri = CN_DEAD; ! 577: break; ! 578: } ! 579: } ! 580: ! 581: dcacninit(cp) ! 582: struct consdev *cp; ! 583: { ! 584: int unit = UNIT(cp->cn_dev); ! 585: ! 586: dcainit(unit); ! 587: dcaconsole = unit; ! 588: } ! 589: ! 590: dcainit(unit) ! 591: int unit; ! 592: { ! 593: register struct dcadevice *dca; ! 594: int s, rate; ! 595: short stat; ! 596: ! 597: #ifdef lint ! 598: stat = unit; if (stat) return; ! 599: #endif ! 600: dca = dca_addr[unit]; ! 601: s = splhigh(); ! 602: dca->dca_irid = 0xFF; ! 603: DELAY(100); ! 604: dca->dca_ic = IC_IE; ! 605: dca->dca_cfcr = CFCR_DLAB; ! 606: rate = ttspeedtab(dcadefaultrate, dcaspeedtab); ! 607: dca->dca_data = rate & 0xFF; ! 608: dca->dca_ier = rate >> 8; ! 609: dca->dca_cfcr = CFCR_8BITS; ! 610: dca->dca_ier = IER_ERXRDY | IER_ETXRDY; ! 611: stat = dca->dca_iir; ! 612: splx(s); ! 613: } ! 614: ! 615: dcacngetc(dev) ! 616: { ! 617: register struct dcadevice *dca = dca_addr[UNIT(dev)]; ! 618: short stat; ! 619: int c, s; ! 620: ! 621: #ifdef lint ! 622: stat = dev; if (stat) return(0); ! 623: #endif ! 624: s = splhigh(); ! 625: while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0) ! 626: ; ! 627: c = dca->dca_data; ! 628: stat = dca->dca_iir; ! 629: splx(s); ! 630: return(c); ! 631: } ! 632: ! 633: /* ! 634: * Console kernel output character routine. ! 635: */ ! 636: dcacnputc(dev, c) ! 637: dev_t dev; ! 638: register int c; ! 639: { ! 640: register struct dcadevice *dca = dca_addr[UNIT(dev)]; ! 641: register int timo; ! 642: short stat; ! 643: int s = splhigh(); ! 644: ! 645: #ifdef lint ! 646: stat = dev; if (stat) return; ! 647: #endif ! 648: if (dcaconsole == -1) { ! 649: (void) dcainit(UNIT(dev)); ! 650: dcaconsole = UNIT(dev); ! 651: } ! 652: /* wait for any pending transmission to finish */ ! 653: timo = 50000; ! 654: while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) ! 655: ; ! 656: dca->dca_data = c; ! 657: /* wait for this transmission to complete */ ! 658: timo = 1500000; ! 659: while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) ! 660: ; ! 661: /* clear any interrupts generated by this transmission */ ! 662: stat = dca->dca_iir; ! 663: splx(s); ! 664: } ! 665: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.