xref: /csrg-svn/sys/kern/tty.c (revision 5626)
1*5626Swnj /*	tty.c	4.21	82/01/30	*/
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 &&
242*5626Swnj 		   u.u_signal[SIGTTOU] != SIG_HOLD
243*5626Swnj /*
244*5626Swnj 						   &&
245903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
246*5626Swnj */
247*5626Swnj 		   ) {
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 
38239Sbill 	/*
383903Sbill 	 * Set and fetch special characters
38439Sbill 	 */
38539Sbill 	case TIOCSETC:
386174Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
38739Sbill 			u.u_error = EFAULT;
38839Sbill 		break;
38939Sbill 
39039Sbill 	case TIOCGETC:
391174Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
39239Sbill 			u.u_error = EFAULT;
39339Sbill 		break;
39439Sbill 
395174Sbill /* local ioctls */
396903Sbill 	/*
397903Sbill 	 * Set/get local special characters.
398903Sbill 	 */
399174Sbill 	case TIOCSLTC:
400174Sbill 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
401174Sbill 			u.u_error = EFAULT;
402174Sbill 		break;
403174Sbill 
404174Sbill 	case TIOCGLTC:
405174Sbill 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
406174Sbill 			u.u_error = EFAULT;
407174Sbill 		break;
408174Sbill 
409903Sbill 	/*
410903Sbill 	 * Return number of characters immediately available.
411903Sbill 	 */
412174Sbill 	case FIONREAD: {
4134484Swnj 		off_t nread = ttnread(tp);
414174Sbill 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
415174Sbill 			u.u_error = EFAULT;
416174Sbill 		break;
417174Sbill 		}
418174Sbill 
419174Sbill 	/*
420174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
421174Sbill 	 */
422174Sbill 	case TIOCSPGRP:
423728Sbill 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
424728Sbill 			u.u_error = EFAULT;
425174Sbill 		break;
426174Sbill 
427174Sbill 	case TIOCGPGRP:
428174Sbill 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
429174Sbill 			u.u_error = EFAULT;
430174Sbill 		break;
431174Sbill 
432174Sbill 	/*
433174Sbill 	 * Modify local mode word.
434174Sbill 	 */
435174Sbill 	case TIOCLBIS:
436728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
437728Sbill 			u.u_error = EFAULT;
438728Sbill 		else
439728Sbill 			tp->t_local |= temp;
440174Sbill 		break;
441174Sbill 
442174Sbill 	case TIOCLBIC:
443728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
444728Sbill 			u.u_error = EFAULT;
445728Sbill 		else
446728Sbill 			tp->t_local &= ~temp;
447174Sbill 		break;
448174Sbill 
449174Sbill 	case TIOCLSET:
450728Sbill 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
451728Sbill 			u.u_error = EFAULT;
452728Sbill 		else
453728Sbill 			tp->t_local = temp;
454174Sbill 		break;
455174Sbill 
456174Sbill 	case TIOCLGET:
457174Sbill 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
458174Sbill 			u.u_error = EFAULT;
459174Sbill 		break;
460174Sbill 
461903Sbill 	/*
462903Sbill 	 * Return number of characters in
463903Sbill 	 * the output.
464903Sbill 	 */
465213Sbill 	case TIOCOUTQ:
466213Sbill 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
467213Sbill 			u.u_error = EFAULT;
468213Sbill 		break;
469213Sbill 
470903Sbill 	/*
471903Sbill 	 * Simulate typing of a character at the terminal.
472903Sbill 	 */
473887Sbill 	case TIOCSTI:
474887Sbill 		c = fubyte(addr);
475887Sbill 		if (u.u_uid && u.u_ttyp != tp || c < 0)
476887Sbill 			u.u_error = EFAULT;
477887Sbill 		else
478887Sbill 			(*linesw[tp->t_line].l_rint)(c, tp);
479887Sbill 		break;
4805573Swnj 
4815573Swnj 	case TIOCSTOP:
4825573Swnj 		c = spl5();
4835573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4845573Swnj 			tp->t_state |= TS_TTSTOP;
4855573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4865573Swnj 		}
4875573Swnj 		splx(c);
4885573Swnj 		break;
4895573Swnj 
4905573Swnj 	case TIOCSTART:
4915573Swnj 		c = spl5();
4925573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4935573Swnj 			tp->t_state &= ~TS_TTSTOP;
4945573Swnj 			tp->t_local &= ~LFLUSHO;
4955573Swnj 			ttstart(tp);
4965573Swnj 		}
4975573Swnj 		splx(c);
4985573Swnj 		break;
4995573Swnj 
500174Sbill /* end of locals */
501887Sbill 
50239Sbill 	default:
50339Sbill 		return(0);
50439Sbill 	}
50539Sbill 	return(1);
50639Sbill }
5074484Swnj 
5084484Swnj ttnread(tp)
5094484Swnj 	struct tty *tp;
5104484Swnj {
5114484Swnj 	int nread = 0;
5124484Swnj 
5134484Swnj 	if (tp->t_local & LPENDIN)
5144484Swnj 		ttypend(tp);
5154484Swnj 	nread = tp->t_canq.c_cc;
5164484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5174484Swnj 		nread += tp->t_rawq.c_cc;
5184484Swnj 	return (nread);
5194484Swnj }
5204484Swnj 
5215408Swnj ttselect(dev, rw)
5224484Swnj 	dev_t dev;
5235408Swnj 	int rw;
5244484Swnj {
5254484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5264484Swnj 	int nread;
5275408Swnj 	int s = spl5();
5284484Swnj 
5295408Swnj 	switch (rw) {
5304484Swnj 
5314484Swnj 	case FREAD:
5324484Swnj 		nread = ttnread(tp);
5334484Swnj 		if (nread > 0)
5345408Swnj 			goto win;
5354938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5365408Swnj 			tp->t_state |= TS_RCOLL;
5374484Swnj 		else
5384484Swnj 			tp->t_rsel = u.u_procp;
5395408Swnj 		break;
5404484Swnj 
5415408Swnj 	case FWRITE:
5425408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5435408Swnj 			goto win;
5445408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5455408Swnj 			tp->t_state |= TS_WCOLL;
5465408Swnj 		else
5475408Swnj 			tp->t_wsel = u.u_procp;
5485408Swnj 		break;
5494484Swnj 	}
5505408Swnj 	splx(s);
5515408Swnj 	return (0);
5525408Swnj win:
5535408Swnj 	splx(s);
5545408Swnj 	return (1);
5554484Swnj }
556