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