xref: /csrg-svn/sys/kern/tty.c (revision 6216)
1*6216Swnj /*	tty.c	4.22	82/03/15	*/
239Sbill 
339Sbill /*
4903Sbill  * TTY subroutines common to more than one line discipline
539Sbill  */
639Sbill #include "../h/param.h"
739Sbill #include "../h/systm.h"
839Sbill #include "../h/dir.h"
939Sbill #include "../h/user.h"
1039Sbill #include "../h/tty.h"
1139Sbill #include "../h/proc.h"
1239Sbill #include "../h/inode.h"
1339Sbill #include "../h/file.h"
1439Sbill #include "../h/reg.h"
1539Sbill #include "../h/conf.h"
1639Sbill #include "../h/buf.h"
17340Sbill #include "../h/dk.h"
1839Sbill 
1939Sbill char	partab[];
2039Sbill 
21146Sbill /*
2239Sbill  * Input mapping table-- if an entry is non-zero, when the
2339Sbill  * corresponding character is typed preceded by "\" the escape
2439Sbill  * sequence is replaced by the table value.  Mostly used for
2539Sbill  * upper-case only terminals.
2639Sbill  */
2739Sbill 
2839Sbill char	maptab[] ={
2939Sbill 	000,000,000,000,000,000,000,000,
3039Sbill 	000,000,000,000,000,000,000,000,
3139Sbill 	000,000,000,000,000,000,000,000,
3239Sbill 	000,000,000,000,000,000,000,000,
3339Sbill 	000,'|',000,000,000,000,000,'`',
3439Sbill 	'{','}',000,000,000,000,000,000,
3539Sbill 	000,000,000,000,000,000,000,000,
3639Sbill 	000,000,000,000,000,000,000,000,
3739Sbill 	000,000,000,000,000,000,000,000,
3839Sbill 	000,000,000,000,000,000,000,000,
3939Sbill 	000,000,000,000,000,000,000,000,
4039Sbill 	000,000,000,000,000,000,'~',000,
4139Sbill 	000,'A','B','C','D','E','F','G',
4239Sbill 	'H','I','J','K','L','M','N','O',
4339Sbill 	'P','Q','R','S','T','U','V','W',
4439Sbill 	'X','Y','Z',000,000,000,000,000,
4539Sbill };
4639Sbill 
47925Sbill short	tthiwat[16] =
48925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
49925Sbill short	ttlowat[16] =
50925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
51925Sbill 
5239Sbill #define	OBUFSIZ	100
5339Sbill 
5439Sbill /*
5539Sbill  * set default control characters.
5639Sbill  */
5739Sbill ttychars(tp)
5839Sbill register struct tty *tp;
5939Sbill {
60174Sbill 
6139Sbill 	tun.t_intrc = CINTR;
6239Sbill 	tun.t_quitc = CQUIT;
6339Sbill 	tun.t_startc = CSTART;
6439Sbill 	tun.t_stopc = CSTOP;
6539Sbill 	tun.t_eofc = CEOT;
6639Sbill 	tun.t_brkc = CBRK;
6739Sbill 	tp->t_erase = CERASE;
6839Sbill 	tp->t_kill = CKILL;
69174Sbill /* begin local */
70208Sbill 	tlun.t_suspc = CTRL(z);
71208Sbill 	tlun.t_dsuspc = CTRL(y);
72174Sbill 	tlun.t_rprntc = CTRL(r);
73174Sbill 	tlun.t_flushc = CTRL(o);
74174Sbill 	tlun.t_werasc = CTRL(w);
75174Sbill 	tlun.t_lnextc = CTRL(v);
76174Sbill 	tp->t_local = 0;
77174Sbill 	tp->t_lstate = 0;
78174Sbill /* end local */
7939Sbill }
8039Sbill 
8139Sbill /*
82903Sbill  * Wait for output to drain, then flush input waiting.
8339Sbill  */
84903Sbill wflushtty(tp)
855408Swnj 	register struct tty *tp;
8639Sbill {
8739Sbill 
88903Sbill 	(void) spl5();
895622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
905622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
91903Sbill 		(*tp->t_oproc)(tp);
925408Swnj 		tp->t_state |= TS_ASLEEP;
93903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
94903Sbill 	}
955426Swnj 	flushtty(tp, FREAD);
96903Sbill 	(void) spl0();
9739Sbill }
9839Sbill 
9939Sbill /*
100903Sbill  * flush all TTY queues
10139Sbill  */
102903Sbill flushtty(tp, rw)
103903Sbill register struct tty *tp;
10439Sbill {
105903Sbill 	register s;
106903Sbill 
107903Sbill 	s = spl6();
108903Sbill 	if (rw & FREAD) {
109903Sbill 		while (getc(&tp->t_canq) >= 0)
110903Sbill 			;
111903Sbill 		wakeup((caddr_t)&tp->t_rawq);
112903Sbill 	}
113903Sbill 	if (rw & FWRITE) {
114903Sbill 		wakeup((caddr_t)&tp->t_outq);
1155408Swnj 		tp->t_state &= ~TS_TTSTOP;
1165426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
117903Sbill 		while (getc(&tp->t_outq) >= 0)
118903Sbill 			;
119903Sbill 	}
120903Sbill 	if (rw & FREAD) {
121903Sbill 		while (getc(&tp->t_rawq) >= 0)
122903Sbill 			;
123903Sbill 		tp->t_delct = 0;
124903Sbill 		tp->t_rocount = 0;		/* local */
125903Sbill 		tp->t_rocol = 0;
126903Sbill 		tp->t_lstate = 0;
127903Sbill 	}
128903Sbill 	splx(s);
12939Sbill }
13039Sbill 
131903Sbill /*
132903Sbill  * Send stop character on input overflow.
133903Sbill  */
134903Sbill ttyblock(tp)
135903Sbill register struct tty *tp;
13639Sbill {
137903Sbill 	register x;
138903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
139903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
140903Sbill 		flushtty(tp, FREAD|FWRITE);
1415408Swnj 		tp->t_state &= ~TS_TBLOCK;
142903Sbill 	}
143903Sbill 	if (x >= TTYHOG/2) {
144903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
1455408Swnj 			tp->t_state |= TS_TBLOCK;
146903Sbill 			tp->t_char++;
147903Sbill 			ttstart(tp);
148903Sbill 		}
149903Sbill 	}
15039Sbill }
15139Sbill 
15239Sbill /*
153903Sbill  * Restart typewriter output following a delay
154903Sbill  * timeout.
155903Sbill  * The name of the routine is passed to the timeout
156903Sbill  * subroutine and it is called during a clock interrupt.
157121Sbill  */
158903Sbill ttrstrt(tp)
159121Sbill register struct tty *tp;
160121Sbill {
161121Sbill 
1623351Swnj 	if (tp == 0) {
1633351Swnj 		printf("ttrstrt: arg was 0!\n");
1643351Swnj 		return;
1653351Swnj 	}
1665408Swnj 	tp->t_state &= ~TS_TIMEOUT;
167903Sbill 	ttstart(tp);
168121Sbill }
169121Sbill 
170121Sbill /*
171903Sbill  * Start output on the typewriter. It is used from the top half
172903Sbill  * after some characters have been put on the output queue,
173903Sbill  * from the interrupt routine to transmit the next
174903Sbill  * character, and after a timeout has finished.
17539Sbill  */
176903Sbill ttstart(tp)
177903Sbill register struct tty *tp;
17839Sbill {
179903Sbill 	register s;
18039Sbill 
181903Sbill 	s = spl5();
1825622Swnj 	if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
1835622Swnj 	    tp->t_oproc)		/* kludge for pty */
184903Sbill 		(*tp->t_oproc)(tp);
185903Sbill 	splx(s);
18639Sbill }
18739Sbill 
18839Sbill /*
189903Sbill  * Common code for tty ioctls.
19039Sbill  */
1911780Sbill /*ARGSUSED*/
1921904Swnj ttioctl(tp, com, addr, flag)
19339Sbill register struct tty *tp;
19439Sbill caddr_t addr;
19539Sbill {
1961904Swnj 	int dev;
19739Sbill 	unsigned t;
198174Sbill 	struct sgttyb iocb;
199191Sbill 	struct clist tq;
20039Sbill 	extern int nldisp;
201887Sbill 	register c;
202728Sbill 	int temp;
20339Sbill 
204903Sbill 	/*
205915Sbill 	 * This is especially so that isatty() will
206915Sbill 	 * fail when carrier is gone.
207915Sbill 	 */
2085408Swnj 	if ((tp->t_state&TS_CARR_ON) == 0) {
209915Sbill 		u.u_error = EBADF;
210915Sbill 		return (1);
211915Sbill 	}
212915Sbill 
2131904Swnj 	dev = tp->t_dev;
214915Sbill 	/*
215903Sbill 	 * If the ioctl involves modification,
216903Sbill 	 * insist on being able to write the device,
217903Sbill 	 * and hang if in the background.
218903Sbill 	 */
21939Sbill 	switch(com) {
22039Sbill 
221915Sbill 	case TIOCSETD:
222915Sbill 	case TIOCSETP:
223915Sbill 	case TIOCSETN:
224903Sbill 	case TIOCFLUSH:
225903Sbill 	case TIOCSETC:
226903Sbill 	case TIOCSLTC:
227903Sbill 	case TIOCSPGRP:
228903Sbill 	case TIOCLBIS:
229903Sbill 	case TIOCLBIC:
230903Sbill 	case TIOCLSET:
231903Sbill 	case TIOCSTI:
232915Sbill /* this is reasonable, but impractical...
233903Sbill 		if ((flag & FWRITE) == 0) {
234903Sbill 			u.u_error = EBADF;
235903Sbill 			return (1);
236903Sbill 		}
237915Sbill  */
238903Sbill 		while (tp->t_line == NTTYDISC &&
239903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
240903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
241903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2425626Swnj 		   u.u_signal[SIGTTOU] != SIG_HOLD
2435626Swnj /*
2445626Swnj 						   &&
245903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
2465626Swnj */
2475626Swnj 		   ) {
248903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
249903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
250903Sbill 		}
251903Sbill 		break;
252903Sbill 	}
253903Sbill 
25439Sbill 	/*
255903Sbill 	 * Process the ioctl.
25639Sbill 	 */
257903Sbill 	switch(com) {
258903Sbill 
259903Sbill 	/*
260903Sbill 	 * Get discipline number
261903Sbill 	 */
26239Sbill 	case TIOCGETD:
26339Sbill 		t = tp->t_line;
26439Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
26539Sbill 			u.u_error = EFAULT;
26639Sbill 		break;
26739Sbill 
26839Sbill 	/*
269903Sbill 	 * Set line discipline
27039Sbill 	 */
27139Sbill 	case TIOCSETD:
27239Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
27339Sbill 			u.u_error = EFAULT;
27439Sbill 			break;
27539Sbill 		}
27639Sbill 		if (t >= nldisp) {
27739Sbill 			u.u_error = ENXIO;
27839Sbill 			break;
27939Sbill 		}
280174Sbill 		(void) spl5();
28139Sbill 		if (tp->t_line)
28239Sbill 			(*linesw[tp->t_line].l_close)(tp);
28339Sbill 		if (t)
28439Sbill 			(*linesw[t].l_open)(dev, tp, addr);
28539Sbill 		if (u.u_error==0)
28639Sbill 			tp->t_line = t;
287174Sbill 		(void) spl0();
28839Sbill 		break;
28939Sbill 
29039Sbill 	/*
2915614Swnj 	 * Prevent more opens on channel
2925614Swnj 	 */
2935614Swnj 	case TIOCEXCL:
2945614Swnj 		tp->t_state |= TS_XCLUDE;
2955614Swnj 		break;
2965614Swnj 
2975614Swnj 	case TIOCNXCL:
2985614Swnj 		tp->t_state &= ~TS_XCLUDE;
2995614Swnj 		break;
3005614Swnj 
3015614Swnj 	/*
30239Sbill 	 * Set new parameters
30339Sbill 	 */
30439Sbill 	case TIOCSETP:
305191Sbill 	case TIOCSETN:
30639Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
30739Sbill 			u.u_error = EFAULT;
30839Sbill 			return(1);
30939Sbill 		}
310121Sbill 		(void) spl5();
3114484Swnj 		if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
3124484Swnj 		    com == TIOCSETP)
3134484Swnj 			wflushtty(tp);
3144484Swnj 		else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
3154484Swnj 			if (iocb.sg_flags & CBREAK) {
3164484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3174484Swnj 				tq = tp->t_rawq;
3184484Swnj 				tp->t_rawq = tp->t_canq;
3194484Swnj 				tp->t_canq = tq;
3204484Swnj 			} else {
3214484Swnj 				tp->t_local |= LPENDIN;
3224484Swnj 				ttwakeup(tp);
323174Sbill 			}
324174Sbill 		}
3254484Swnj 		tp->t_ispeed = iocb.sg_ispeed;
3264484Swnj 		tp->t_ospeed = iocb.sg_ospeed;
327174Sbill 		tp->t_erase = iocb.sg_erase;
328174Sbill 		tp->t_kill = iocb.sg_kill;
329174Sbill 		tp->t_flags = iocb.sg_flags;
3303941Sbugs 		if (tp->t_flags & RAW) {
3315408Swnj 			tp->t_state &= ~TS_TTSTOP;
3323941Sbugs 			ttstart(tp);
3333941Sbugs 		}
334121Sbill 		(void) spl0();
33539Sbill 		break;
33639Sbill 
33739Sbill 	/*
338903Sbill 	 * Send current parameters to user
33939Sbill 	 */
34039Sbill 	case TIOCGETP:
341174Sbill 		iocb.sg_ispeed = tp->t_ispeed;
342174Sbill 		iocb.sg_ospeed = tp->t_ospeed;
343174Sbill 		iocb.sg_erase = tp->t_erase;
344174Sbill 		iocb.sg_kill = tp->t_kill;
345174Sbill 		iocb.sg_flags = tp->t_flags;
34639Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
34739Sbill 			u.u_error = EFAULT;
34839Sbill 		break;
34939Sbill 
35039Sbill 	/*
35139Sbill 	 * Hang up line on last close
35239Sbill 	 */
35339Sbill 	case TIOCHPCL:
3545408Swnj 		tp->t_state |= TS_HUPCLS;
35539Sbill 		break;
35639Sbill 
3573942Sbugs 	case TIOCFLUSH: {
3583942Sbugs 		int flags;
3593942Sbugs 		if (addr == 0)
3603942Sbugs 			flags = FREAD|FWRITE;
3613942Sbugs 		else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
3623942Sbugs 			u.u_error = EFAULT;
3633983Sroot 			return(1);
3643942Sbugs 		}
3653942Sbugs 		flushtty(tp, flags);
36639Sbill 		break;
3673944Sbugs 	}
36839Sbill 
3695408Swnj 	case FIONBIO: {
3705408Swnj 		int nbio;
3715408Swnj 		if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
3725408Swnj 			u.u_error = EFAULT;
3735408Swnj 			return(1);
3745408Swnj 		}
3755408Swnj 		if (nbio)
3765408Swnj 			tp->t_state |= TS_NBIO;
3775408Swnj 		else
3785408Swnj 			tp->t_state &= ~TS_NBIO;
3795408Swnj 		break;
3805408Swnj 	}
3815408Swnj 
382*6216Swnj 	case FIOASYNC: {
383*6216Swnj 		int async;
384*6216Swnj 		if (copyin(addr, (caddr_t)&async, sizeof (async))) {
385*6216Swnj 			u.u_error = EFAULT;
386*6216Swnj 			return(1);
387*6216Swnj 		}
388*6216Swnj 		if (async)
389*6216Swnj 			tp->t_state |= TS_ASYNC;
390*6216Swnj 		else
391*6216Swnj 			tp->t_state &= ~TS_ASYNC;
392*6216Swnj 		break;
393*6216Swnj 	}
394*6216Swnj 
39539Sbill 	/*
396903Sbill 	 * Set and fetch special characters
39739Sbill 	 */
39839Sbill 	case TIOCSETC:
399174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
40039Sbill 			u.u_error = EFAULT;
40139Sbill 		break;
40239Sbill 
40339Sbill 	case TIOCGETC:
404174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
40539Sbill 			u.u_error = EFAULT;
40639Sbill 		break;
40739Sbill 
408174Sbill /* local ioctls */
409903Sbill 	/*
410903Sbill 	 * Set/get local special characters.
411903Sbill 	 */
412174Sbill 	case TIOCSLTC:
413174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
414174Sbill 			u.u_error = EFAULT;
415174Sbill 		break;
416174Sbill 
417174Sbill 	case TIOCGLTC:
418174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
419174Sbill 			u.u_error = EFAULT;
420174Sbill 		break;
421174Sbill 
422903Sbill 	/*
423903Sbill 	 * Return number of characters immediately available.
424903Sbill 	 */
425174Sbill 	case FIONREAD: {
4264484Swnj 		off_t nread = ttnread(tp);
427174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
428174Sbill 			u.u_error = EFAULT;
429174Sbill 		break;
430174Sbill 		}
431174Sbill 
432174Sbill 	/*
433174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
434174Sbill 	 */
435174Sbill 	case TIOCSPGRP:
436728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
437728Sbill 			u.u_error = EFAULT;
438174Sbill 		break;
439174Sbill 
440174Sbill 	case TIOCGPGRP:
441174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
442174Sbill 			u.u_error = EFAULT;
443174Sbill 		break;
444174Sbill 
445174Sbill 	/*
446174Sbill 	 * Modify local mode word.
447174Sbill 	 */
448174Sbill 	case TIOCLBIS:
449728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
450728Sbill 			u.u_error = EFAULT;
451728Sbill 		else
452728Sbill 			tp->t_local |= temp;
453174Sbill 		break;
454174Sbill 
455174Sbill 	case TIOCLBIC:
456728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
457728Sbill 			u.u_error = EFAULT;
458728Sbill 		else
459728Sbill 			tp->t_local &= ~temp;
460174Sbill 		break;
461174Sbill 
462174Sbill 	case TIOCLSET:
463728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
464728Sbill 			u.u_error = EFAULT;
465728Sbill 		else
466728Sbill 			tp->t_local = temp;
467174Sbill 		break;
468174Sbill 
469174Sbill 	case TIOCLGET:
470174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
471174Sbill 			u.u_error = EFAULT;
472174Sbill 		break;
473174Sbill 
474903Sbill 	/*
475903Sbill 	 * Return number of characters in
476903Sbill 	 * the output.
477903Sbill 	 */
478213Sbill 	case TIOCOUTQ:
479213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
480213Sbill 			u.u_error = EFAULT;
481213Sbill 		break;
482213Sbill 
483903Sbill 	/*
484903Sbill 	 * Simulate typing of a character at the terminal.
485903Sbill 	 */
486887Sbill 	case TIOCSTI:
487887Sbill 		c = fubyte(addr);
488887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
489887Sbill 			u.u_error = EFAULT;
490887Sbill 		else
491887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
492887Sbill 		break;
4935573Swnj 
4945573Swnj 	case TIOCSTOP:
4955573Swnj 		c = spl5();
4965573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4975573Swnj 			tp->t_state |= TS_TTSTOP;
4985573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4995573Swnj 		}
5005573Swnj 		splx(c);
5015573Swnj 		break;
5025573Swnj 
5035573Swnj 	case TIOCSTART:
5045573Swnj 		c = spl5();
5055573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
5065573Swnj 			tp->t_state &= ~TS_TTSTOP;
5075573Swnj 			tp->t_local &= ~LFLUSHO;
5085573Swnj 			ttstart(tp);
5095573Swnj 		}
5105573Swnj 		splx(c);
5115573Swnj 		break;
5125573Swnj 
513174Sbill /* end of locals */
514887Sbill 
51539Sbill 	default:
51639Sbill 		return(0);
51739Sbill 	}
51839Sbill 	return(1);
51939Sbill }
5204484Swnj 
5214484Swnj ttnread(tp)
5224484Swnj 	struct tty *tp;
5234484Swnj {
5244484Swnj 	int nread = 0;
5254484Swnj 
5264484Swnj 	if (tp->t_local & LPENDIN)
5274484Swnj 		ttypend(tp);
5284484Swnj 	nread = tp->t_canq.c_cc;
5294484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5304484Swnj 		nread += tp->t_rawq.c_cc;
5314484Swnj 	return (nread);
5324484Swnj }
5334484Swnj 
5345408Swnj ttselect(dev, rw)
5354484Swnj 	dev_t dev;
5365408Swnj 	int rw;
5374484Swnj {
5384484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5394484Swnj 	int nread;
5405408Swnj 	int s = spl5();
5414484Swnj 
5425408Swnj 	switch (rw) {
5434484Swnj 
5444484Swnj 	case FREAD:
5454484Swnj 		nread = ttnread(tp);
5464484Swnj 		if (nread > 0)
5475408Swnj 			goto win;
5484938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5495408Swnj 			tp->t_state |= TS_RCOLL;
5504484Swnj 		else
5514484Swnj 			tp->t_rsel = u.u_procp;
5525408Swnj 		break;
5534484Swnj 
5545408Swnj 	case FWRITE:
5555408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5565408Swnj 			goto win;
5575408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5585408Swnj 			tp->t_state |= TS_WCOLL;
5595408Swnj 		else
5605408Swnj 			tp->t_wsel = u.u_procp;
5615408Swnj 		break;
5624484Swnj 	}
5635408Swnj 	splx(s);
5645408Swnj 	return (0);
5655408Swnj win:
5665408Swnj 	splx(s);
5675408Swnj 	return (1);
5684484Swnj }
569