1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * from: @(#)com.c 7.5 (Berkeley) 5/16/91 34 * $Id: com.c,v 1.13 1993/09/29 02:36:21 cgd Exp $ 35 */ 36 37 #include "com.h" 38 #if NCOM > 0 39 /* 40 * COM driver, based on HP dca driver 41 * uses National Semiconductor NS16450/NS16550AF UART 42 */ 43 #include "param.h" 44 #include "systm.h" 45 #include "ioctl.h" 46 #include "select.h" 47 #include "tty.h" 48 #include "proc.h" 49 #include "user.h" 50 #include "conf.h" 51 #include "file.h" 52 #include "uio.h" 53 #include "kernel.h" 54 #include "syslog.h" 55 #include "types.h" 56 57 #include "i386/isa/isa_device.h" 58 #include "i386/isa/comreg.h" 59 #include "i386/isa/ic/ns16550.h" 60 #define cominor(d) 61 62 int comprobe(), comattach(), comintr(), comparam(); 63 void comstart(); 64 65 struct isa_driver comdriver = { 66 comprobe, comattach, "com" 67 }; 68 69 int comsoftCAR; 70 int com_active; 71 int com_hasfifo; 72 int ncom = NCOM; 73 #ifdef COMCONSOLE 74 int comconsole = COMCONSOLE; 75 #else 76 int comconsole = -1; 77 #endif 78 int comconsinit; 79 int comdefaultrate = TTYDEF_SPEED; 80 int commajor; 81 short com_addr[NCOM]; 82 struct tty *com_tty[NCOM]; 83 84 struct speedtab comspeedtab[] = { 85 0, 0, 86 50, COMBRD(50), 87 75, COMBRD(75), 88 110, COMBRD(110), 89 134, COMBRD(134), 90 150, COMBRD(150), 91 200, COMBRD(200), 92 300, COMBRD(300), 93 600, COMBRD(600), 94 1200, COMBRD(1200), 95 1800, COMBRD(1800), 96 2400, COMBRD(2400), 97 4800, COMBRD(4800), 98 9600, COMBRD(9600), 99 19200, COMBRD(19200), 100 38400, COMBRD(38400), 101 57600, COMBRD(57600), 102 -1, -1 103 }; 104 105 extern struct tty *constty; 106 #ifdef KGDB 107 #include "machine/remote-sl.h" 108 109 extern int kgdb_dev; 110 extern int kgdb_rate; 111 extern int kgdb_debug_init; 112 #endif 113 114 #define UNIT(x) (minor(x)) 115 116 comprobe(dev) 117 struct isa_device *dev; 118 { 119 /* force access to id reg */ 120 outb(dev->id_iobase+com_cfcr, 0); 121 outb(dev->id_iobase+com_iir, 0); 122 DELAY(100); 123 if ((inb(dev->id_iobase+com_iir) & 0x38) == 0) 124 return(8); 125 return(0); 126 } 127 128 129 int 130 comattach(isdp) 131 struct isa_device *isdp; 132 { 133 struct tty *tp; 134 u_char unit; 135 int port = isdp->id_iobase; 136 137 unit = isdp->id_unit; 138 if (unit == comconsole) 139 DELAY(1000); 140 com_addr[unit] = port; 141 com_active |= 1 << unit; 142 comsoftCAR |= 1 << unit; /* XXX */ 143 144 /* look for a NS 16550AF UART with FIFOs */ 145 outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4); 146 DELAY(100); 147 if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) { 148 com_hasfifo |= 1 << unit; 149 printf("com%d: fifo\n", isdp->id_unit); 150 } 151 152 outb(port+com_ier, 0); 153 outb(port+com_mcr, 0 | MCR_IENABLE); 154 #ifdef KGDB 155 if (kgdb_dev == makedev(commajor, unit)) { 156 if (comconsole == unit) 157 kgdb_dev = -1; /* can't debug over console port */ 158 else { 159 (void) cominit(unit, kgdb_rate); 160 if (kgdb_debug_init) { 161 /* 162 * Print prefix of device name, 163 * let kgdb_connect print the rest. 164 */ 165 printf("com%d: ", unit); 166 kgdb_connect(1); 167 } else 168 printf("com%d: kgdb enabled\n", unit); 169 } 170 } 171 #endif 172 /* 173 * Need to reset baud rate, etc. of next print so reset comconsinit. 174 * Also make sure console is always "hardwired" 175 */ 176 if (unit == comconsole) { 177 comconsinit = 0; 178 comsoftCAR |= (1 << unit); 179 } 180 return (1); 181 } 182 183 /* ARGSUSED */ 184 comopen(dev_t dev, int flag, int mode, struct proc *p) 185 { 186 register struct tty *tp; 187 register int unit; 188 int error = 0; 189 190 unit = UNIT(dev); 191 if (unit >= NCOM || (com_active & (1 << unit)) == 0) 192 return (ENXIO); 193 if(!com_tty[unit]) { 194 tp = com_tty[unit] = ttymalloc(); 195 } else 196 tp = com_tty[unit]; 197 tp->t_oproc = comstart; 198 tp->t_param = comparam; 199 tp->t_dev = dev; 200 if ((tp->t_state & TS_ISOPEN) == 0) { 201 tp->t_state |= TS_WOPEN; 202 ttychars(tp); 203 if (tp->t_ispeed == 0) { 204 tp->t_iflag = TTYDEF_IFLAG; 205 tp->t_oflag = TTYDEF_OFLAG; 206 tp->t_cflag = TTYDEF_CFLAG; 207 tp->t_lflag = TTYDEF_LFLAG; 208 tp->t_ispeed = tp->t_ospeed = comdefaultrate; 209 } 210 comparam(tp, &tp->t_termios); 211 ttsetwater(tp); 212 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 213 return (EBUSY); 214 (void) spltty(); 215 (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET); 216 if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD)) 217 tp->t_state |= TS_CARR_ON; 218 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 219 (tp->t_state & TS_CARR_ON) == 0) { 220 tp->t_state |= TS_WOPEN; 221 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 222 ttopen, 0)) 223 break; 224 } 225 (void) spl0(); 226 if (error == 0) 227 error = (*linesw[tp->t_line].l_open)(dev, tp); 228 return (error); 229 } 230 231 /*ARGSUSED*/ 232 comclose(dev, flag, mode, p) 233 dev_t dev; 234 int flag, mode; 235 struct proc *p; 236 { 237 register struct tty *tp; 238 register com; 239 register int unit; 240 241 unit = UNIT(dev); 242 com = com_addr[unit]; 243 tp = com_tty[unit]; 244 (*linesw[tp->t_line].l_close)(tp, flag); 245 outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 246 #ifdef KGDB 247 /* do not disable interrupts if debugging */ 248 if (kgdb_dev != makedev(commajor, unit)) 249 #endif 250 outb(com+com_ier, 0); 251 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 252 (tp->t_state&TS_ISOPEN) == 0) 253 (void) commctl(dev, 0, DMSET); 254 ttyclose(tp); 255 #ifdef broken /* session holds a ref to the tty; can't deallocate */ 256 ttyfree(tp); 257 com_tty[unit] = (struct tty *)NULL; 258 #endif 259 return(0); 260 } 261 262 comread(dev, uio, flag) 263 dev_t dev; 264 struct uio *uio; 265 { 266 register struct tty *tp = com_tty[UNIT(dev)]; 267 268 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 269 } 270 271 comwrite(dev, uio, flag) 272 dev_t dev; 273 struct uio *uio; 274 { 275 int unit = UNIT(dev); 276 register struct tty *tp = com_tty[unit]; 277 278 /* 279 * (XXX) We disallow virtual consoles if the physical console is 280 * a serial port. This is in case there is a display attached that 281 * is not the console. In that situation we don't need/want the X 282 * server taking over the console. 283 */ 284 if (constty && unit == comconsole) 285 constty = NULL; 286 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 287 } 288 289 comintr(unit) 290 register int unit; 291 { 292 register com; 293 register u_char code; 294 register struct tty *tp; 295 296 unit; 297 com = com_addr[unit]; 298 while (1) { 299 code = inb(com+com_iir); 300 switch (code & IIR_IMASK) { 301 case IIR_NOPEND: 302 return (1); 303 case IIR_RXTOUT: 304 case IIR_RXRDY: 305 tp = com_tty[unit]; 306 /* 307 * Process received bytes. Inline for speed... 308 */ 309 #ifdef KGDB 310 #define RCVBYTE() \ 311 code = inb(com+com_data); \ 312 if ((tp->t_state & TS_ISOPEN) == 0) { \ 313 if (kgdb_dev == makedev(commajor, unit) && \ 314 code == FRAME_END) \ 315 kgdb_connect(0); /* trap into kgdb */ \ 316 } else \ 317 (*linesw[tp->t_line].l_rint)(code, tp) 318 #else 319 #define RCVBYTE() \ 320 code = inb(com+com_data); \ 321 if (tp->t_state & TS_ISOPEN) \ 322 (*linesw[tp->t_line].l_rint)(code, tp) 323 #endif 324 325 RCVBYTE(); 326 327 if (com_hasfifo & (1 << unit)) 328 while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) { 329 if (code == LSR_RXRDY) { 330 RCVBYTE(); 331 } else 332 comeint(unit, code, com); 333 } 334 break; 335 case IIR_TXRDY: 336 tp = com_tty[unit]; 337 tp->t_state &=~ (TS_BUSY|TS_FLUSH); 338 if (tp->t_line) 339 (*linesw[tp->t_line].l_start)(tp); 340 else 341 comstart(tp); 342 break; 343 case IIR_RLS: 344 comeint(unit, inb(com+com_lsr), com); 345 break; 346 default: 347 if (code & IIR_NOPEND) 348 return (1); 349 log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n", 350 unit, code); 351 /* fall through */ 352 case IIR_MLSC: 353 commint(unit, com); 354 break; 355 } 356 } 357 } 358 359 comeint(unit, stat, com) 360 register int unit, stat; 361 register com; 362 { 363 register struct tty *tp; 364 register int c; 365 366 tp = com_tty[unit]; 367 c = inb(com+com_data); 368 if ((tp->t_state & TS_ISOPEN) == 0) { 369 #ifdef KGDB 370 /* we don't care about parity errors */ 371 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 372 kgdb_dev == makedev(commajor, unit) && c == FRAME_END) 373 kgdb_connect(0); /* trap into kgdb */ 374 #endif 375 return; 376 } 377 if (stat & (LSR_BI | LSR_FE)) 378 c |= TTY_FE; 379 else if (stat & LSR_PE) 380 c |= TTY_PE; 381 else if (stat & LSR_OE) { /* 30 Aug 92*/ 382 c |= TTY_PE; /* Ought to have it's own define... */ 383 log(LOG_WARNING, "com%d: silo overflow\n", unit); 384 } 385 (*linesw[tp->t_line].l_rint)(c, tp); 386 } 387 388 commint(unit, com) 389 register int unit; 390 register com; 391 { 392 register struct tty *tp; 393 register int stat; 394 395 tp = com_tty[unit]; 396 stat = inb(com+com_msr); 397 if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) { 398 if (stat & MSR_DCD) 399 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 400 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 401 outb(com+com_mcr, 402 inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE); 403 } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) && 404 (tp->t_flags & CRTSCTS)) { 405 /* the line is up and we want to do rts/cts flow control */ 406 if (stat & MSR_CTS) { 407 tp->t_state &=~ TS_TTSTOP; 408 ttstart(tp); 409 } else 410 tp->t_state |= TS_TTSTOP; 411 } 412 } 413 414 comioctl(dev, cmd, data, flag) 415 dev_t dev; 416 caddr_t data; 417 { 418 register struct tty *tp; 419 register int unit = UNIT(dev); 420 register com; 421 register int error; 422 423 tp = com_tty[unit]; 424 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 425 if (error >= 0) 426 return (error); 427 error = ttioctl(tp, cmd, data, flag); 428 if (error >= 0) 429 return (error); 430 431 com = com_addr[unit]; 432 switch (cmd) { 433 434 case TIOCSBRK: 435 outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK); 436 break; 437 438 case TIOCCBRK: 439 outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 440 break; 441 442 case TIOCSDTR: 443 (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS); 444 break; 445 446 case TIOCCDTR: 447 (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC); 448 break; 449 450 case TIOCMSET: 451 (void) commctl(dev, *(int *)data, DMSET); 452 break; 453 454 case TIOCMBIS: 455 (void) commctl(dev, *(int *)data, DMBIS); 456 break; 457 458 case TIOCMBIC: 459 (void) commctl(dev, *(int *)data, DMBIC); 460 break; 461 462 case TIOCMGET: 463 *(int *)data = commctl(dev, 0, DMGET); 464 break; 465 466 default: 467 return (ENOTTY); 468 } 469 return (0); 470 } 471 472 comparam(tp, t) 473 register struct tty *tp; 474 register struct termios *t; 475 { 476 register com; 477 register int cfcr, cflag = t->c_cflag; 478 int unit = UNIT(tp->t_dev); 479 int ospeed = ttspeedtab(t->c_ospeed, comspeedtab); 480 481 /* check requested parameters */ 482 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 483 return(EINVAL); 484 /* and copy to tty */ 485 tp->t_ispeed = t->c_ispeed; 486 tp->t_ospeed = t->c_ospeed; 487 tp->t_cflag = cflag; 488 489 com = com_addr[unit]; 490 outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/); 491 if (ospeed == 0) { 492 (void) commctl(unit, 0, DMSET); /* hang up line */ 493 return(0); 494 } 495 outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB); 496 outb(com+com_data, ospeed & 0xFF); 497 outb(com+com_ier, ospeed >> 8); 498 switch (cflag&CSIZE) { 499 case CS5: 500 cfcr = CFCR_5BITS; break; 501 case CS6: 502 cfcr = CFCR_6BITS; break; 503 case CS7: 504 cfcr = CFCR_7BITS; break; 505 case CS8: 506 cfcr = CFCR_8BITS; break; 507 } 508 if (cflag&PARENB) { 509 cfcr |= CFCR_PENAB; 510 if ((cflag&PARODD) == 0) 511 cfcr |= CFCR_PEVEN; 512 } 513 if (cflag&CSTOPB) 514 cfcr |= CFCR_STOPB; 515 outb(com+com_cfcr, cfcr); 516 517 if (com_hasfifo & (1 << unit)) 518 outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_4); 519 520 return(0); 521 } 522 523 void 524 comstart(tp) 525 register struct tty *tp; 526 { 527 register com; 528 int s, unit, c; 529 530 unit = UNIT(tp->t_dev); 531 com = com_addr[unit]; 532 s = spltty(); 533 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 534 goto out; 535 if (tp->t_outq.c_cc <= tp->t_lowat) { 536 if (tp->t_state&TS_ASLEEP) { 537 tp->t_state &= ~TS_ASLEEP; 538 wakeup((caddr_t)&tp->t_outq); 539 } 540 selwakeup(&tp->t_wsel); 541 } 542 if (tp->t_outq.c_cc == 0) 543 goto out; 544 if (inb(com+com_lsr) & LSR_TXRDY) { 545 c = getc(&tp->t_outq); 546 tp->t_state |= TS_BUSY; 547 outb(com+com_data, c); 548 if (com_hasfifo & (1 << unit)) 549 for (c = 1; c < 16 && tp->t_outq.c_cc; ++c) 550 outb(com+com_data, getc(&tp->t_outq)); 551 } 552 out: 553 splx(s); 554 } 555 556 /* 557 * Stop output on a line. 558 */ 559 /*ARGSUSED*/ 560 comstop(tp, flag) 561 register struct tty *tp; 562 { 563 register int s; 564 565 s = spltty(); 566 if (tp->t_state & TS_BUSY) { 567 if ((tp->t_state&TS_TTSTOP)==0) 568 tp->t_state |= TS_FLUSH; 569 } 570 splx(s); 571 } 572 573 commctl(dev, bits, how) 574 dev_t dev; 575 int bits, how; 576 { 577 register com; 578 register int unit; 579 int s; 580 581 unit = UNIT(dev); 582 com = com_addr[unit]; 583 s = spltty(); 584 switch (how) { 585 586 case DMSET: 587 outb(com+com_mcr, bits | MCR_IENABLE); 588 break; 589 590 case DMBIS: 591 outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE); 592 break; 593 594 case DMBIC: 595 outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE); 596 break; 597 598 case DMGET: 599 bits = inb(com+com_msr); 600 break; 601 } 602 (void) splx(s); 603 return(bits); 604 } 605 606 /* 607 * Following are all routines needed for COM to act as console 608 */ 609 #include "i386/i386/cons.h" 610 611 comcnprobe(cp) 612 struct consdev *cp; 613 { 614 int unit; 615 616 /* locate the major number */ 617 for (commajor = 0; commajor < nchrdev; commajor++) 618 if (cdevsw[commajor].d_open == comopen) 619 break; 620 621 /* XXX: ick */ 622 unit = CONUNIT; 623 com_addr[CONUNIT] = CONADDR; 624 625 /* make sure hardware exists? XXX */ 626 627 /* initialize required fields */ 628 cp->cn_dev = makedev(commajor, unit); 629 #ifdef COMCONSOLE 630 cp->cn_pri = CN_REMOTE; /* Force a serial port console */ 631 #else 632 cp->cn_pri = CN_NORMAL; 633 #endif 634 } 635 636 comcninit(cp) 637 struct consdev *cp; 638 { 639 int unit = UNIT(cp->cn_dev); 640 641 cominit(unit, comdefaultrate); 642 comconsole = unit; 643 comconsinit = 1; 644 } 645 646 cominit(unit, rate) 647 int unit, rate; 648 { 649 register int com; 650 int s; 651 short stat; 652 653 #ifdef lint 654 stat = unit; if (stat) return; 655 #endif 656 com = com_addr[unit]; 657 s = splhigh(); 658 outb(com+com_cfcr, CFCR_DLAB); 659 rate = ttspeedtab(comdefaultrate, comspeedtab); 660 outb(com+com_data, rate & 0xFF); 661 outb(com+com_ier, rate >> 8); 662 outb(com+com_cfcr, CFCR_8BITS); 663 outb(com+com_ier, IER_ERXRDY | IER_ETXRDY); 664 outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4); 665 stat = inb(com+com_iir); 666 splx(s); 667 } 668 669 comcngetc(dev) 670 { 671 register com = com_addr[UNIT(dev)]; 672 short stat; 673 int c, s; 674 675 #ifdef lint 676 stat = dev; if (stat) return(0); 677 #endif 678 s = splhigh(); 679 while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0) 680 ; 681 c = inb(com+com_data); 682 stat = inb(com+com_iir); 683 splx(s); 684 return(c); 685 } 686 687 /* 688 * Console kernel output character routine. 689 */ 690 comcnputc(dev, c) 691 dev_t dev; 692 register int c; 693 { 694 register com = com_addr[UNIT(dev)]; 695 register int timo; 696 short stat; 697 int s = splhigh(); 698 699 #ifdef lint 700 stat = dev; if (stat) return; 701 #endif 702 #ifdef KGDB 703 if (dev != kgdb_dev) 704 #endif 705 if (comconsinit == 0) { 706 (void) cominit(UNIT(dev), comdefaultrate); 707 comconsinit = 1; 708 } 709 /* wait for any pending transmission to finish */ 710 timo = 50000; 711 while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 712 ; 713 outb(com+com_data, c); 714 /* wait for this transmission to complete */ 715 timo = 1500000; 716 while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 717 ; 718 /* clear any interrupts generated by this transmission */ 719 stat = inb(com+com_iir); 720 splx(s); 721 } 722 723 int 724 comselect(dev, rw, p) 725 dev_t dev; 726 int rw; 727 struct proc *p; 728 { 729 register struct tty *tp = com_tty[UNIT(dev)]; 730 int nread; 731 int s = spltty(); 732 struct proc *selp; 733 734 switch (rw) { 735 736 case FREAD: 737 nread = ttnread(tp); 738 if (nread > 0 || 739 ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 740 goto win; 741 selrecord(p, &tp->t_rsel); 742 break; 743 744 case FWRITE: 745 if (tp->t_outq.c_cc <= tp->t_lowat) 746 goto win; 747 selrecord(p, &tp->t_wsel); 748 break; 749 } 750 splx(s); 751 return (0); 752 win: 753 splx(s); 754 return (1); 755 } 756 757 #endif 758