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