Home | History | Annotate | Line # | Download | only in kern
tty.c revision 1.1.1.3
      1  1.1.1.2  fvdl /*-
      2  1.1.1.2  fvdl  * Copyright (c) 1982, 1986, 1990, 1991, 1993
      3  1.1.1.2  fvdl  *	The Regents of the University of California.  All rights reserved.
      4  1.1.1.2  fvdl  * (c) UNIX System Laboratories, Inc.
      5  1.1.1.2  fvdl  * All or some portions of this file are derived from material licensed
      6  1.1.1.2  fvdl  * to the University of California by American Telephone and Telegraph
      7  1.1.1.2  fvdl  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      8  1.1.1.2  fvdl  * the permission of UNIX System Laboratories, Inc.
      9  1.1.1.2  fvdl  *
     10  1.1.1.2  fvdl  * Redistribution and use in source and binary forms, with or without
     11  1.1.1.2  fvdl  * modification, are permitted provided that the following conditions
     12  1.1.1.2  fvdl  * are met:
     13  1.1.1.2  fvdl  * 1. Redistributions of source code must retain the above copyright
     14  1.1.1.2  fvdl  *    notice, this list of conditions and the following disclaimer.
     15  1.1.1.2  fvdl  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1.1.2  fvdl  *    notice, this list of conditions and the following disclaimer in the
     17  1.1.1.2  fvdl  *    documentation and/or other materials provided with the distribution.
     18  1.1.1.2  fvdl  * 3. All advertising materials mentioning features or use of this software
     19  1.1.1.2  fvdl  *    must display the following acknowledgement:
     20  1.1.1.2  fvdl  *	This product includes software developed by the University of
     21  1.1.1.2  fvdl  *	California, Berkeley and its contributors.
     22  1.1.1.2  fvdl  * 4. Neither the name of the University nor the names of its contributors
     23  1.1.1.2  fvdl  *    may be used to endorse or promote products derived from this software
     24  1.1.1.2  fvdl  *    without specific prior written permission.
     25  1.1.1.2  fvdl  *
     26  1.1.1.2  fvdl  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  1.1.1.2  fvdl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  1.1.1.2  fvdl  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  1.1.1.2  fvdl  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  1.1.1.2  fvdl  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  1.1.1.2  fvdl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  1.1.1.2  fvdl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  1.1.1.2  fvdl  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  1.1.1.2  fvdl  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  1.1.1.2  fvdl  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  1.1.1.2  fvdl  * SUCH DAMAGE.
     37  1.1.1.2  fvdl  *
     38  1.1.1.3  fvdl  *	@(#)tty.c	8.13 (Berkeley) 1/9/95
     39  1.1.1.2  fvdl  */
     40  1.1.1.2  fvdl 
     41  1.1.1.2  fvdl #include <sys/param.h>
     42  1.1.1.2  fvdl #include <sys/systm.h>
     43  1.1.1.2  fvdl #include <sys/ioctl.h>
     44  1.1.1.2  fvdl #include <sys/proc.h>
     45  1.1.1.2  fvdl #define	TTYDEFCHARS
     46  1.1.1.2  fvdl #include <sys/tty.h>
     47  1.1.1.2  fvdl #undef	TTYDEFCHARS
     48  1.1.1.2  fvdl #include <sys/file.h>
     49  1.1.1.2  fvdl #include <sys/conf.h>
     50  1.1.1.2  fvdl #include <sys/dkstat.h>
     51  1.1.1.2  fvdl #include <sys/uio.h>
     52  1.1.1.2  fvdl #include <sys/kernel.h>
     53  1.1.1.2  fvdl #include <sys/vnode.h>
     54  1.1.1.2  fvdl #include <sys/syslog.h>
     55  1.1.1.2  fvdl 
     56  1.1.1.2  fvdl #include <vm/vm.h>
     57  1.1.1.2  fvdl 
     58  1.1.1.2  fvdl static int	proc_compare __P((struct proc *p1, struct proc *p2));
     59  1.1.1.2  fvdl static int	ttnread __P((struct tty *));
     60  1.1.1.2  fvdl static void	ttyblock __P((struct tty *tp));
     61  1.1.1.2  fvdl static void	ttyecho __P((int, struct tty *tp));
     62  1.1.1.2  fvdl static void	ttyrubo __P((struct tty *, int));
     63  1.1.1.2  fvdl 
     64  1.1.1.2  fvdl /* Symbolic sleep message strings. */
     65  1.1.1.2  fvdl char ttclos[]	= "ttycls";
     66  1.1.1.2  fvdl char ttopen[]	= "ttyopn";
     67  1.1.1.2  fvdl char ttybg[]	= "ttybg";
     68  1.1.1.2  fvdl char ttybuf[]	= "ttybuf";
     69  1.1.1.2  fvdl char ttyin[]	= "ttyin";
     70  1.1.1.2  fvdl char ttyout[]	= "ttyout";
     71  1.1.1.2  fvdl 
     72  1.1.1.2  fvdl /*
     73  1.1.1.2  fvdl  * Table with character classes and parity. The 8th bit indicates parity,
     74  1.1.1.2  fvdl  * the 7th bit indicates the character is an alphameric or underscore (for
     75  1.1.1.2  fvdl  * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
     76  1.1.1.2  fvdl  * are 0 then the character needs no special processing on output; classes
     77  1.1.1.2  fvdl  * other than 0 might be translated or (not currently) require delays.
     78  1.1.1.2  fvdl  */
     79  1.1.1.2  fvdl #define	E	0x00	/* Even parity. */
     80  1.1.1.2  fvdl #define	O	0x80	/* Odd parity. */
     81  1.1.1.2  fvdl #define	PARITY(c)	(char_type[c] & O)
     82  1.1.1.2  fvdl 
     83  1.1.1.2  fvdl #define	ALPHA	0x40	/* Alpha or underscore. */
     84  1.1.1.2  fvdl #define	ISALPHA(c)	(char_type[(c) & TTY_CHARMASK] & ALPHA)
     85  1.1.1.2  fvdl 
     86  1.1.1.2  fvdl #define	CCLASSMASK	0x3f
     87  1.1.1.2  fvdl #define	CCLASS(c)	(char_type[c] & CCLASSMASK)
     88  1.1.1.2  fvdl 
     89  1.1.1.2  fvdl #define	BS	BACKSPACE
     90  1.1.1.2  fvdl #define	CC	CONTROL
     91  1.1.1.2  fvdl #define	CR	RETURN
     92  1.1.1.2  fvdl #define	NA	ORDINARY | ALPHA
     93  1.1.1.2  fvdl #define	NL	NEWLINE
     94  1.1.1.2  fvdl #define	NO	ORDINARY
     95  1.1.1.2  fvdl #define	TB	TAB
     96  1.1.1.2  fvdl #define	VT	VTAB
     97  1.1.1.2  fvdl 
     98  1.1.1.2  fvdl char const char_type[] = {
     99  1.1.1.2  fvdl 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
    100  1.1.1.2  fvdl 	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
    101  1.1.1.2  fvdl 	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
    102  1.1.1.2  fvdl 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
    103  1.1.1.2  fvdl 	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
    104  1.1.1.2  fvdl 	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
    105  1.1.1.2  fvdl 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
    106  1.1.1.2  fvdl 	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
    107  1.1.1.2  fvdl 	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
    108  1.1.1.2  fvdl 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
    109  1.1.1.2  fvdl 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
    110  1.1.1.2  fvdl 	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
    111  1.1.1.2  fvdl 	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
    112  1.1.1.2  fvdl 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
    113  1.1.1.2  fvdl 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
    114  1.1.1.2  fvdl 	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
    115  1.1.1.2  fvdl 	/*
    116  1.1.1.2  fvdl 	 * Meta chars; should be settable per character set;
    117  1.1.1.2  fvdl 	 * for now, treat them all as normal characters.
    118  1.1.1.2  fvdl 	 */
    119  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    120  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    121  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    122  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    123  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    124  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    125  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    126  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    127  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    128  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    129  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    130  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    131  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    132  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    133  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    134  1.1.1.2  fvdl 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
    135  1.1.1.2  fvdl };
    136  1.1.1.2  fvdl #undef	BS
    137  1.1.1.2  fvdl #undef	CC
    138  1.1.1.2  fvdl #undef	CR
    139  1.1.1.2  fvdl #undef	NA
    140  1.1.1.2  fvdl #undef	NL
    141  1.1.1.2  fvdl #undef	NO
    142  1.1.1.2  fvdl #undef	TB
    143  1.1.1.2  fvdl #undef	VT
    144  1.1.1.2  fvdl 
    145  1.1.1.2  fvdl /* Macros to clear/set/test flags. */
    146  1.1.1.2  fvdl #define	SET(t, f)	(t) |= (f)
    147  1.1.1.2  fvdl #define	CLR(t, f)	(t) &= ~(f)
    148  1.1.1.2  fvdl #define	ISSET(t, f)	((t) & (f))
    149  1.1.1.2  fvdl 
    150  1.1.1.2  fvdl /*
    151  1.1.1.2  fvdl  * Initial open of tty, or (re)entry to standard tty line discipline.
    152  1.1.1.2  fvdl  */
    153  1.1.1.2  fvdl int
    154  1.1.1.2  fvdl ttyopen(device, tp)
    155  1.1.1.2  fvdl 	dev_t device;
    156  1.1.1.2  fvdl 	register struct tty *tp;
    157  1.1.1.2  fvdl {
    158  1.1.1.2  fvdl 	int s;
    159  1.1.1.2  fvdl 
    160  1.1.1.2  fvdl 	s = spltty();
    161  1.1.1.2  fvdl 	tp->t_dev = device;
    162  1.1.1.2  fvdl 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
    163  1.1.1.2  fvdl 		SET(tp->t_state, TS_ISOPEN);
    164  1.1.1.2  fvdl 		bzero(&tp->t_winsize, sizeof(tp->t_winsize));
    165  1.1.1.2  fvdl 	}
    166  1.1.1.2  fvdl 	CLR(tp->t_state, TS_WOPEN);
    167  1.1.1.2  fvdl 	splx(s);
    168  1.1.1.2  fvdl 	return (0);
    169  1.1.1.2  fvdl }
    170  1.1.1.2  fvdl 
    171  1.1.1.2  fvdl /*
    172  1.1.1.2  fvdl  * Handle close() on a tty line: flush and set to initial state,
    173  1.1.1.2  fvdl  * bumping generation number so that pending read/write calls
    174  1.1.1.2  fvdl  * can detect recycling of the tty.
    175  1.1.1.2  fvdl  */
    176  1.1.1.2  fvdl int
    177  1.1.1.2  fvdl ttyclose(tp)
    178  1.1.1.2  fvdl 	register struct tty *tp;
    179  1.1.1.2  fvdl {
    180  1.1.1.2  fvdl 	extern struct tty *constty;	/* Temporary virtual console. */
    181  1.1.1.2  fvdl 
    182  1.1.1.2  fvdl 	if (constty == tp)
    183  1.1.1.2  fvdl 		constty = NULL;
    184  1.1.1.2  fvdl 
    185  1.1.1.2  fvdl 	ttyflush(tp, FREAD | FWRITE);
    186  1.1.1.2  fvdl 
    187  1.1.1.2  fvdl 	tp->t_gen++;
    188  1.1.1.2  fvdl 	tp->t_pgrp = NULL;
    189  1.1.1.2  fvdl 	tp->t_session = NULL;
    190  1.1.1.2  fvdl 	tp->t_state = 0;
    191  1.1.1.2  fvdl 	return (0);
    192  1.1.1.2  fvdl }
    193  1.1.1.2  fvdl 
    194  1.1.1.2  fvdl #define	FLUSHQ(q) {							\
    195  1.1.1.2  fvdl 	if ((q)->c_cc)							\
    196  1.1.1.2  fvdl 		ndflush(q, (q)->c_cc);					\
    197  1.1.1.2  fvdl }
    198  1.1.1.2  fvdl 
    199  1.1.1.2  fvdl /* Is 'c' a line delimiter ("break" character)? */
    200  1.1.1.2  fvdl #define	TTBREAKC(c)							\
    201  1.1.1.2  fvdl 	((c) == '\n' || ((c) == cc[VEOF] ||				\
    202  1.1.1.2  fvdl 	(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
    203  1.1.1.2  fvdl 
    204  1.1.1.2  fvdl 
    205  1.1.1.2  fvdl /*
    206  1.1.1.2  fvdl  * Process input of a single character received on a tty.
    207  1.1.1.2  fvdl  */
    208  1.1.1.2  fvdl int
    209  1.1.1.2  fvdl ttyinput(c, tp)
    210  1.1.1.2  fvdl 	register int c;
    211  1.1.1.2  fvdl 	register struct tty *tp;
    212  1.1.1.2  fvdl {
    213  1.1.1.2  fvdl 	register int iflag, lflag;
    214  1.1.1.2  fvdl 	register u_char *cc;
    215  1.1.1.2  fvdl 	int i, err;
    216  1.1.1.2  fvdl 
    217  1.1.1.2  fvdl 	/*
    218  1.1.1.2  fvdl 	 * If input is pending take it first.
    219  1.1.1.2  fvdl 	 */
    220  1.1.1.2  fvdl 	lflag = tp->t_lflag;
    221  1.1.1.2  fvdl 	if (ISSET(lflag, PENDIN))
    222  1.1.1.2  fvdl 		ttypend(tp);
    223  1.1.1.2  fvdl 	/*
    224  1.1.1.2  fvdl 	 * Gather stats.
    225  1.1.1.2  fvdl 	 */
    226  1.1.1.2  fvdl 	if (ISSET(lflag, ICANON)) {
    227  1.1.1.2  fvdl 		++tk_cancc;
    228  1.1.1.2  fvdl 		++tp->t_cancc;
    229  1.1.1.2  fvdl 	} else {
    230  1.1.1.2  fvdl 		++tk_rawcc;
    231  1.1.1.2  fvdl 		++tp->t_rawcc;
    232  1.1.1.2  fvdl 	}
    233  1.1.1.2  fvdl 	++tk_nin;
    234  1.1.1.2  fvdl 
    235  1.1.1.2  fvdl 	/* Handle exceptional conditions (break, parity, framing). */
    236  1.1.1.2  fvdl 	cc = tp->t_cc;
    237  1.1.1.2  fvdl 	iflag = tp->t_iflag;
    238  1.1.1.2  fvdl 	if (err = (ISSET(c, TTY_ERRORMASK))) {
    239  1.1.1.2  fvdl 		CLR(c, TTY_ERRORMASK);
    240  1.1.1.2  fvdl 		if (ISSET(err, TTY_FE) && !c) {	/* Break. */
    241  1.1.1.2  fvdl 			if (ISSET(iflag, IGNBRK))
    242  1.1.1.2  fvdl 				goto endcase;
    243  1.1.1.2  fvdl 			else if (ISSET(iflag, BRKINT) &&
    244  1.1.1.2  fvdl 			    ISSET(lflag, ISIG) &&
    245  1.1.1.2  fvdl 			    (cc[VINTR] != _POSIX_VDISABLE))
    246  1.1.1.2  fvdl 				c = cc[VINTR];
    247  1.1.1.2  fvdl 			else if (ISSET(iflag, PARMRK))
    248  1.1.1.2  fvdl 				goto parmrk;
    249  1.1.1.2  fvdl 		} else if (ISSET(err, TTY_PE) &&
    250  1.1.1.2  fvdl 		    ISSET(iflag, INPCK) || ISSET(err, TTY_FE)) {
    251  1.1.1.2  fvdl 			if (ISSET(iflag, IGNPAR))
    252  1.1.1.2  fvdl 				goto endcase;
    253  1.1.1.2  fvdl 			else if (ISSET(iflag, PARMRK)) {
    254  1.1.1.2  fvdl parmrk:				(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
    255  1.1.1.2  fvdl 				(void)putc(0 | TTY_QUOTE, &tp->t_rawq);
    256  1.1.1.2  fvdl 				(void)putc(c | TTY_QUOTE, &tp->t_rawq);
    257  1.1.1.2  fvdl 				goto endcase;
    258  1.1.1.2  fvdl 			} else
    259  1.1.1.2  fvdl 				c = 0;
    260  1.1.1.2  fvdl 		}
    261  1.1.1.2  fvdl 	}
    262  1.1.1.2  fvdl 	/*
    263  1.1.1.2  fvdl 	 * In tandem mode, check high water mark.
    264  1.1.1.2  fvdl 	 */
    265  1.1.1.2  fvdl 	if (ISSET(iflag, IXOFF))
    266  1.1.1.2  fvdl 		ttyblock(tp);
    267  1.1.1.2  fvdl 	if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
    268  1.1.1.2  fvdl 		CLR(c, 0x80);
    269  1.1.1.2  fvdl 	if (!ISSET(lflag, EXTPROC)) {
    270  1.1.1.2  fvdl 		/*
    271  1.1.1.2  fvdl 		 * Check for literal nexting very first
    272  1.1.1.2  fvdl 		 */
    273  1.1.1.2  fvdl 		if (ISSET(tp->t_state, TS_LNCH)) {
    274  1.1.1.2  fvdl 			SET(c, TTY_QUOTE);
    275  1.1.1.2  fvdl 			CLR(tp->t_state, TS_LNCH);
    276  1.1.1.2  fvdl 		}
    277  1.1.1.2  fvdl 		/*
    278  1.1.1.2  fvdl 		 * Scan for special characters.  This code
    279  1.1.1.2  fvdl 		 * is really just a big case statement with
    280  1.1.1.2  fvdl 		 * non-constant cases.  The bottom of the
    281  1.1.1.2  fvdl 		 * case statement is labeled ``endcase'', so goto
    282  1.1.1.2  fvdl 		 * it after a case match, or similar.
    283  1.1.1.2  fvdl 		 */
    284  1.1.1.2  fvdl 
    285  1.1.1.2  fvdl 		/*
    286  1.1.1.2  fvdl 		 * Control chars which aren't controlled
    287  1.1.1.2  fvdl 		 * by ICANON, ISIG, or IXON.
    288  1.1.1.2  fvdl 		 */
    289  1.1.1.2  fvdl 		if (ISSET(lflag, IEXTEN)) {
    290  1.1.1.2  fvdl 			if (CCEQ(cc[VLNEXT], c)) {
    291  1.1.1.2  fvdl 				if (ISSET(lflag, ECHO)) {
    292  1.1.1.2  fvdl 					if (ISSET(lflag, ECHOE)) {
    293  1.1.1.2  fvdl 						(void)ttyoutput('^', tp);
    294  1.1.1.2  fvdl 						(void)ttyoutput('\b', tp);
    295  1.1.1.2  fvdl 					} else
    296  1.1.1.2  fvdl 						ttyecho(c, tp);
    297  1.1.1.2  fvdl 				}
    298  1.1.1.2  fvdl 				SET(tp->t_state, TS_LNCH);
    299  1.1.1.2  fvdl 				goto endcase;
    300  1.1.1.2  fvdl 			}
    301  1.1.1.2  fvdl 			if (CCEQ(cc[VDISCARD], c)) {
    302  1.1.1.2  fvdl 				if (ISSET(lflag, FLUSHO))
    303  1.1.1.2  fvdl 					CLR(tp->t_lflag, FLUSHO);
    304  1.1.1.2  fvdl 				else {
    305  1.1.1.2  fvdl 					ttyflush(tp, FWRITE);
    306  1.1.1.2  fvdl 					ttyecho(c, tp);
    307  1.1.1.2  fvdl 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
    308  1.1.1.2  fvdl 						ttyretype(tp);
    309  1.1.1.2  fvdl 					SET(tp->t_lflag, FLUSHO);
    310  1.1.1.2  fvdl 				}
    311  1.1.1.2  fvdl 				goto startoutput;
    312  1.1.1.2  fvdl 			}
    313  1.1.1.2  fvdl 		}
    314  1.1.1.2  fvdl 		/*
    315  1.1.1.2  fvdl 		 * Signals.
    316  1.1.1.2  fvdl 		 */
    317  1.1.1.2  fvdl 		if (ISSET(lflag, ISIG)) {
    318  1.1.1.2  fvdl 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
    319  1.1.1.2  fvdl 				if (!ISSET(lflag, NOFLSH))
    320  1.1.1.2  fvdl 					ttyflush(tp, FREAD | FWRITE);
    321  1.1.1.2  fvdl 				ttyecho(c, tp);
    322  1.1.1.2  fvdl 				pgsignal(tp->t_pgrp,
    323  1.1.1.2  fvdl 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
    324  1.1.1.2  fvdl 				goto endcase;
    325  1.1.1.2  fvdl 			}
    326  1.1.1.2  fvdl 			if (CCEQ(cc[VSUSP], c)) {
    327  1.1.1.2  fvdl 				if (!ISSET(lflag, NOFLSH))
    328  1.1.1.2  fvdl 					ttyflush(tp, FREAD);
    329  1.1.1.2  fvdl 				ttyecho(c, tp);
    330  1.1.1.2  fvdl 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
    331  1.1.1.2  fvdl 				goto endcase;
    332  1.1.1.2  fvdl 			}
    333  1.1.1.2  fvdl 		}
    334  1.1.1.2  fvdl 		/*
    335  1.1.1.2  fvdl 		 * Handle start/stop characters.
    336  1.1.1.2  fvdl 		 */
    337  1.1.1.2  fvdl 		if (ISSET(iflag, IXON)) {
    338  1.1.1.2  fvdl 			if (CCEQ(cc[VSTOP], c)) {
    339  1.1.1.2  fvdl 				if (!ISSET(tp->t_state, TS_TTSTOP)) {
    340  1.1.1.2  fvdl 					SET(tp->t_state, TS_TTSTOP);
    341  1.1.1.2  fvdl #ifdef sun4c						/* XXX */
    342  1.1.1.2  fvdl 					(*tp->t_stop)(tp, 0);
    343  1.1.1.2  fvdl #else
    344  1.1.1.2  fvdl 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
    345  1.1.1.2  fvdl 					   0);
    346  1.1.1.2  fvdl #endif
    347  1.1.1.2  fvdl 					return (0);
    348  1.1.1.2  fvdl 				}
    349  1.1.1.2  fvdl 				if (!CCEQ(cc[VSTART], c))
    350  1.1.1.2  fvdl 					return (0);
    351  1.1.1.2  fvdl 				/*
    352  1.1.1.2  fvdl 				 * if VSTART == VSTOP then toggle
    353  1.1.1.2  fvdl 				 */
    354  1.1.1.2  fvdl 				goto endcase;
    355  1.1.1.2  fvdl 			}
    356  1.1.1.2  fvdl 			if (CCEQ(cc[VSTART], c))
    357  1.1.1.2  fvdl 				goto restartoutput;
    358  1.1.1.2  fvdl 		}
    359  1.1.1.2  fvdl 		/*
    360  1.1.1.2  fvdl 		 * IGNCR, ICRNL, & INLCR
    361  1.1.1.2  fvdl 		 */
    362  1.1.1.2  fvdl 		if (c == '\r') {
    363  1.1.1.2  fvdl 			if (ISSET(iflag, IGNCR))
    364  1.1.1.2  fvdl 				goto endcase;
    365  1.1.1.2  fvdl 			else if (ISSET(iflag, ICRNL))
    366  1.1.1.2  fvdl 				c = '\n';
    367  1.1.1.2  fvdl 		} else if (c == '\n' && ISSET(iflag, INLCR))
    368  1.1.1.2  fvdl 			c = '\r';
    369  1.1.1.2  fvdl 	}
    370  1.1.1.2  fvdl 	if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
    371  1.1.1.2  fvdl 		/*
    372  1.1.1.2  fvdl 		 * From here on down canonical mode character
    373  1.1.1.2  fvdl 		 * processing takes place.
    374  1.1.1.2  fvdl 		 */
    375  1.1.1.2  fvdl 		/*
    376  1.1.1.2  fvdl 		 * erase (^H / ^?)
    377  1.1.1.2  fvdl 		 */
    378  1.1.1.2  fvdl 		if (CCEQ(cc[VERASE], c)) {
    379  1.1.1.2  fvdl 			if (tp->t_rawq.c_cc)
    380  1.1.1.2  fvdl 				ttyrub(unputc(&tp->t_rawq), tp);
    381  1.1.1.2  fvdl 			goto endcase;
    382  1.1.1.2  fvdl 		}
    383  1.1.1.2  fvdl 		/*
    384  1.1.1.2  fvdl 		 * kill (^U)
    385  1.1.1.2  fvdl 		 */
    386  1.1.1.2  fvdl 		if (CCEQ(cc[VKILL], c)) {
    387  1.1.1.2  fvdl 			if (ISSET(lflag, ECHOKE) &&
    388  1.1.1.2  fvdl 			    tp->t_rawq.c_cc == tp->t_rocount &&
    389  1.1.1.2  fvdl 			    !ISSET(lflag, ECHOPRT))
    390  1.1.1.2  fvdl 				while (tp->t_rawq.c_cc)
    391  1.1.1.2  fvdl 					ttyrub(unputc(&tp->t_rawq), tp);
    392  1.1.1.2  fvdl 			else {
    393  1.1.1.2  fvdl 				ttyecho(c, tp);
    394  1.1.1.2  fvdl 				if (ISSET(lflag, ECHOK) ||
    395  1.1.1.2  fvdl 				    ISSET(lflag, ECHOKE))
    396  1.1.1.2  fvdl 					ttyecho('\n', tp);
    397  1.1.1.2  fvdl 				FLUSHQ(&tp->t_rawq);
    398  1.1.1.2  fvdl 				tp->t_rocount = 0;
    399  1.1.1.2  fvdl 			}
    400  1.1.1.2  fvdl 			CLR(tp->t_state, TS_LOCAL);
    401  1.1.1.2  fvdl 			goto endcase;
    402  1.1.1.2  fvdl 		}
    403  1.1.1.2  fvdl 		/*
    404  1.1.1.2  fvdl 		 * word erase (^W)
    405  1.1.1.2  fvdl 		 */
    406  1.1.1.2  fvdl 		if (CCEQ(cc[VWERASE], c)) {
    407  1.1.1.2  fvdl 			int alt = ISSET(lflag, ALTWERASE);
    408  1.1.1.2  fvdl 			int ctype;
    409  1.1.1.2  fvdl 
    410  1.1.1.2  fvdl 			/*
    411  1.1.1.2  fvdl 			 * erase whitespace
    412  1.1.1.2  fvdl 			 */
    413  1.1.1.2  fvdl 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
    414  1.1.1.2  fvdl 				ttyrub(c, tp);
    415  1.1.1.2  fvdl 			if (c == -1)
    416  1.1.1.2  fvdl 				goto endcase;
    417  1.1.1.2  fvdl 			/*
    418  1.1.1.2  fvdl 			 * erase last char of word and remember the
    419  1.1.1.2  fvdl 			 * next chars type (for ALTWERASE)
    420  1.1.1.2  fvdl 			 */
    421  1.1.1.2  fvdl 			ttyrub(c, tp);
    422  1.1.1.2  fvdl 			c = unputc(&tp->t_rawq);
    423  1.1.1.2  fvdl 			if (c == -1)
    424  1.1.1.2  fvdl 				goto endcase;
    425  1.1.1.2  fvdl 			if (c == ' ' || c == '\t') {
    426  1.1.1.2  fvdl 				(void)putc(c, &tp->t_rawq);
    427  1.1.1.2  fvdl 				goto endcase;
    428  1.1.1.2  fvdl 			}
    429  1.1.1.2  fvdl 			ctype = ISALPHA(c);
    430  1.1.1.2  fvdl 			/*
    431  1.1.1.2  fvdl 			 * erase rest of word
    432  1.1.1.2  fvdl 			 */
    433  1.1.1.2  fvdl 			do {
    434  1.1.1.2  fvdl 				ttyrub(c, tp);
    435  1.1.1.2  fvdl 				c = unputc(&tp->t_rawq);
    436  1.1.1.2  fvdl 				if (c == -1)
    437  1.1.1.2  fvdl 					goto endcase;
    438  1.1.1.2  fvdl 			} while (c != ' ' && c != '\t' &&
    439  1.1.1.2  fvdl 			    (alt == 0 || ISALPHA(c) == ctype));
    440  1.1.1.2  fvdl 			(void)putc(c, &tp->t_rawq);
    441  1.1.1.2  fvdl 			goto endcase;
    442  1.1.1.2  fvdl 		}
    443  1.1.1.2  fvdl 		/*
    444  1.1.1.2  fvdl 		 * reprint line (^R)
    445  1.1.1.2  fvdl 		 */
    446  1.1.1.2  fvdl 		if (CCEQ(cc[VREPRINT], c)) {
    447  1.1.1.2  fvdl 			ttyretype(tp);
    448  1.1.1.2  fvdl 			goto endcase;
    449  1.1.1.2  fvdl 		}
    450  1.1.1.2  fvdl 		/*
    451  1.1.1.2  fvdl 		 * ^T - kernel info and generate SIGINFO
    452  1.1.1.2  fvdl 		 */
    453  1.1.1.2  fvdl 		if (CCEQ(cc[VSTATUS], c)) {
    454  1.1.1.2  fvdl 			if (ISSET(lflag, ISIG))
    455  1.1.1.2  fvdl 				pgsignal(tp->t_pgrp, SIGINFO, 1);
    456  1.1.1.2  fvdl 			if (!ISSET(lflag, NOKERNINFO))
    457  1.1.1.2  fvdl 				ttyinfo(tp);
    458  1.1.1.2  fvdl 			goto endcase;
    459  1.1.1.2  fvdl 		}
    460  1.1.1.2  fvdl 	}
    461  1.1.1.2  fvdl 	/*
    462  1.1.1.2  fvdl 	 * Check for input buffer overflow
    463  1.1.1.2  fvdl 	 */
    464  1.1.1.2  fvdl 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
    465  1.1.1.2  fvdl 		if (ISSET(iflag, IMAXBEL)) {
    466  1.1.1.2  fvdl 			if (tp->t_outq.c_cc < tp->t_hiwat)
    467  1.1.1.2  fvdl 				(void)ttyoutput(CTRL('g'), tp);
    468  1.1.1.2  fvdl 		} else
    469  1.1.1.2  fvdl 			ttyflush(tp, FREAD | FWRITE);
    470  1.1.1.2  fvdl 		goto endcase;
    471  1.1.1.2  fvdl 	}
    472  1.1.1.2  fvdl 	/*
    473  1.1.1.2  fvdl 	 * Put data char in q for user and
    474  1.1.1.2  fvdl 	 * wakeup on seeing a line delimiter.
    475  1.1.1.2  fvdl 	 */
    476  1.1.1.2  fvdl 	if (putc(c, &tp->t_rawq) >= 0) {
    477  1.1.1.2  fvdl 		if (!ISSET(lflag, ICANON)) {
    478  1.1.1.2  fvdl 			ttwakeup(tp);
    479  1.1.1.2  fvdl 			ttyecho(c, tp);
    480  1.1.1.2  fvdl 			goto endcase;
    481  1.1.1.2  fvdl 		}
    482  1.1.1.2  fvdl 		if (TTBREAKC(c)) {
    483  1.1.1.2  fvdl 			tp->t_rocount = 0;
    484  1.1.1.2  fvdl 			catq(&tp->t_rawq, &tp->t_canq);
    485  1.1.1.2  fvdl 			ttwakeup(tp);
    486  1.1.1.2  fvdl 		} else if (tp->t_rocount++ == 0)
    487  1.1.1.2  fvdl 			tp->t_rocol = tp->t_column;
    488  1.1.1.2  fvdl 		if (ISSET(tp->t_state, TS_ERASE)) {
    489  1.1.1.2  fvdl 			/*
    490  1.1.1.2  fvdl 			 * end of prterase \.../
    491  1.1.1.2  fvdl 			 */
    492  1.1.1.2  fvdl 			CLR(tp->t_state, TS_ERASE);
    493  1.1.1.2  fvdl 			(void)ttyoutput('/', tp);
    494  1.1.1.2  fvdl 		}
    495  1.1.1.2  fvdl 		i = tp->t_column;
    496  1.1.1.2  fvdl 		ttyecho(c, tp);
    497  1.1.1.2  fvdl 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
    498  1.1.1.2  fvdl 			/*
    499  1.1.1.2  fvdl 			 * Place the cursor over the '^' of the ^D.
    500  1.1.1.2  fvdl 			 */
    501  1.1.1.2  fvdl 			i = min(2, tp->t_column - i);
    502  1.1.1.2  fvdl 			while (i > 0) {
    503  1.1.1.2  fvdl 				(void)ttyoutput('\b', tp);
    504  1.1.1.2  fvdl 				i--;
    505  1.1.1.2  fvdl 			}
    506  1.1.1.2  fvdl 		}
    507  1.1.1.2  fvdl 	}
    508  1.1.1.2  fvdl endcase:
    509  1.1.1.2  fvdl 	/*
    510  1.1.1.2  fvdl 	 * IXANY means allow any character to restart output.
    511  1.1.1.2  fvdl 	 */
    512  1.1.1.2  fvdl 	if (ISSET(tp->t_state, TS_TTSTOP) &&
    513  1.1.1.2  fvdl 	    !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
    514  1.1.1.2  fvdl 		return (0);
    515  1.1.1.2  fvdl restartoutput:
    516  1.1.1.2  fvdl 	CLR(tp->t_lflag, FLUSHO);
    517  1.1.1.2  fvdl 	CLR(tp->t_state, TS_TTSTOP);
    518  1.1.1.2  fvdl startoutput:
    519  1.1.1.2  fvdl 	return (ttstart(tp));
    520  1.1.1.2  fvdl }
    521  1.1.1.2  fvdl 
    522  1.1.1.2  fvdl /*
    523  1.1.1.2  fvdl  * Output a single character on a tty, doing output processing
    524  1.1.1.2  fvdl  * as needed (expanding tabs, newline processing, etc.).
    525  1.1.1.2  fvdl  * Returns < 0 if succeeds, otherwise returns char to resend.
    526  1.1.1.2  fvdl  * Must be recursive.
    527  1.1.1.2  fvdl  */
    528  1.1.1.2  fvdl int
    529  1.1.1.2  fvdl ttyoutput(c, tp)
    530  1.1.1.2  fvdl 	register int c;
    531  1.1.1.2  fvdl 	register struct tty *tp;
    532  1.1.1.2  fvdl {
    533  1.1.1.2  fvdl 	register long oflag;
    534  1.1.1.3  fvdl 	register int notout, col, s;
    535  1.1.1.2  fvdl 
    536  1.1.1.2  fvdl 	oflag = tp->t_oflag;
    537  1.1.1.2  fvdl 	if (!ISSET(oflag, OPOST)) {
    538  1.1.1.2  fvdl 		if (ISSET(tp->t_lflag, FLUSHO))
    539  1.1.1.2  fvdl 			return (-1);
    540  1.1.1.2  fvdl 		if (putc(c, &tp->t_outq))
    541  1.1.1.2  fvdl 			return (c);
    542  1.1.1.2  fvdl 		tk_nout++;
    543  1.1.1.2  fvdl 		tp->t_outcc++;
    544  1.1.1.2  fvdl 		return (-1);
    545  1.1.1.2  fvdl 	}
    546  1.1.1.2  fvdl 	/*
    547  1.1.1.2  fvdl 	 * Do tab expansion if OXTABS is set.  Special case if we external
    548  1.1.1.2  fvdl 	 * processing, we don't do the tab expansion because we'll probably
    549  1.1.1.2  fvdl 	 * get it wrong.  If tab expansion needs to be done, let it happen
    550  1.1.1.2  fvdl 	 * externally.
    551  1.1.1.2  fvdl 	 */
    552  1.1.1.2  fvdl 	CLR(c, ~TTY_CHARMASK);
    553  1.1.1.2  fvdl 	if (c == '\t' &&
    554  1.1.1.2  fvdl 	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
    555  1.1.1.2  fvdl 		c = 8 - (tp->t_column & 7);
    556  1.1.1.3  fvdl 		if (ISSET(tp->t_lflag, FLUSHO)) {
    557  1.1.1.3  fvdl 			notout = 0;
    558  1.1.1.3  fvdl 		} else {
    559  1.1.1.2  fvdl 			s = spltty();		/* Don't interrupt tabs. */
    560  1.1.1.3  fvdl 			notout = b_to_q("        ", c, &tp->t_outq);
    561  1.1.1.3  fvdl 			c -= notout;
    562  1.1.1.2  fvdl 			tk_nout += c;
    563  1.1.1.2  fvdl 			tp->t_outcc += c;
    564  1.1.1.2  fvdl 			splx(s);
    565  1.1.1.2  fvdl 		}
    566  1.1.1.2  fvdl 		tp->t_column += c;
    567  1.1.1.3  fvdl 		return (notout ? '\t' : -1);
    568  1.1.1.2  fvdl 	}
    569  1.1.1.2  fvdl 	if (c == CEOT && ISSET(oflag, ONOEOT))
    570  1.1.1.2  fvdl 		return (-1);
    571  1.1.1.2  fvdl 
    572  1.1.1.2  fvdl 	/*
    573  1.1.1.2  fvdl 	 * Newline translation: if ONLCR is set,
    574  1.1.1.2  fvdl 	 * translate newline into "\r\n".
    575  1.1.1.2  fvdl 	 */
    576  1.1.1.2  fvdl 	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
    577  1.1.1.2  fvdl 		tk_nout++;
    578  1.1.1.2  fvdl 		tp->t_outcc++;
    579  1.1.1.2  fvdl 		if (putc('\r', &tp->t_outq))
    580  1.1.1.2  fvdl 			return (c);
    581  1.1.1.2  fvdl 	}
    582  1.1.1.2  fvdl 	tk_nout++;
    583  1.1.1.2  fvdl 	tp->t_outcc++;
    584  1.1.1.2  fvdl 	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
    585  1.1.1.2  fvdl 		return (c);
    586  1.1.1.2  fvdl 
    587  1.1.1.2  fvdl 	col = tp->t_column;
    588  1.1.1.2  fvdl 	switch (CCLASS(c)) {
    589  1.1.1.2  fvdl 	case BACKSPACE:
    590  1.1.1.2  fvdl 		if (col > 0)
    591  1.1.1.2  fvdl 			--col;
    592  1.1.1.2  fvdl 		break;
    593  1.1.1.2  fvdl 	case CONTROL:
    594  1.1.1.2  fvdl 		break;
    595  1.1.1.2  fvdl 	case NEWLINE:
    596  1.1.1.2  fvdl 	case RETURN:
    597  1.1.1.2  fvdl 		col = 0;
    598  1.1.1.2  fvdl 		break;
    599  1.1.1.2  fvdl 	case ORDINARY:
    600  1.1.1.2  fvdl 		++col;
    601  1.1.1.2  fvdl 		break;
    602  1.1.1.2  fvdl 	case TAB:
    603  1.1.1.2  fvdl 		col = (col + 8) & ~7;
    604  1.1.1.2  fvdl 		break;
    605  1.1.1.2  fvdl 	}
    606  1.1.1.2  fvdl 	tp->t_column = col;
    607  1.1.1.2  fvdl 	return (-1);
    608  1.1.1.2  fvdl }
    609  1.1.1.2  fvdl 
    610  1.1.1.2  fvdl /*
    611  1.1.1.2  fvdl  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
    612  1.1.1.2  fvdl  * has been called to do discipline-specific functions and/or reject any
    613  1.1.1.2  fvdl  * of these ioctl commands.
    614  1.1.1.2  fvdl  */
    615  1.1.1.2  fvdl /* ARGSUSED */
    616  1.1.1.2  fvdl int
    617  1.1.1.2  fvdl ttioctl(tp, cmd, data, flag)
    618  1.1.1.2  fvdl 	register struct tty *tp;
    619  1.1.1.3  fvdl 	u_long cmd;
    620  1.1.1.2  fvdl 	void *data;
    621  1.1.1.3  fvdl 	int flag;
    622  1.1.1.2  fvdl {
    623  1.1.1.2  fvdl 	extern struct tty *constty;	/* Temporary virtual console. */
    624  1.1.1.2  fvdl 	extern int nlinesw;
    625  1.1.1.2  fvdl 	register struct proc *p;
    626  1.1.1.2  fvdl 	int s, error;
    627  1.1.1.2  fvdl 
    628  1.1.1.2  fvdl 	p = curproc;			/* XXX */
    629  1.1.1.2  fvdl 
    630  1.1.1.2  fvdl 	/* If the ioctl involves modification, hang if in the background. */
    631  1.1.1.2  fvdl 	switch (cmd) {
    632  1.1.1.2  fvdl 	case  TIOCFLUSH:
    633  1.1.1.2  fvdl 	case  TIOCSETA:
    634  1.1.1.2  fvdl 	case  TIOCSETD:
    635  1.1.1.2  fvdl 	case  TIOCSETAF:
    636  1.1.1.2  fvdl 	case  TIOCSETAW:
    637  1.1.1.2  fvdl #ifdef notdef
    638  1.1.1.2  fvdl 	case  TIOCSPGRP:
    639  1.1.1.2  fvdl #endif
    640  1.1.1.2  fvdl 	case  TIOCSTI:
    641  1.1.1.2  fvdl 	case  TIOCSWINSZ:
    642  1.1.1.2  fvdl #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
    643  1.1.1.2  fvdl 	case  TIOCLBIC:
    644  1.1.1.2  fvdl 	case  TIOCLBIS:
    645  1.1.1.2  fvdl 	case  TIOCLSET:
    646  1.1.1.2  fvdl 	case  TIOCSETC:
    647  1.1.1.2  fvdl 	case OTIOCSETD:
    648  1.1.1.2  fvdl 	case  TIOCSETN:
    649  1.1.1.2  fvdl 	case  TIOCSETP:
    650  1.1.1.2  fvdl 	case  TIOCSLTC:
    651  1.1.1.2  fvdl #endif
    652  1.1.1.2  fvdl 		while (isbackground(curproc, tp) &&
    653  1.1.1.2  fvdl 		    p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&
    654  1.1.1.2  fvdl 		    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
    655  1.1.1.2  fvdl 		    (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
    656  1.1.1.2  fvdl 			pgsignal(p->p_pgrp, SIGTTOU, 1);
    657  1.1.1.2  fvdl 			if (error = ttysleep(tp,
    658  1.1.1.2  fvdl 			    &lbolt, TTOPRI | PCATCH, ttybg, 0))
    659  1.1.1.2  fvdl 				return (error);
    660  1.1.1.2  fvdl 		}
    661  1.1.1.2  fvdl 		break;
    662  1.1.1.2  fvdl 	}
    663  1.1.1.2  fvdl 
    664  1.1.1.2  fvdl 	switch (cmd) {			/* Process the ioctl. */
    665  1.1.1.2  fvdl 	case FIOASYNC:			/* set/clear async i/o */
    666  1.1.1.2  fvdl 		s = spltty();
    667  1.1.1.2  fvdl 		if (*(int *)data)
    668  1.1.1.2  fvdl 			SET(tp->t_state, TS_ASYNC);
    669  1.1.1.2  fvdl 		else
    670  1.1.1.2  fvdl 			CLR(tp->t_state, TS_ASYNC);
    671  1.1.1.2  fvdl 		splx(s);
    672  1.1.1.2  fvdl 		break;
    673  1.1.1.2  fvdl 	case FIONBIO:			/* set/clear non-blocking i/o */
    674  1.1.1.2  fvdl 		break;			/* XXX: delete. */
    675  1.1.1.2  fvdl 	case FIONREAD:			/* get # bytes to read */
    676  1.1.1.2  fvdl 		*(int *)data = ttnread(tp);
    677  1.1.1.2  fvdl 		break;
    678  1.1.1.2  fvdl 	case TIOCEXCL:			/* set exclusive use of tty */
    679  1.1.1.2  fvdl 		s = spltty();
    680  1.1.1.2  fvdl 		SET(tp->t_state, TS_XCLUDE);
    681  1.1.1.2  fvdl 		splx(s);
    682  1.1.1.2  fvdl 		break;
    683  1.1.1.2  fvdl 	case TIOCFLUSH: {		/* flush buffers */
    684  1.1.1.2  fvdl 		register int flags = *(int *)data;
    685  1.1.1.2  fvdl 
    686  1.1.1.2  fvdl 		if (flags == 0)
    687  1.1.1.2  fvdl 			flags = FREAD | FWRITE;
    688  1.1.1.2  fvdl 		else
    689  1.1.1.2  fvdl 			flags &= FREAD | FWRITE;
    690  1.1.1.2  fvdl 		ttyflush(tp, flags);
    691  1.1.1.2  fvdl 		break;
    692  1.1.1.2  fvdl 	}
    693  1.1.1.2  fvdl 	case TIOCCONS:			/* become virtual console */
    694  1.1.1.2  fvdl 		if (*(int *)data) {
    695  1.1.1.2  fvdl 			if (constty && constty != tp &&
    696  1.1.1.2  fvdl 			    ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
    697  1.1.1.2  fvdl 			    (TS_CARR_ON | TS_ISOPEN))
    698  1.1.1.2  fvdl 				return (EBUSY);
    699  1.1.1.2  fvdl #ifndef	UCONSOLE
    700  1.1.1.2  fvdl 			if (error = suser(p->p_ucred, &p->p_acflag))
    701  1.1.1.2  fvdl 				return (error);
    702  1.1.1.2  fvdl #endif
    703  1.1.1.2  fvdl 			constty = tp;
    704  1.1.1.2  fvdl 		} else if (tp == constty)
    705  1.1.1.2  fvdl 			constty = NULL;
    706  1.1.1.2  fvdl 		break;
    707  1.1.1.2  fvdl 	case TIOCDRAIN:			/* wait till output drained */
    708  1.1.1.2  fvdl 		if (error = ttywait(tp))
    709  1.1.1.2  fvdl 			return (error);
    710  1.1.1.2  fvdl 		break;
    711  1.1.1.2  fvdl 	case TIOCGETA: {		/* get termios struct */
    712  1.1.1.2  fvdl 		struct termios *t = (struct termios *)data;
    713  1.1.1.2  fvdl 
    714  1.1.1.2  fvdl 		bcopy(&tp->t_termios, t, sizeof(struct termios));
    715  1.1.1.2  fvdl 		break;
    716  1.1.1.2  fvdl 	}
    717  1.1.1.2  fvdl 	case TIOCGETD:			/* get line discipline */
    718  1.1.1.2  fvdl 		*(int *)data = tp->t_line;
    719  1.1.1.2  fvdl 		break;
    720  1.1.1.2  fvdl 	case TIOCGWINSZ:		/* get window size */
    721  1.1.1.2  fvdl 		*(struct winsize *)data = tp->t_winsize;
    722  1.1.1.2  fvdl 		break;
    723  1.1.1.2  fvdl 	case TIOCGPGRP:			/* get pgrp of tty */
    724  1.1.1.2  fvdl 		if (!isctty(p, tp))
    725  1.1.1.2  fvdl 			return (ENOTTY);
    726  1.1.1.2  fvdl 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
    727  1.1.1.2  fvdl 		break;
    728  1.1.1.2  fvdl #ifdef TIOCHPCL
    729  1.1.1.2  fvdl 	case TIOCHPCL:			/* hang up on last close */
    730  1.1.1.2  fvdl 		s = spltty();
    731  1.1.1.2  fvdl 		SET(tp->t_cflag, HUPCL);
    732  1.1.1.2  fvdl 		splx(s);
    733  1.1.1.2  fvdl 		break;
    734  1.1.1.2  fvdl #endif
    735  1.1.1.2  fvdl 	case TIOCNXCL:			/* reset exclusive use of tty */
    736  1.1.1.2  fvdl 		s = spltty();
    737  1.1.1.2  fvdl 		CLR(tp->t_state, TS_XCLUDE);
    738  1.1.1.2  fvdl 		splx(s);
    739  1.1.1.2  fvdl 		break;
    740  1.1.1.2  fvdl 	case TIOCOUTQ:			/* output queue size */
    741  1.1.1.2  fvdl 		*(int *)data = tp->t_outq.c_cc;
    742  1.1.1.2  fvdl 		break;
    743  1.1.1.2  fvdl 	case TIOCSETA:			/* set termios struct */
    744  1.1.1.2  fvdl 	case TIOCSETAW:			/* drain output, set */
    745  1.1.1.2  fvdl 	case TIOCSETAF: {		/* drn out, fls in, set */
    746  1.1.1.2  fvdl 		register struct termios *t = (struct termios *)data;
    747  1.1.1.2  fvdl 
    748  1.1.1.2  fvdl 		s = spltty();
    749  1.1.1.2  fvdl 		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
    750  1.1.1.2  fvdl 			if (error = ttywait(tp)) {
    751  1.1.1.2  fvdl 				splx(s);
    752  1.1.1.2  fvdl 				return (error);
    753  1.1.1.2  fvdl 			}
    754  1.1.1.2  fvdl 			if (cmd == TIOCSETAF)
    755  1.1.1.2  fvdl 				ttyflush(tp, FREAD);
    756  1.1.1.2  fvdl 		}
    757  1.1.1.2  fvdl 		if (!ISSET(t->c_cflag, CIGNORE)) {
    758  1.1.1.2  fvdl 			/*
    759  1.1.1.2  fvdl 			 * Set device hardware.
    760  1.1.1.2  fvdl 			 */
    761  1.1.1.2  fvdl 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
    762  1.1.1.2  fvdl 				splx(s);
    763  1.1.1.2  fvdl 				return (error);
    764  1.1.1.2  fvdl 			} else {
    765  1.1.1.2  fvdl 				if (!ISSET(tp->t_state, TS_CARR_ON) &&
    766  1.1.1.2  fvdl 				    ISSET(tp->t_cflag, CLOCAL) &&
    767  1.1.1.2  fvdl 				    !ISSET(t->c_cflag, CLOCAL)) {
    768  1.1.1.2  fvdl 					CLR(tp->t_state, TS_ISOPEN);
    769  1.1.1.2  fvdl 					SET(tp->t_state, TS_WOPEN);
    770  1.1.1.2  fvdl 					ttwakeup(tp);
    771  1.1.1.2  fvdl 				}
    772  1.1.1.2  fvdl 				tp->t_cflag = t->c_cflag;
    773  1.1.1.2  fvdl 				tp->t_ispeed = t->c_ispeed;
    774  1.1.1.2  fvdl 				tp->t_ospeed = t->c_ospeed;
    775  1.1.1.2  fvdl 			}
    776  1.1.1.2  fvdl 			ttsetwater(tp);
    777  1.1.1.2  fvdl 		}
    778  1.1.1.2  fvdl 		if (cmd != TIOCSETAF) {
    779  1.1.1.2  fvdl 			if (ISSET(t->c_lflag, ICANON) !=
    780  1.1.1.2  fvdl 			    ISSET(tp->t_lflag, ICANON))
    781  1.1.1.2  fvdl 				if (ISSET(t->c_lflag, ICANON)) {
    782  1.1.1.2  fvdl 					SET(tp->t_lflag, PENDIN);
    783  1.1.1.2  fvdl 					ttwakeup(tp);
    784  1.1.1.2  fvdl 				} else {
    785  1.1.1.2  fvdl 					struct clist tq;
    786  1.1.1.2  fvdl 
    787  1.1.1.2  fvdl 					catq(&tp->t_rawq, &tp->t_canq);
    788  1.1.1.2  fvdl 					tq = tp->t_rawq;
    789  1.1.1.2  fvdl 					tp->t_rawq = tp->t_canq;
    790  1.1.1.2  fvdl 					tp->t_canq = tq;
    791  1.1.1.2  fvdl 					CLR(tp->t_lflag, PENDIN);
    792  1.1.1.2  fvdl 				}
    793  1.1.1.2  fvdl 		}
    794  1.1.1.2  fvdl 		tp->t_iflag = t->c_iflag;
    795  1.1.1.2  fvdl 		tp->t_oflag = t->c_oflag;
    796  1.1.1.2  fvdl 		/*
    797  1.1.1.2  fvdl 		 * Make the EXTPROC bit read only.
    798  1.1.1.2  fvdl 		 */
    799  1.1.1.2  fvdl 		if (ISSET(tp->t_lflag, EXTPROC))
    800  1.1.1.2  fvdl 			SET(t->c_lflag, EXTPROC);
    801  1.1.1.2  fvdl 		else
    802  1.1.1.2  fvdl 			CLR(t->c_lflag, EXTPROC);
    803  1.1.1.2  fvdl 		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
    804  1.1.1.2  fvdl 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
    805  1.1.1.2  fvdl 		splx(s);
    806  1.1.1.2  fvdl 		break;
    807  1.1.1.2  fvdl 	}
    808  1.1.1.2  fvdl 	case TIOCSETD: {		/* set line discipline */
    809  1.1.1.2  fvdl 		register int t = *(int *)data;
    810  1.1.1.2  fvdl 		dev_t device = tp->t_dev;
    811  1.1.1.2  fvdl 
    812  1.1.1.2  fvdl 		if ((u_int)t >= nlinesw)
    813  1.1.1.2  fvdl 			return (ENXIO);
    814  1.1.1.2  fvdl 		if (t != tp->t_line) {
    815  1.1.1.2  fvdl 			s = spltty();
    816  1.1.1.2  fvdl 			(*linesw[tp->t_line].l_close)(tp, flag);
    817  1.1.1.2  fvdl 			error = (*linesw[t].l_open)(device, tp);
    818  1.1.1.2  fvdl 			if (error) {
    819  1.1.1.2  fvdl 				(void)(*linesw[tp->t_line].l_open)(device, tp);
    820  1.1.1.2  fvdl 				splx(s);
    821  1.1.1.2  fvdl 				return (error);
    822  1.1.1.2  fvdl 			}
    823  1.1.1.2  fvdl 			tp->t_line = t;
    824  1.1.1.2  fvdl 			splx(s);
    825  1.1.1.2  fvdl 		}
    826  1.1.1.2  fvdl 		break;
    827  1.1.1.2  fvdl 	}
    828  1.1.1.2  fvdl 	case TIOCSTART:			/* start output, like ^Q */
    829  1.1.1.2  fvdl 		s = spltty();
    830  1.1.1.2  fvdl 		if (ISSET(tp->t_state, TS_TTSTOP) ||
    831  1.1.1.2  fvdl 		    ISSET(tp->t_lflag, FLUSHO)) {
    832  1.1.1.2  fvdl 			CLR(tp->t_lflag, FLUSHO);
    833  1.1.1.2  fvdl 			CLR(tp->t_state, TS_TTSTOP);
    834  1.1.1.2  fvdl 			ttstart(tp);
    835  1.1.1.2  fvdl 		}
    836  1.1.1.2  fvdl 		splx(s);
    837  1.1.1.2  fvdl 		break;
    838  1.1.1.2  fvdl 	case TIOCSTI:			/* simulate terminal input */
    839  1.1.1.2  fvdl 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
    840  1.1.1.2  fvdl 			return (EPERM);
    841  1.1.1.2  fvdl 		if (p->p_ucred->cr_uid && !isctty(p, tp))
    842  1.1.1.2  fvdl 			return (EACCES);
    843  1.1.1.2  fvdl 		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
    844  1.1.1.2  fvdl 		break;
    845  1.1.1.2  fvdl 	case TIOCSTOP:			/* stop output, like ^S */
    846  1.1.1.2  fvdl 		s = spltty();
    847  1.1.1.2  fvdl 		if (!ISSET(tp->t_state, TS_TTSTOP)) {
    848  1.1.1.2  fvdl 			SET(tp->t_state, TS_TTSTOP);
    849  1.1.1.2  fvdl #ifdef sun4c				/* XXX */
    850  1.1.1.2  fvdl 			(*tp->t_stop)(tp, 0);
    851  1.1.1.2  fvdl #else
    852  1.1.1.2  fvdl 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
    853  1.1.1.2  fvdl #endif
    854  1.1.1.2  fvdl 		}
    855  1.1.1.2  fvdl 		splx(s);
    856  1.1.1.2  fvdl 		break;
    857  1.1.1.2  fvdl 	case TIOCSCTTY:			/* become controlling tty */
    858  1.1.1.2  fvdl 		/* Session ctty vnode pointer set in vnode layer. */
    859  1.1.1.2  fvdl 		if (!SESS_LEADER(p) ||
    860  1.1.1.2  fvdl 		    (p->p_session->s_ttyvp || tp->t_session) &&
    861  1.1.1.2  fvdl 		    (tp->t_session != p->p_session))
    862  1.1.1.2  fvdl 			return (EPERM);
    863  1.1.1.2  fvdl 		tp->t_session = p->p_session;
    864  1.1.1.2  fvdl 		tp->t_pgrp = p->p_pgrp;
    865  1.1.1.2  fvdl 		p->p_session->s_ttyp = tp;
    866  1.1.1.2  fvdl 		p->p_flag |= P_CONTROLT;
    867  1.1.1.2  fvdl 		break;
    868  1.1.1.2  fvdl 	case TIOCSPGRP: {		/* set pgrp of tty */
    869  1.1.1.2  fvdl 		register struct pgrp *pgrp = pgfind(*(int *)data);
    870  1.1.1.2  fvdl 
    871  1.1.1.2  fvdl 		if (!isctty(p, tp))
    872  1.1.1.2  fvdl 			return (ENOTTY);
    873  1.1.1.2  fvdl 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
    874  1.1.1.2  fvdl 			return (EPERM);
    875  1.1.1.2  fvdl 		tp->t_pgrp = pgrp;
    876  1.1.1.2  fvdl 		break;
    877  1.1.1.2  fvdl 	}
    878  1.1.1.2  fvdl 	case TIOCSWINSZ:		/* set window size */
    879  1.1.1.2  fvdl 		if (bcmp((caddr_t)&tp->t_winsize, data,
    880  1.1.1.2  fvdl 		    sizeof (struct winsize))) {
    881  1.1.1.2  fvdl 			tp->t_winsize = *(struct winsize *)data;
    882  1.1.1.2  fvdl 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
    883  1.1.1.2  fvdl 		}
    884  1.1.1.2  fvdl 		break;
    885  1.1.1.2  fvdl 	default:
    886  1.1.1.2  fvdl #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
    887  1.1.1.2  fvdl 		return (ttcompat(tp, cmd, data, flag));
    888  1.1.1.2  fvdl #else
    889  1.1.1.2  fvdl 		return (-1);
    890  1.1.1.2  fvdl #endif
    891  1.1.1.2  fvdl 	}
    892  1.1.1.2  fvdl 	return (0);
    893  1.1.1.2  fvdl }
    894  1.1.1.2  fvdl 
    895  1.1.1.2  fvdl int
    896  1.1.1.2  fvdl ttselect(device, rw, p)
    897  1.1.1.2  fvdl 	dev_t device;
    898  1.1.1.2  fvdl 	int rw;
    899  1.1.1.2  fvdl 	struct proc *p;
    900  1.1.1.2  fvdl {
    901  1.1.1.2  fvdl 	register struct tty *tp;
    902  1.1.1.2  fvdl 	int nread, s;
    903  1.1.1.2  fvdl 
    904  1.1.1.2  fvdl 	tp = &cdevsw[major(device)].d_ttys[minor(device)];
    905  1.1.1.2  fvdl 
    906  1.1.1.2  fvdl 	s = spltty();
    907  1.1.1.2  fvdl 	switch (rw) {
    908  1.1.1.2  fvdl 	case FREAD:
    909  1.1.1.2  fvdl 		nread = ttnread(tp);
    910  1.1.1.2  fvdl 		if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&
    911  1.1.1.2  fvdl 		    !ISSET(tp->t_state, TS_CARR_ON))
    912  1.1.1.2  fvdl 			goto win;
    913  1.1.1.2  fvdl 		selrecord(p, &tp->t_rsel);
    914  1.1.1.2  fvdl 		break;
    915  1.1.1.2  fvdl 	case FWRITE:
    916  1.1.1.2  fvdl 		if (tp->t_outq.c_cc <= tp->t_lowat) {
    917  1.1.1.2  fvdl win:			splx(s);
    918  1.1.1.2  fvdl 			return (1);
    919  1.1.1.2  fvdl 		}
    920  1.1.1.2  fvdl 		selrecord(p, &tp->t_wsel);
    921  1.1.1.2  fvdl 		break;
    922  1.1.1.2  fvdl 	}
    923  1.1.1.2  fvdl 	splx(s);
    924  1.1.1.2  fvdl 	return (0);
    925  1.1.1.2  fvdl }
    926  1.1.1.2  fvdl 
    927  1.1.1.2  fvdl static int
    928  1.1.1.2  fvdl ttnread(tp)
    929  1.1.1.2  fvdl 	struct tty *tp;
    930  1.1.1.2  fvdl {
    931  1.1.1.2  fvdl 	int nread;
    932  1.1.1.2  fvdl 
    933  1.1.1.2  fvdl 	if (ISSET(tp->t_lflag, PENDIN))
    934  1.1.1.2  fvdl 		ttypend(tp);
    935  1.1.1.2  fvdl 	nread = tp->t_canq.c_cc;
    936  1.1.1.2  fvdl 	if (!ISSET(tp->t_lflag, ICANON))
    937  1.1.1.2  fvdl 		nread += tp->t_rawq.c_cc;
    938  1.1.1.2  fvdl 	return (nread);
    939  1.1.1.2  fvdl }
    940  1.1.1.2  fvdl 
    941  1.1.1.2  fvdl /*
    942  1.1.1.2  fvdl  * Wait for output to drain.
    943  1.1.1.2  fvdl  */
    944  1.1.1.2  fvdl int
    945  1.1.1.2  fvdl ttywait(tp)
    946  1.1.1.2  fvdl 	register struct tty *tp;
    947  1.1.1.2  fvdl {
    948  1.1.1.2  fvdl 	int error, s;
    949  1.1.1.2  fvdl 
    950  1.1.1.2  fvdl 	error = 0;
    951  1.1.1.2  fvdl 	s = spltty();
    952  1.1.1.2  fvdl 	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
    953  1.1.1.2  fvdl 	    (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
    954  1.1.1.2  fvdl 	    && tp->t_oproc) {
    955  1.1.1.2  fvdl 		(*tp->t_oproc)(tp);
    956  1.1.1.2  fvdl 		SET(tp->t_state, TS_ASLEEP);
    957  1.1.1.2  fvdl 		if (error = ttysleep(tp,
    958  1.1.1.2  fvdl 		    &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))
    959  1.1.1.2  fvdl 			break;
    960  1.1.1.2  fvdl 	}
    961  1.1.1.2  fvdl 	splx(s);
    962  1.1.1.2  fvdl 	return (error);
    963  1.1.1.2  fvdl }
    964  1.1.1.2  fvdl 
    965  1.1.1.2  fvdl /*
    966  1.1.1.2  fvdl  * Flush if successfully wait.
    967  1.1.1.2  fvdl  */
    968  1.1.1.2  fvdl int
    969  1.1.1.2  fvdl ttywflush(tp)
    970  1.1.1.2  fvdl 	struct tty *tp;
    971  1.1.1.2  fvdl {
    972  1.1.1.2  fvdl 	int error;
    973  1.1.1.2  fvdl 
    974  1.1.1.2  fvdl 	if ((error = ttywait(tp)) == 0)
    975  1.1.1.2  fvdl 		ttyflush(tp, FREAD);
    976  1.1.1.2  fvdl 	return (error);
    977  1.1.1.2  fvdl }
    978  1.1.1.2  fvdl 
    979  1.1.1.2  fvdl /*
    980  1.1.1.2  fvdl  * Flush tty read and/or write queues, notifying anyone waiting.
    981  1.1.1.2  fvdl  */
    982  1.1.1.2  fvdl void
    983  1.1.1.2  fvdl ttyflush(tp, rw)
    984  1.1.1.2  fvdl 	register struct tty *tp;
    985  1.1.1.2  fvdl 	int rw;
    986  1.1.1.2  fvdl {
    987  1.1.1.2  fvdl 	register int s;
    988  1.1.1.2  fvdl 
    989  1.1.1.2  fvdl 	s = spltty();
    990  1.1.1.2  fvdl 	if (rw & FREAD) {
    991  1.1.1.2  fvdl 		FLUSHQ(&tp->t_canq);
    992  1.1.1.2  fvdl 		FLUSHQ(&tp->t_rawq);
    993  1.1.1.2  fvdl 		tp->t_rocount = 0;
    994  1.1.1.2  fvdl 		tp->t_rocol = 0;
    995  1.1.1.2  fvdl 		CLR(tp->t_state, TS_LOCAL);
    996  1.1.1.2  fvdl 		ttwakeup(tp);
    997  1.1.1.2  fvdl 	}
    998  1.1.1.2  fvdl 	if (rw & FWRITE) {
    999  1.1.1.2  fvdl 		CLR(tp->t_state, TS_TTSTOP);
   1000  1.1.1.2  fvdl #ifdef sun4c						/* XXX */
   1001  1.1.1.2  fvdl 		(*tp->t_stop)(tp, rw);
   1002  1.1.1.2  fvdl #else
   1003  1.1.1.2  fvdl 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
   1004  1.1.1.2  fvdl #endif
   1005  1.1.1.2  fvdl 		FLUSHQ(&tp->t_outq);
   1006  1.1.1.2  fvdl 		wakeup((caddr_t)&tp->t_outq);
   1007  1.1.1.2  fvdl 		selwakeup(&tp->t_wsel);
   1008  1.1.1.2  fvdl 	}
   1009  1.1.1.2  fvdl 	splx(s);
   1010  1.1.1.2  fvdl }
   1011  1.1.1.2  fvdl 
   1012  1.1.1.2  fvdl /*
   1013  1.1.1.2  fvdl  * Copy in the default termios characters.
   1014  1.1.1.2  fvdl  */
   1015  1.1.1.2  fvdl void
   1016  1.1.1.2  fvdl ttychars(tp)
   1017  1.1.1.2  fvdl 	struct tty *tp;
   1018  1.1.1.2  fvdl {
   1019  1.1.1.2  fvdl 
   1020  1.1.1.2  fvdl 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
   1021  1.1.1.2  fvdl }
   1022  1.1.1.2  fvdl 
   1023  1.1.1.2  fvdl /*
   1024  1.1.1.2  fvdl  * Send stop character on input overflow.
   1025  1.1.1.2  fvdl  */
   1026  1.1.1.2  fvdl static void
   1027  1.1.1.2  fvdl ttyblock(tp)
   1028  1.1.1.2  fvdl 	register struct tty *tp;
   1029  1.1.1.2  fvdl {
   1030  1.1.1.2  fvdl 	register int total;
   1031  1.1.1.2  fvdl 
   1032  1.1.1.2  fvdl 	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
   1033  1.1.1.2  fvdl 	if (tp->t_rawq.c_cc > TTYHOG) {
   1034  1.1.1.2  fvdl 		ttyflush(tp, FREAD | FWRITE);
   1035  1.1.1.2  fvdl 		CLR(tp->t_state, TS_TBLOCK);
   1036  1.1.1.2  fvdl 	}
   1037  1.1.1.2  fvdl 	/*
   1038  1.1.1.2  fvdl 	 * Block further input iff: current input > threshold
   1039  1.1.1.2  fvdl 	 * AND input is available to user program.
   1040  1.1.1.2  fvdl 	 */
   1041  1.1.1.2  fvdl 	if (total >= TTYHOG / 2 &&
   1042  1.1.1.2  fvdl 	    !ISSET(tp->t_state, TS_TBLOCK) &&
   1043  1.1.1.2  fvdl 	    !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&
   1044  1.1.1.2  fvdl 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
   1045  1.1.1.2  fvdl 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
   1046  1.1.1.2  fvdl 			SET(tp->t_state, TS_TBLOCK);
   1047  1.1.1.2  fvdl 			ttstart(tp);
   1048  1.1.1.2  fvdl 		}
   1049  1.1.1.2  fvdl 	}
   1050  1.1.1.2  fvdl }
   1051  1.1.1.2  fvdl 
   1052  1.1.1.2  fvdl void
   1053  1.1.1.2  fvdl ttrstrt(tp_arg)
   1054  1.1.1.2  fvdl 	void *tp_arg;
   1055  1.1.1.2  fvdl {
   1056  1.1.1.2  fvdl 	struct tty *tp;
   1057  1.1.1.2  fvdl 	int s;
   1058  1.1.1.2  fvdl 
   1059  1.1.1.2  fvdl #ifdef DIAGNOSTIC
   1060  1.1.1.2  fvdl 	if (tp_arg == NULL)
   1061  1.1.1.2  fvdl 		panic("ttrstrt");
   1062  1.1.1.2  fvdl #endif
   1063  1.1.1.2  fvdl 	tp = tp_arg;
   1064  1.1.1.2  fvdl 	s = spltty();
   1065  1.1.1.2  fvdl 
   1066  1.1.1.2  fvdl 	CLR(tp->t_state, TS_TIMEOUT);
   1067  1.1.1.2  fvdl 	ttstart(tp);
   1068  1.1.1.2  fvdl 
   1069  1.1.1.2  fvdl 	splx(s);
   1070  1.1.1.2  fvdl }
   1071  1.1.1.2  fvdl 
   1072  1.1.1.2  fvdl int
   1073  1.1.1.2  fvdl ttstart(tp)
   1074  1.1.1.2  fvdl 	struct tty *tp;
   1075  1.1.1.2  fvdl {
   1076  1.1.1.2  fvdl 
   1077  1.1.1.2  fvdl 	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
   1078  1.1.1.2  fvdl 		(*tp->t_oproc)(tp);
   1079  1.1.1.2  fvdl 	return (0);
   1080  1.1.1.2  fvdl }
   1081  1.1.1.2  fvdl 
   1082  1.1.1.2  fvdl /*
   1083  1.1.1.2  fvdl  * "close" a line discipline
   1084  1.1.1.2  fvdl  */
   1085  1.1.1.2  fvdl int
   1086  1.1.1.2  fvdl ttylclose(tp, flag)
   1087  1.1.1.2  fvdl 	struct tty *tp;
   1088  1.1.1.2  fvdl 	int flag;
   1089  1.1.1.2  fvdl {
   1090  1.1.1.2  fvdl 
   1091  1.1.1.2  fvdl 	if (flag & IO_NDELAY)
   1092  1.1.1.2  fvdl 		ttyflush(tp, FREAD | FWRITE);
   1093  1.1.1.2  fvdl 	else
   1094  1.1.1.2  fvdl 		ttywflush(tp);
   1095  1.1.1.2  fvdl 	return (0);
   1096  1.1.1.2  fvdl }
   1097  1.1.1.2  fvdl 
   1098  1.1.1.2  fvdl /*
   1099  1.1.1.2  fvdl  * Handle modem control transition on a tty.
   1100  1.1.1.2  fvdl  * Flag indicates new state of carrier.
   1101  1.1.1.2  fvdl  * Returns 0 if the line should be turned off, otherwise 1.
   1102  1.1.1.2  fvdl  */
   1103  1.1.1.2  fvdl int
   1104  1.1.1.2  fvdl ttymodem(tp, flag)
   1105  1.1.1.2  fvdl 	register struct tty *tp;
   1106  1.1.1.2  fvdl 	int flag;
   1107  1.1.1.2  fvdl {
   1108  1.1.1.2  fvdl 
   1109  1.1.1.2  fvdl 	if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
   1110  1.1.1.2  fvdl 		/*
   1111  1.1.1.2  fvdl 		 * MDMBUF: do flow control according to carrier flag
   1112  1.1.1.2  fvdl 		 */
   1113  1.1.1.2  fvdl 		if (flag) {
   1114  1.1.1.2  fvdl 			CLR(tp->t_state, TS_TTSTOP);
   1115  1.1.1.2  fvdl 			ttstart(tp);
   1116  1.1.1.2  fvdl 		} else if (!ISSET(tp->t_state, TS_TTSTOP)) {
   1117  1.1.1.2  fvdl 			SET(tp->t_state, TS_TTSTOP);
   1118  1.1.1.2  fvdl #ifdef sun4c						/* XXX */
   1119  1.1.1.2  fvdl 			(*tp->t_stop)(tp, 0);
   1120  1.1.1.2  fvdl #else
   1121  1.1.1.2  fvdl 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
   1122  1.1.1.2  fvdl #endif
   1123  1.1.1.2  fvdl 		}
   1124  1.1.1.2  fvdl 	} else if (flag == 0) {
   1125  1.1.1.2  fvdl 		/*
   1126  1.1.1.2  fvdl 		 * Lost carrier.
   1127  1.1.1.2  fvdl 		 */
   1128  1.1.1.2  fvdl 		CLR(tp->t_state, TS_CARR_ON);
   1129  1.1.1.2  fvdl 		if (ISSET(tp->t_state, TS_ISOPEN) &&
   1130  1.1.1.2  fvdl 		    !ISSET(tp->t_cflag, CLOCAL)) {
   1131  1.1.1.2  fvdl 			if (tp->t_session && tp->t_session->s_leader)
   1132  1.1.1.2  fvdl 				psignal(tp->t_session->s_leader, SIGHUP);
   1133  1.1.1.2  fvdl 			ttyflush(tp, FREAD | FWRITE);
   1134  1.1.1.2  fvdl 			return (0);
   1135  1.1.1.2  fvdl 		}
   1136  1.1.1.2  fvdl 	} else {
   1137  1.1.1.2  fvdl 		/*
   1138  1.1.1.2  fvdl 		 * Carrier now on.
   1139  1.1.1.2  fvdl 		 */
   1140  1.1.1.2  fvdl 		SET(tp->t_state, TS_CARR_ON);
   1141  1.1.1.2  fvdl 		ttwakeup(tp);
   1142  1.1.1.2  fvdl 	}
   1143  1.1.1.2  fvdl 	return (1);
   1144  1.1.1.2  fvdl }
   1145  1.1.1.2  fvdl 
   1146  1.1.1.2  fvdl /*
   1147  1.1.1.2  fvdl  * Default modem control routine (for other line disciplines).
   1148  1.1.1.2  fvdl  * Return argument flag, to turn off device on carrier drop.
   1149  1.1.1.2  fvdl  */
   1150  1.1.1.2  fvdl int
   1151  1.1.1.2  fvdl nullmodem(tp, flag)
   1152  1.1.1.2  fvdl 	register struct tty *tp;
   1153  1.1.1.2  fvdl 	int flag;
   1154  1.1.1.2  fvdl {
   1155  1.1.1.2  fvdl 
   1156  1.1.1.2  fvdl 	if (flag)
   1157  1.1.1.2  fvdl 		SET(tp->t_state, TS_CARR_ON);
   1158  1.1.1.2  fvdl 	else {
   1159  1.1.1.2  fvdl 		CLR(tp->t_state, TS_CARR_ON);
   1160  1.1.1.2  fvdl 		if (!ISSET(tp->t_cflag, CLOCAL)) {
   1161  1.1.1.2  fvdl 			if (tp->t_session && tp->t_session->s_leader)
   1162  1.1.1.2  fvdl 				psignal(tp->t_session->s_leader, SIGHUP);
   1163  1.1.1.2  fvdl 			return (0);
   1164  1.1.1.2  fvdl 		}
   1165  1.1.1.2  fvdl 	}
   1166  1.1.1.2  fvdl 	return (1);
   1167  1.1.1.2  fvdl }
   1168  1.1.1.2  fvdl 
   1169  1.1.1.2  fvdl /*
   1170  1.1.1.2  fvdl  * Reinput pending characters after state switch
   1171  1.1.1.2  fvdl  * call at spltty().
   1172  1.1.1.2  fvdl  */
   1173  1.1.1.2  fvdl void
   1174  1.1.1.2  fvdl ttypend(tp)
   1175  1.1.1.2  fvdl 	register struct tty *tp;
   1176  1.1.1.2  fvdl {
   1177  1.1.1.2  fvdl 	struct clist tq;
   1178  1.1.1.2  fvdl 	register c;
   1179  1.1.1.2  fvdl 
   1180  1.1.1.2  fvdl 	CLR(tp->t_lflag, PENDIN);
   1181  1.1.1.2  fvdl 	SET(tp->t_state, TS_TYPEN);
   1182  1.1.1.2  fvdl 	tq = tp->t_rawq;
   1183  1.1.1.2  fvdl 	tp->t_rawq.c_cc = 0;
   1184  1.1.1.2  fvdl 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
   1185  1.1.1.2  fvdl 	while ((c = getc(&tq)) >= 0)
   1186  1.1.1.2  fvdl 		ttyinput(c, tp);
   1187  1.1.1.2  fvdl 	CLR(tp->t_state, TS_TYPEN);
   1188  1.1.1.2  fvdl }
   1189  1.1.1.2  fvdl 
   1190  1.1.1.2  fvdl /*
   1191  1.1.1.2  fvdl  * Process a read call on a tty device.
   1192  1.1.1.2  fvdl  */
   1193  1.1.1.2  fvdl int
   1194  1.1.1.2  fvdl ttread(tp, uio, flag)
   1195  1.1.1.2  fvdl 	register struct tty *tp;
   1196  1.1.1.2  fvdl 	struct uio *uio;
   1197  1.1.1.2  fvdl 	int flag;
   1198  1.1.1.2  fvdl {
   1199  1.1.1.2  fvdl 	register struct clist *qp;
   1200  1.1.1.2  fvdl 	register int c;
   1201  1.1.1.2  fvdl 	register long lflag;
   1202  1.1.1.2  fvdl 	register u_char *cc = tp->t_cc;
   1203  1.1.1.2  fvdl 	register struct proc *p = curproc;
   1204  1.1.1.2  fvdl 	int s, first, error = 0;
   1205  1.1.1.2  fvdl 
   1206  1.1.1.2  fvdl loop:	lflag = tp->t_lflag;
   1207  1.1.1.2  fvdl 	s = spltty();
   1208  1.1.1.2  fvdl 	/*
   1209  1.1.1.2  fvdl 	 * take pending input first
   1210  1.1.1.2  fvdl 	 */
   1211  1.1.1.2  fvdl 	if (ISSET(lflag, PENDIN))
   1212  1.1.1.2  fvdl 		ttypend(tp);
   1213  1.1.1.2  fvdl 	splx(s);
   1214  1.1.1.2  fvdl 
   1215  1.1.1.2  fvdl 	/*
   1216  1.1.1.2  fvdl 	 * Hang process if it's in the background.
   1217  1.1.1.2  fvdl 	 */
   1218  1.1.1.2  fvdl 	if (isbackground(p, tp)) {
   1219  1.1.1.2  fvdl 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
   1220  1.1.1.2  fvdl 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
   1221  1.1.1.2  fvdl 		    p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)
   1222  1.1.1.2  fvdl 			return (EIO);
   1223  1.1.1.2  fvdl 		pgsignal(p->p_pgrp, SIGTTIN, 1);
   1224  1.1.1.2  fvdl 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
   1225  1.1.1.2  fvdl 			return (error);
   1226  1.1.1.2  fvdl 		goto loop;
   1227  1.1.1.2  fvdl 	}
   1228  1.1.1.2  fvdl 
   1229  1.1.1.2  fvdl 	/*
   1230  1.1.1.2  fvdl 	 * If canonical, use the canonical queue,
   1231  1.1.1.2  fvdl 	 * else use the raw queue.
   1232  1.1.1.2  fvdl 	 *
   1233  1.1.1.2  fvdl 	 * (should get rid of clists...)
   1234  1.1.1.2  fvdl 	 */
   1235  1.1.1.2  fvdl 	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
   1236  1.1.1.2  fvdl 
   1237  1.1.1.2  fvdl 	/*
   1238  1.1.1.2  fvdl 	 * If there is no input, sleep on rawq
   1239  1.1.1.2  fvdl 	 * awaiting hardware receipt and notification.
   1240  1.1.1.2  fvdl 	 * If we have data, we don't need to check for carrier.
   1241  1.1.1.2  fvdl 	 */
   1242  1.1.1.2  fvdl 	s = spltty();
   1243  1.1.1.2  fvdl 	if (qp->c_cc <= 0) {
   1244  1.1.1.2  fvdl 		int carrier;
   1245  1.1.1.2  fvdl 
   1246  1.1.1.2  fvdl 		carrier = ISSET(tp->t_state, TS_CARR_ON) ||
   1247  1.1.1.2  fvdl 		    ISSET(tp->t_cflag, CLOCAL);
   1248  1.1.1.2  fvdl 		if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
   1249  1.1.1.2  fvdl 			splx(s);
   1250  1.1.1.2  fvdl 			return (0);	/* EOF */
   1251  1.1.1.2  fvdl 		}
   1252  1.1.1.2  fvdl 		if (flag & IO_NDELAY) {
   1253  1.1.1.2  fvdl 			splx(s);
   1254  1.1.1.2  fvdl 			return (EWOULDBLOCK);
   1255  1.1.1.2  fvdl 		}
   1256  1.1.1.2  fvdl 		error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
   1257  1.1.1.2  fvdl 		    carrier ? ttyin : ttopen, 0);
   1258  1.1.1.2  fvdl 		splx(s);
   1259  1.1.1.2  fvdl 		if (error)
   1260  1.1.1.2  fvdl 			return (error);
   1261  1.1.1.2  fvdl 		goto loop;
   1262  1.1.1.2  fvdl 	}
   1263  1.1.1.2  fvdl 	splx(s);
   1264  1.1.1.2  fvdl 
   1265  1.1.1.2  fvdl 	/*
   1266  1.1.1.2  fvdl 	 * Input present, check for input mapping and processing.
   1267  1.1.1.2  fvdl 	 */
   1268  1.1.1.2  fvdl 	first = 1;
   1269  1.1.1.2  fvdl 	while ((c = getc(qp)) >= 0) {
   1270  1.1.1.2  fvdl 		/*
   1271  1.1.1.2  fvdl 		 * delayed suspend (^Y)
   1272  1.1.1.2  fvdl 		 */
   1273  1.1.1.2  fvdl 		if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {
   1274  1.1.1.2  fvdl 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
   1275  1.1.1.2  fvdl 			if (first) {
   1276  1.1.1.2  fvdl 				if (error = ttysleep(tp,
   1277  1.1.1.2  fvdl 				    &lbolt, TTIPRI | PCATCH, ttybg, 0))
   1278  1.1.1.2  fvdl 					break;
   1279  1.1.1.2  fvdl 				goto loop;
   1280  1.1.1.2  fvdl 			}
   1281  1.1.1.2  fvdl 			break;
   1282  1.1.1.2  fvdl 		}
   1283  1.1.1.2  fvdl 		/*
   1284  1.1.1.2  fvdl 		 * Interpret EOF only in canonical mode.
   1285  1.1.1.2  fvdl 		 */
   1286  1.1.1.2  fvdl 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
   1287  1.1.1.2  fvdl 			break;
   1288  1.1.1.2  fvdl 		/*
   1289  1.1.1.2  fvdl 		 * Give user character.
   1290  1.1.1.2  fvdl 		 */
   1291  1.1.1.2  fvdl  		error = ureadc(c, uio);
   1292  1.1.1.2  fvdl 		if (error)
   1293  1.1.1.2  fvdl 			break;
   1294  1.1.1.2  fvdl  		if (uio->uio_resid == 0)
   1295  1.1.1.2  fvdl 			break;
   1296  1.1.1.2  fvdl 		/*
   1297  1.1.1.2  fvdl 		 * In canonical mode check for a "break character"
   1298  1.1.1.2  fvdl 		 * marking the end of a "line of input".
   1299  1.1.1.2  fvdl 		 */
   1300  1.1.1.2  fvdl 		if (ISSET(lflag, ICANON) && TTBREAKC(c))
   1301  1.1.1.2  fvdl 			break;
   1302  1.1.1.2  fvdl 		first = 0;
   1303  1.1.1.2  fvdl 	}
   1304  1.1.1.2  fvdl 	/*
   1305  1.1.1.2  fvdl 	 * Look to unblock output now that (presumably)
   1306  1.1.1.2  fvdl 	 * the input queue has gone down.
   1307  1.1.1.2  fvdl 	 */
   1308  1.1.1.2  fvdl 	s = spltty();
   1309  1.1.1.2  fvdl 	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
   1310  1.1.1.2  fvdl 		if (cc[VSTART] != _POSIX_VDISABLE &&
   1311  1.1.1.2  fvdl 		    putc(cc[VSTART], &tp->t_outq) == 0) {
   1312  1.1.1.2  fvdl 			CLR(tp->t_state, TS_TBLOCK);
   1313  1.1.1.2  fvdl 			ttstart(tp);
   1314  1.1.1.2  fvdl 		}
   1315  1.1.1.2  fvdl 	}
   1316  1.1.1.2  fvdl 	splx(s);
   1317  1.1.1.2  fvdl 	return (error);
   1318  1.1.1.2  fvdl }
   1319  1.1.1.2  fvdl 
   1320  1.1.1.2  fvdl /*
   1321  1.1.1.2  fvdl  * Check the output queue on tp for space for a kernel message (from uprintf
   1322  1.1.1.2  fvdl  * or tprintf).  Allow some space over the normal hiwater mark so we don't
   1323  1.1.1.2  fvdl  * lose messages due to normal flow control, but don't let the tty run amok.
   1324  1.1.1.2  fvdl  * Sleeps here are not interruptible, but we return prematurely if new signals
   1325  1.1.1.2  fvdl  * arrive.
   1326  1.1.1.2  fvdl  */
   1327  1.1.1.2  fvdl int
   1328  1.1.1.2  fvdl ttycheckoutq(tp, wait)
   1329  1.1.1.2  fvdl 	register struct tty *tp;
   1330  1.1.1.2  fvdl 	int wait;
   1331  1.1.1.2  fvdl {
   1332  1.1.1.2  fvdl 	int hiwat, s, oldsig;
   1333  1.1.1.2  fvdl 
   1334  1.1.1.2  fvdl 	hiwat = tp->t_hiwat;
   1335  1.1.1.2  fvdl 	s = spltty();
   1336  1.1.1.2  fvdl 	oldsig = wait ? curproc->p_siglist : 0;
   1337  1.1.1.2  fvdl 	if (tp->t_outq.c_cc > hiwat + 200)
   1338  1.1.1.2  fvdl 		while (tp->t_outq.c_cc > hiwat) {
   1339  1.1.1.2  fvdl 			ttstart(tp);
   1340  1.1.1.2  fvdl 			if (wait == 0 || curproc->p_siglist != oldsig) {
   1341  1.1.1.2  fvdl 				splx(s);
   1342  1.1.1.2  fvdl 				return (0);
   1343  1.1.1.2  fvdl 			}
   1344  1.1.1.2  fvdl 			timeout((void (*)__P((void *)))wakeup,
   1345  1.1.1.2  fvdl 			    (void *)&tp->t_outq, hz);
   1346  1.1.1.2  fvdl 			SET(tp->t_state, TS_ASLEEP);
   1347  1.1.1.2  fvdl 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
   1348  1.1.1.2  fvdl 		}
   1349  1.1.1.2  fvdl 	splx(s);
   1350  1.1.1.2  fvdl 	return (1);
   1351  1.1.1.2  fvdl }
   1352  1.1.1.2  fvdl 
   1353  1.1.1.2  fvdl /*
   1354  1.1.1.2  fvdl  * Process a write call on a tty device.
   1355  1.1.1.2  fvdl  */
   1356  1.1.1.2  fvdl int
   1357  1.1.1.2  fvdl ttwrite(tp, uio, flag)
   1358  1.1.1.2  fvdl 	register struct tty *tp;
   1359  1.1.1.2  fvdl 	register struct uio *uio;
   1360  1.1.1.2  fvdl 	int flag;
   1361  1.1.1.2  fvdl {
   1362  1.1.1.2  fvdl 	register char *cp;
   1363  1.1.1.2  fvdl 	register int cc, ce;
   1364  1.1.1.2  fvdl 	register struct proc *p;
   1365  1.1.1.2  fvdl 	int i, hiwat, cnt, error, s;
   1366  1.1.1.2  fvdl 	char obuf[OBUFSIZ];
   1367  1.1.1.2  fvdl 
   1368  1.1.1.2  fvdl 	hiwat = tp->t_hiwat;
   1369  1.1.1.2  fvdl 	cnt = uio->uio_resid;
   1370  1.1.1.2  fvdl 	error = 0;
   1371  1.1.1.2  fvdl 	cc = 0;
   1372  1.1.1.2  fvdl loop:
   1373  1.1.1.2  fvdl 	s = spltty();
   1374  1.1.1.2  fvdl 	if (!ISSET(tp->t_state, TS_CARR_ON) &&
   1375  1.1.1.2  fvdl 	    !ISSET(tp->t_cflag, CLOCAL)) {
   1376  1.1.1.2  fvdl 		if (ISSET(tp->t_state, TS_ISOPEN)) {
   1377  1.1.1.2  fvdl 			splx(s);
   1378  1.1.1.2  fvdl 			return (EIO);
   1379  1.1.1.2  fvdl 		} else if (flag & IO_NDELAY) {
   1380  1.1.1.2  fvdl 			splx(s);
   1381  1.1.1.2  fvdl 			error = EWOULDBLOCK;
   1382  1.1.1.2  fvdl 			goto out;
   1383  1.1.1.2  fvdl 		} else {
   1384  1.1.1.2  fvdl 			/* Sleep awaiting carrier. */
   1385  1.1.1.2  fvdl 			error = ttysleep(tp,
   1386  1.1.1.2  fvdl 			    &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);
   1387  1.1.1.2  fvdl 			splx(s);
   1388  1.1.1.2  fvdl 			if (error)
   1389  1.1.1.2  fvdl 				goto out;
   1390  1.1.1.2  fvdl 			goto loop;
   1391  1.1.1.2  fvdl 		}
   1392  1.1.1.2  fvdl 	}
   1393  1.1.1.2  fvdl 	splx(s);
   1394  1.1.1.2  fvdl 	/*
   1395  1.1.1.2  fvdl 	 * Hang the process if it's in the background.
   1396  1.1.1.2  fvdl 	 */
   1397  1.1.1.2  fvdl 	p = curproc;
   1398  1.1.1.2  fvdl 	if (isbackground(p, tp) &&
   1399  1.1.1.2  fvdl 	    ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
   1400  1.1.1.2  fvdl 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
   1401  1.1.1.2  fvdl 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
   1402  1.1.1.2  fvdl 	     p->p_pgrp->pg_jobc) {
   1403  1.1.1.2  fvdl 		pgsignal(p->p_pgrp, SIGTTOU, 1);
   1404  1.1.1.2  fvdl 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
   1405  1.1.1.2  fvdl 			goto out;
   1406  1.1.1.2  fvdl 		goto loop;
   1407  1.1.1.2  fvdl 	}
   1408  1.1.1.2  fvdl 	/*
   1409  1.1.1.2  fvdl 	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
   1410  1.1.1.2  fvdl 	 * output translation.  Keep track of high water mark, sleep on
   1411  1.1.1.2  fvdl 	 * overflow awaiting device aid in acquiring new space.
   1412  1.1.1.2  fvdl 	 */
   1413  1.1.1.2  fvdl 	while (uio->uio_resid > 0 || cc > 0) {
   1414  1.1.1.2  fvdl 		if (ISSET(tp->t_lflag, FLUSHO)) {
   1415  1.1.1.2  fvdl 			uio->uio_resid = 0;
   1416  1.1.1.2  fvdl 			return (0);
   1417  1.1.1.2  fvdl 		}
   1418  1.1.1.2  fvdl 		if (tp->t_outq.c_cc > hiwat)
   1419  1.1.1.2  fvdl 			goto ovhiwat;
   1420  1.1.1.2  fvdl 		/*
   1421  1.1.1.2  fvdl 		 * Grab a hunk of data from the user, unless we have some
   1422  1.1.1.2  fvdl 		 * leftover from last time.
   1423  1.1.1.2  fvdl 		 */
   1424  1.1.1.2  fvdl 		if (cc == 0) {
   1425  1.1.1.2  fvdl 			cc = min(uio->uio_resid, OBUFSIZ);
   1426  1.1.1.2  fvdl 			cp = obuf;
   1427  1.1.1.2  fvdl 			error = uiomove(cp, cc, uio);
   1428  1.1.1.2  fvdl 			if (error) {
   1429  1.1.1.2  fvdl 				cc = 0;
   1430  1.1.1.2  fvdl 				break;
   1431  1.1.1.2  fvdl 			}
   1432  1.1.1.2  fvdl 		}
   1433  1.1.1.2  fvdl 		/*
   1434  1.1.1.2  fvdl 		 * If nothing fancy need be done, grab those characters we
   1435  1.1.1.2  fvdl 		 * can handle without any of ttyoutput's processing and
   1436  1.1.1.2  fvdl 		 * just transfer them to the output q.  For those chars
   1437  1.1.1.2  fvdl 		 * which require special processing (as indicated by the
   1438  1.1.1.2  fvdl 		 * bits in char_type), call ttyoutput.  After processing
   1439  1.1.1.2  fvdl 		 * a hunk of data, look for FLUSHO so ^O's will take effect
   1440  1.1.1.2  fvdl 		 * immediately.
   1441  1.1.1.2  fvdl 		 */
   1442  1.1.1.2  fvdl 		while (cc > 0) {
   1443  1.1.1.2  fvdl 			if (!ISSET(tp->t_oflag, OPOST))
   1444  1.1.1.2  fvdl 				ce = cc;
   1445  1.1.1.2  fvdl 			else {
   1446  1.1.1.2  fvdl 				ce = cc - scanc((u_int)cc, (u_char *)cp,
   1447  1.1.1.2  fvdl 				   (u_char *)char_type, CCLASSMASK);
   1448  1.1.1.2  fvdl 				/*
   1449  1.1.1.2  fvdl 				 * If ce is zero, then we're processing
   1450  1.1.1.2  fvdl 				 * a special character through ttyoutput.
   1451  1.1.1.2  fvdl 				 */
   1452  1.1.1.2  fvdl 				if (ce == 0) {
   1453  1.1.1.2  fvdl 					tp->t_rocount = 0;
   1454  1.1.1.2  fvdl 					if (ttyoutput(*cp, tp) >= 0) {
   1455  1.1.1.2  fvdl 						/* No Clists, wait a bit. */
   1456  1.1.1.2  fvdl 						ttstart(tp);
   1457  1.1.1.2  fvdl 						if (error = ttysleep(tp, &lbolt,
   1458  1.1.1.2  fvdl 						    TTOPRI | PCATCH, ttybuf, 0))
   1459  1.1.1.2  fvdl 							break;
   1460  1.1.1.2  fvdl 						goto loop;
   1461  1.1.1.2  fvdl 					}
   1462  1.1.1.2  fvdl 					cp++;
   1463  1.1.1.2  fvdl 					cc--;
   1464  1.1.1.2  fvdl 					if (ISSET(tp->t_lflag, FLUSHO) ||
   1465  1.1.1.2  fvdl 					    tp->t_outq.c_cc > hiwat)
   1466  1.1.1.2  fvdl 						goto ovhiwat;
   1467  1.1.1.2  fvdl 					continue;
   1468  1.1.1.2  fvdl 				}
   1469  1.1.1.2  fvdl 			}
   1470  1.1.1.2  fvdl 			/*
   1471  1.1.1.2  fvdl 			 * A bunch of normal characters have been found.
   1472  1.1.1.2  fvdl 			 * Transfer them en masse to the output queue and
   1473  1.1.1.2  fvdl 			 * continue processing at the top of the loop.
   1474  1.1.1.2  fvdl 			 * If there are any further characters in this
   1475  1.1.1.2  fvdl 			 * <= OBUFSIZ chunk, the first should be a character
   1476  1.1.1.2  fvdl 			 * requiring special handling by ttyoutput.
   1477  1.1.1.2  fvdl 			 */
   1478  1.1.1.2  fvdl 			tp->t_rocount = 0;
   1479  1.1.1.2  fvdl 			i = b_to_q(cp, ce, &tp->t_outq);
   1480  1.1.1.2  fvdl 			ce -= i;
   1481  1.1.1.2  fvdl 			tp->t_column += ce;
   1482  1.1.1.2  fvdl 			cp += ce, cc -= ce, tk_nout += ce;
   1483  1.1.1.2  fvdl 			tp->t_outcc += ce;
   1484  1.1.1.2  fvdl 			if (i > 0) {
   1485  1.1.1.2  fvdl 				/* No Clists, wait a bit. */
   1486  1.1.1.2  fvdl 				ttstart(tp);
   1487  1.1.1.2  fvdl 				if (error = ttysleep(tp,
   1488  1.1.1.2  fvdl 				    &lbolt, TTOPRI | PCATCH, ttybuf, 0))
   1489  1.1.1.2  fvdl 					break;
   1490  1.1.1.2  fvdl 				goto loop;
   1491  1.1.1.2  fvdl 			}
   1492  1.1.1.2  fvdl 			if (ISSET(tp->t_lflag, FLUSHO) ||
   1493  1.1.1.2  fvdl 			    tp->t_outq.c_cc > hiwat)
   1494  1.1.1.2  fvdl 				break;
   1495  1.1.1.2  fvdl 		}
   1496  1.1.1.2  fvdl 		ttstart(tp);
   1497  1.1.1.2  fvdl 	}
   1498  1.1.1.2  fvdl out:
   1499  1.1.1.2  fvdl 	/*
   1500  1.1.1.2  fvdl 	 * If cc is nonzero, we leave the uio structure inconsistent, as the
   1501  1.1.1.2  fvdl 	 * offset and iov pointers have moved forward, but it doesn't matter
   1502  1.1.1.2  fvdl 	 * (the call will either return short or restart with a new uio).
   1503  1.1.1.2  fvdl 	 */
   1504  1.1.1.2  fvdl 	uio->uio_resid += cc;
   1505  1.1.1.2  fvdl 	return (error);
   1506  1.1.1.2  fvdl 
   1507  1.1.1.2  fvdl ovhiwat:
   1508  1.1.1.2  fvdl 	ttstart(tp);
   1509  1.1.1.2  fvdl 	s = spltty();
   1510  1.1.1.2  fvdl 	/*
   1511  1.1.1.2  fvdl 	 * This can only occur if FLUSHO is set in t_lflag,
   1512  1.1.1.2  fvdl 	 * or if ttstart/oproc is synchronous (or very fast).
   1513  1.1.1.2  fvdl 	 */
   1514  1.1.1.2  fvdl 	if (tp->t_outq.c_cc <= hiwat) {
   1515  1.1.1.2  fvdl 		splx(s);
   1516  1.1.1.2  fvdl 		goto loop;
   1517  1.1.1.2  fvdl 	}
   1518  1.1.1.2  fvdl 	if (flag & IO_NDELAY) {
   1519  1.1.1.2  fvdl 		splx(s);
   1520  1.1.1.2  fvdl 		uio->uio_resid += cc;
   1521  1.1.1.2  fvdl 		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
   1522  1.1.1.2  fvdl 	}
   1523  1.1.1.2  fvdl 	SET(tp->t_state, TS_ASLEEP);
   1524  1.1.1.2  fvdl 	error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
   1525  1.1.1.2  fvdl 	splx(s);
   1526  1.1.1.2  fvdl 	if (error)
   1527  1.1.1.2  fvdl 		goto out;
   1528  1.1.1.2  fvdl 	goto loop;
   1529  1.1.1.2  fvdl }
   1530  1.1.1.2  fvdl 
   1531  1.1.1.2  fvdl /*
   1532  1.1.1.2  fvdl  * Rubout one character from the rawq of tp
   1533  1.1.1.2  fvdl  * as cleanly as possible.
   1534  1.1.1.2  fvdl  */
   1535  1.1.1.2  fvdl void
   1536  1.1.1.2  fvdl ttyrub(c, tp)
   1537  1.1.1.2  fvdl 	register int c;
   1538  1.1.1.2  fvdl 	register struct tty *tp;
   1539  1.1.1.2  fvdl {
   1540  1.1.1.2  fvdl 	register char *cp;
   1541  1.1.1.2  fvdl 	register int savecol;
   1542  1.1.1.2  fvdl 	int tabc, s;
   1543  1.1.1.2  fvdl 
   1544  1.1.1.2  fvdl 	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
   1545  1.1.1.2  fvdl 		return;
   1546  1.1.1.2  fvdl 	CLR(tp->t_lflag, FLUSHO);
   1547  1.1.1.2  fvdl 	if (ISSET(tp->t_lflag, ECHOE)) {
   1548  1.1.1.2  fvdl 		if (tp->t_rocount == 0) {
   1549  1.1.1.2  fvdl 			/*
   1550  1.1.1.2  fvdl 			 * Screwed by ttwrite; retype
   1551  1.1.1.2  fvdl 			 */
   1552  1.1.1.2  fvdl 			ttyretype(tp);
   1553  1.1.1.2  fvdl 			return;
   1554  1.1.1.2  fvdl 		}
   1555  1.1.1.2  fvdl 		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
   1556  1.1.1.2  fvdl 			ttyrubo(tp, 2);
   1557  1.1.1.2  fvdl 		else {
   1558  1.1.1.2  fvdl 			CLR(c, ~TTY_CHARMASK);
   1559  1.1.1.2  fvdl 			switch (CCLASS(c)) {
   1560  1.1.1.2  fvdl 			case ORDINARY:
   1561  1.1.1.2  fvdl 				ttyrubo(tp, 1);
   1562  1.1.1.2  fvdl 				break;
   1563  1.1.1.2  fvdl 			case BACKSPACE:
   1564  1.1.1.2  fvdl 			case CONTROL:
   1565  1.1.1.2  fvdl 			case NEWLINE:
   1566  1.1.1.2  fvdl 			case RETURN:
   1567  1.1.1.2  fvdl 			case VTAB:
   1568  1.1.1.2  fvdl 				if (ISSET(tp->t_lflag, ECHOCTL))
   1569  1.1.1.2  fvdl 					ttyrubo(tp, 2);
   1570  1.1.1.2  fvdl 				break;
   1571  1.1.1.2  fvdl 			case TAB:
   1572  1.1.1.2  fvdl 				if (tp->t_rocount < tp->t_rawq.c_cc) {
   1573  1.1.1.2  fvdl 					ttyretype(tp);
   1574  1.1.1.2  fvdl 					return;
   1575  1.1.1.2  fvdl 				}
   1576  1.1.1.2  fvdl 				s = spltty();
   1577  1.1.1.2  fvdl 				savecol = tp->t_column;
   1578  1.1.1.2  fvdl 				SET(tp->t_state, TS_CNTTB);
   1579  1.1.1.2  fvdl 				SET(tp->t_lflag, FLUSHO);
   1580  1.1.1.2  fvdl 				tp->t_column = tp->t_rocol;
   1581  1.1.1.2  fvdl 				cp = tp->t_rawq.c_cf;
   1582  1.1.1.2  fvdl 				if (cp)
   1583  1.1.1.2  fvdl 					tabc = *cp;	/* XXX FIX NEXTC */
   1584  1.1.1.2  fvdl 				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
   1585  1.1.1.2  fvdl 					ttyecho(tabc, tp);
   1586  1.1.1.2  fvdl 				CLR(tp->t_lflag, FLUSHO);
   1587  1.1.1.2  fvdl 				CLR(tp->t_state, TS_CNTTB);
   1588  1.1.1.2  fvdl 				splx(s);
   1589  1.1.1.2  fvdl 
   1590  1.1.1.2  fvdl 				/* savecol will now be length of the tab. */
   1591  1.1.1.2  fvdl 				savecol -= tp->t_column;
   1592  1.1.1.2  fvdl 				tp->t_column += savecol;
   1593  1.1.1.2  fvdl 				if (savecol > 8)
   1594  1.1.1.2  fvdl 					savecol = 8;	/* overflow screw */
   1595  1.1.1.2  fvdl 				while (--savecol >= 0)
   1596  1.1.1.2  fvdl 					(void)ttyoutput('\b', tp);
   1597  1.1.1.2  fvdl 				break;
   1598  1.1.1.2  fvdl 			default:			/* XXX */
   1599  1.1.1.2  fvdl #define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
   1600  1.1.1.2  fvdl 				(void)printf(PANICSTR, c, CCLASS(c));
   1601  1.1.1.2  fvdl #ifdef notdef
   1602  1.1.1.2  fvdl 				panic(PANICSTR, c, CCLASS(c));
   1603  1.1.1.2  fvdl #endif
   1604  1.1.1.2  fvdl 			}
   1605  1.1.1.2  fvdl 		}
   1606  1.1.1.2  fvdl 	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
   1607  1.1.1.2  fvdl 		if (!ISSET(tp->t_state, TS_ERASE)) {
   1608  1.1.1.2  fvdl 			SET(tp->t_state, TS_ERASE);
   1609  1.1.1.2  fvdl 			(void)ttyoutput('\\', tp);
   1610  1.1.1.2  fvdl 		}
   1611  1.1.1.2  fvdl 		ttyecho(c, tp);
   1612  1.1.1.2  fvdl 	} else
   1613  1.1.1.2  fvdl 		ttyecho(tp->t_cc[VERASE], tp);
   1614  1.1.1.2  fvdl 	--tp->t_rocount;
   1615  1.1.1.2  fvdl }
   1616  1.1.1.2  fvdl 
   1617  1.1.1.2  fvdl /*
   1618  1.1.1.2  fvdl  * Back over cnt characters, erasing them.
   1619  1.1.1.2  fvdl  */
   1620  1.1.1.2  fvdl static void
   1621  1.1.1.2  fvdl ttyrubo(tp, cnt)
   1622  1.1.1.2  fvdl 	register struct tty *tp;
   1623  1.1.1.2  fvdl 	int cnt;
   1624  1.1.1.2  fvdl {
   1625  1.1.1.2  fvdl 
   1626  1.1.1.2  fvdl 	while (cnt-- > 0) {
   1627  1.1.1.2  fvdl 		(void)ttyoutput('\b', tp);
   1628  1.1.1.2  fvdl 		(void)ttyoutput(' ', tp);
   1629  1.1.1.2  fvdl 		(void)ttyoutput('\b', tp);
   1630  1.1.1.2  fvdl 	}
   1631  1.1.1.2  fvdl }
   1632  1.1.1.2  fvdl 
   1633  1.1.1.2  fvdl /*
   1634  1.1.1.2  fvdl  * ttyretype --
   1635  1.1.1.2  fvdl  *	Reprint the rawq line.  Note, it is assumed that c_cc has already
   1636  1.1.1.2  fvdl  *	been checked.
   1637  1.1.1.2  fvdl  */
   1638  1.1.1.2  fvdl void
   1639  1.1.1.2  fvdl ttyretype(tp)
   1640  1.1.1.2  fvdl 	register struct tty *tp;
   1641  1.1.1.2  fvdl {
   1642  1.1.1.2  fvdl 	register char *cp;
   1643  1.1.1.2  fvdl 	int s, c;
   1644  1.1.1.2  fvdl 
   1645  1.1.1.2  fvdl 	/* Echo the reprint character. */
   1646  1.1.1.2  fvdl 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
   1647  1.1.1.2  fvdl 		ttyecho(tp->t_cc[VREPRINT], tp);
   1648  1.1.1.2  fvdl 
   1649  1.1.1.2  fvdl 	(void)ttyoutput('\n', tp);
   1650  1.1.1.2  fvdl 
   1651  1.1.1.2  fvdl 	/*
   1652  1.1.1.2  fvdl 	 * XXX
   1653  1.1.1.2  fvdl 	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
   1654  1.1.1.2  fvdl 	 * BIT OF FIRST CHAR.
   1655  1.1.1.2  fvdl 	 */
   1656  1.1.1.2  fvdl 	s = spltty();
   1657  1.1.1.2  fvdl 	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
   1658  1.1.1.2  fvdl 	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
   1659  1.1.1.2  fvdl 		ttyecho(c, tp);
   1660  1.1.1.2  fvdl 	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
   1661  1.1.1.2  fvdl 	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
   1662  1.1.1.2  fvdl 		ttyecho(c, tp);
   1663  1.1.1.2  fvdl 	CLR(tp->t_state, TS_ERASE);
   1664  1.1.1.2  fvdl 	splx(s);
   1665  1.1.1.2  fvdl 
   1666  1.1.1.2  fvdl 	tp->t_rocount = tp->t_rawq.c_cc;
   1667  1.1.1.2  fvdl 	tp->t_rocol = 0;
   1668  1.1.1.2  fvdl }
   1669  1.1.1.2  fvdl 
   1670  1.1.1.2  fvdl /*
   1671  1.1.1.2  fvdl  * Echo a typed character to the terminal.
   1672  1.1.1.2  fvdl  */
   1673  1.1.1.2  fvdl static void
   1674  1.1.1.2  fvdl ttyecho(c, tp)
   1675  1.1.1.2  fvdl 	register int c;
   1676  1.1.1.2  fvdl 	register struct tty *tp;
   1677  1.1.1.2  fvdl {
   1678  1.1.1.2  fvdl 
   1679  1.1.1.2  fvdl 	if (!ISSET(tp->t_state, TS_CNTTB))
   1680  1.1.1.2  fvdl 		CLR(tp->t_lflag, FLUSHO);
   1681  1.1.1.2  fvdl 	if ((!ISSET(tp->t_lflag, ECHO) &&
   1682  1.1.1.2  fvdl 	    (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||
   1683  1.1.1.2  fvdl 	    ISSET(tp->t_lflag, EXTPROC))
   1684  1.1.1.2  fvdl 		return;
   1685  1.1.1.2  fvdl 	if (ISSET(tp->t_lflag, ECHOCTL) &&
   1686  1.1.1.2  fvdl 	    (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
   1687  1.1.1.2  fvdl 	    ISSET(c, TTY_CHARMASK) == 0177)) {
   1688  1.1.1.2  fvdl 		(void)ttyoutput('^', tp);
   1689  1.1.1.2  fvdl 		CLR(c, ~TTY_CHARMASK);
   1690  1.1.1.2  fvdl 		if (c == 0177)
   1691  1.1.1.2  fvdl 			c = '?';
   1692  1.1.1.2  fvdl 		else
   1693  1.1.1.2  fvdl 			c += 'A' - 1;
   1694  1.1.1.2  fvdl 	}
   1695  1.1.1.2  fvdl 	(void)ttyoutput(c, tp);
   1696  1.1.1.2  fvdl }
   1697  1.1.1.2  fvdl 
   1698  1.1.1.2  fvdl /*
   1699  1.1.1.2  fvdl  * Wake up any readers on a tty.
   1700  1.1.1.2  fvdl  */
   1701  1.1.1.2  fvdl void
   1702  1.1.1.2  fvdl ttwakeup(tp)
   1703  1.1.1.2  fvdl 	register struct tty *tp;
   1704  1.1.1.2  fvdl {
   1705  1.1.1.2  fvdl 
   1706  1.1.1.2  fvdl 	selwakeup(&tp->t_rsel);
   1707  1.1.1.2  fvdl 	if (ISSET(tp->t_state, TS_ASYNC))
   1708  1.1.1.2  fvdl 		pgsignal(tp->t_pgrp, SIGIO, 1);
   1709  1.1.1.2  fvdl 	wakeup((caddr_t)&tp->t_rawq);
   1710  1.1.1.2  fvdl }
   1711  1.1.1.2  fvdl 
   1712  1.1.1.2  fvdl /*
   1713  1.1.1.2  fvdl  * Look up a code for a specified speed in a conversion table;
   1714  1.1.1.2  fvdl  * used by drivers to map software speed values to hardware parameters.
   1715  1.1.1.2  fvdl  */
   1716  1.1.1.2  fvdl int
   1717  1.1.1.2  fvdl ttspeedtab(speed, table)
   1718  1.1.1.2  fvdl 	int speed;
   1719  1.1.1.2  fvdl 	register struct speedtab *table;
   1720  1.1.1.2  fvdl {
   1721  1.1.1.2  fvdl 
   1722  1.1.1.2  fvdl 	for ( ; table->sp_speed != -1; table++)
   1723  1.1.1.2  fvdl 		if (table->sp_speed == speed)
   1724  1.1.1.2  fvdl 			return (table->sp_code);
   1725  1.1.1.2  fvdl 	return (-1);
   1726  1.1.1.2  fvdl }
   1727  1.1.1.2  fvdl 
   1728  1.1.1.2  fvdl /*
   1729  1.1.1.2  fvdl  * Set tty hi and low water marks.
   1730  1.1.1.2  fvdl  *
   1731  1.1.1.2  fvdl  * Try to arrange the dynamics so there's about one second
   1732  1.1.1.2  fvdl  * from hi to low water.
   1733  1.1.1.2  fvdl  *
   1734  1.1.1.2  fvdl  */
   1735  1.1.1.2  fvdl void
   1736  1.1.1.2  fvdl ttsetwater(tp)
   1737  1.1.1.2  fvdl 	struct tty *tp;
   1738  1.1.1.2  fvdl {
   1739  1.1.1.2  fvdl 	register int cps, x;
   1740  1.1.1.2  fvdl 
   1741  1.1.1.2  fvdl #define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
   1742  1.1.1.2  fvdl 
   1743  1.1.1.2  fvdl 	cps = tp->t_ospeed / 10;
   1744  1.1.1.2  fvdl 	tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
   1745  1.1.1.2  fvdl 	x += cps;
   1746  1.1.1.2  fvdl 	x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
   1747  1.1.1.2  fvdl 	tp->t_hiwat = roundup(x, CBSIZE);
   1748  1.1.1.2  fvdl #undef	CLAMP
   1749  1.1.1.2  fvdl }
   1750  1.1.1.2  fvdl 
   1751  1.1.1.2  fvdl /*
   1752  1.1.1.2  fvdl  * Report on state of foreground process group.
   1753  1.1.1.2  fvdl  */
   1754  1.1.1.2  fvdl void
   1755  1.1.1.2  fvdl ttyinfo(tp)
   1756  1.1.1.2  fvdl 	register struct tty *tp;
   1757  1.1.1.2  fvdl {
   1758  1.1.1.2  fvdl 	register struct proc *p, *pick;
   1759  1.1.1.2  fvdl 	struct timeval utime, stime;
   1760  1.1.1.2  fvdl 	int tmp;
   1761  1.1.1.2  fvdl 
   1762  1.1.1.2  fvdl 	if (ttycheckoutq(tp,0) == 0)
   1763  1.1.1.2  fvdl 		return;
   1764  1.1.1.2  fvdl 
   1765  1.1.1.2  fvdl 	/* Print load average. */
   1766  1.1.1.2  fvdl 	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
   1767  1.1.1.2  fvdl 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
   1768  1.1.1.2  fvdl 
   1769  1.1.1.2  fvdl 	if (tp->t_session == NULL)
   1770  1.1.1.2  fvdl 		ttyprintf(tp, "not a controlling terminal\n");
   1771  1.1.1.2  fvdl 	else if (tp->t_pgrp == NULL)
   1772  1.1.1.2  fvdl 		ttyprintf(tp, "no foreground process group\n");
   1773  1.1.1.3  fvdl 	else if ((p = tp->t_pgrp->pg_members.lh_first) == 0)
   1774  1.1.1.2  fvdl 		ttyprintf(tp, "empty foreground process group\n");
   1775  1.1.1.2  fvdl 	else {
   1776  1.1.1.2  fvdl 		/* Pick interesting process. */
   1777  1.1.1.3  fvdl 		for (pick = NULL; p != 0; p = p->p_pglist.le_next)
   1778  1.1.1.2  fvdl 			if (proc_compare(pick, p))
   1779  1.1.1.2  fvdl 				pick = p;
   1780  1.1.1.2  fvdl 
   1781  1.1.1.2  fvdl 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
   1782  1.1.1.2  fvdl 		    pick->p_stat == SRUN ? "running" :
   1783  1.1.1.2  fvdl 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
   1784  1.1.1.2  fvdl 
   1785  1.1.1.2  fvdl 		calcru(pick, &utime, &stime, NULL);
   1786  1.1.1.2  fvdl 
   1787  1.1.1.2  fvdl 		/* Print user time. */
   1788  1.1.1.2  fvdl 		ttyprintf(tp, "%d.%02du ",
   1789  1.1.1.2  fvdl 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
   1790  1.1.1.2  fvdl 
   1791  1.1.1.2  fvdl 		/* Print system time. */
   1792  1.1.1.2  fvdl 		ttyprintf(tp, "%d.%02ds ",
   1793  1.1.1.2  fvdl 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
   1794  1.1.1.2  fvdl 
   1795  1.1.1.2  fvdl #define	pgtok(a)	(((a) * NBPG) / 1024)
   1796  1.1.1.2  fvdl 		/* Print percentage cpu, resident set size. */
   1797  1.1.1.2  fvdl 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
   1798  1.1.1.2  fvdl 		ttyprintf(tp, "%d%% %dk\n",
   1799  1.1.1.2  fvdl 		    tmp / 100,
   1800  1.1.1.2  fvdl 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
   1801  1.1.1.2  fvdl #ifdef pmap_resident_count
   1802  1.1.1.2  fvdl 			pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap))
   1803  1.1.1.2  fvdl #else
   1804  1.1.1.2  fvdl 			pgtok(pick->p_vmspace->vm_rssize)
   1805  1.1.1.2  fvdl #endif
   1806  1.1.1.2  fvdl 			);
   1807  1.1.1.2  fvdl 	}
   1808  1.1.1.2  fvdl 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
   1809  1.1.1.2  fvdl }
   1810  1.1.1.2  fvdl 
   1811  1.1.1.2  fvdl /*
   1812  1.1.1.2  fvdl  * Returns 1 if p2 is "better" than p1
   1813  1.1.1.2  fvdl  *
   1814  1.1.1.2  fvdl  * The algorithm for picking the "interesting" process is thus:
   1815  1.1.1.2  fvdl  *
   1816  1.1.1.2  fvdl  *	1) Only foreground processes are eligible - implied.
   1817  1.1.1.2  fvdl  *	2) Runnable processes are favored over anything else.  The runner
   1818  1.1.1.2  fvdl  *	   with the highest cpu utilization is picked (p_estcpu).  Ties are
   1819  1.1.1.2  fvdl  *	   broken by picking the highest pid.
   1820  1.1.1.2  fvdl  *	3) The sleeper with the shortest sleep time is next.  With ties,
   1821  1.1.1.2  fvdl  *	   we pick out just "short-term" sleepers (P_SINTR == 0).
   1822  1.1.1.2  fvdl  *	4) Further ties are broken by picking the highest pid.
   1823  1.1.1.2  fvdl  */
   1824  1.1.1.2  fvdl #define ISRUN(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
   1825  1.1.1.2  fvdl #define TESTAB(a, b)    ((a)<<1 | (b))
   1826  1.1.1.2  fvdl #define ONLYA   2
   1827  1.1.1.2  fvdl #define ONLYB   1
   1828  1.1.1.2  fvdl #define BOTH    3
   1829  1.1.1.2  fvdl 
   1830  1.1.1.2  fvdl static int
   1831  1.1.1.2  fvdl proc_compare(p1, p2)
   1832  1.1.1.2  fvdl 	register struct proc *p1, *p2;
   1833  1.1.1.2  fvdl {
   1834  1.1.1.2  fvdl 
   1835  1.1.1.2  fvdl 	if (p1 == NULL)
   1836  1.1.1.2  fvdl 		return (1);
   1837  1.1.1.2  fvdl 	/*
   1838  1.1.1.2  fvdl 	 * see if at least one of them is runnable
   1839  1.1.1.2  fvdl 	 */
   1840  1.1.1.2  fvdl 	switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
   1841  1.1.1.2  fvdl 	case ONLYA:
   1842  1.1.1.2  fvdl 		return (0);
   1843  1.1.1.2  fvdl 	case ONLYB:
   1844  1.1.1.2  fvdl 		return (1);
   1845  1.1.1.2  fvdl 	case BOTH:
   1846  1.1.1.2  fvdl 		/*
   1847  1.1.1.2  fvdl 		 * tie - favor one with highest recent cpu utilization
   1848  1.1.1.2  fvdl 		 */
   1849  1.1.1.2  fvdl 		if (p2->p_estcpu > p1->p_estcpu)
   1850  1.1.1.2  fvdl 			return (1);
   1851  1.1.1.2  fvdl 		if (p1->p_estcpu > p2->p_estcpu)
   1852  1.1.1.2  fvdl 			return (0);
   1853  1.1.1.2  fvdl 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
   1854  1.1.1.2  fvdl 	}
   1855  1.1.1.2  fvdl 	/*
   1856  1.1.1.2  fvdl  	 * weed out zombies
   1857  1.1.1.2  fvdl 	 */
   1858  1.1.1.2  fvdl 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
   1859  1.1.1.2  fvdl 	case ONLYA:
   1860  1.1.1.2  fvdl 		return (1);
   1861  1.1.1.2  fvdl 	case ONLYB:
   1862  1.1.1.2  fvdl 		return (0);
   1863  1.1.1.2  fvdl 	case BOTH:
   1864  1.1.1.2  fvdl 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
   1865  1.1.1.2  fvdl 	}
   1866  1.1.1.2  fvdl 	/*
   1867  1.1.1.2  fvdl 	 * pick the one with the smallest sleep time
   1868  1.1.1.2  fvdl 	 */
   1869  1.1.1.2  fvdl 	if (p2->p_slptime > p1->p_slptime)
   1870  1.1.1.2  fvdl 		return (0);
   1871  1.1.1.2  fvdl 	if (p1->p_slptime > p2->p_slptime)
   1872  1.1.1.2  fvdl 		return (1);
   1873  1.1.1.2  fvdl 	/*
   1874  1.1.1.2  fvdl 	 * favor one sleeping in a non-interruptible sleep
   1875  1.1.1.2  fvdl 	 */
   1876  1.1.1.2  fvdl 	if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
   1877  1.1.1.2  fvdl 		return (1);
   1878  1.1.1.2  fvdl 	if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
   1879  1.1.1.2  fvdl 		return (0);
   1880  1.1.1.2  fvdl 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
   1881  1.1.1.2  fvdl }
   1882  1.1.1.2  fvdl 
   1883  1.1.1.2  fvdl /*
   1884  1.1.1.2  fvdl  * Output char to tty; console putchar style.
   1885  1.1.1.2  fvdl  */
   1886  1.1.1.2  fvdl int
   1887  1.1.1.2  fvdl tputchar(c, tp)
   1888  1.1.1.2  fvdl 	int c;
   1889  1.1.1.2  fvdl 	struct tty *tp;
   1890  1.1.1.2  fvdl {
   1891  1.1.1.2  fvdl 	register int s;
   1892  1.1.1.2  fvdl 
   1893  1.1.1.2  fvdl 	s = spltty();
   1894  1.1.1.2  fvdl 	if (ISSET(tp->t_state,
   1895  1.1.1.2  fvdl 	    TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
   1896  1.1.1.2  fvdl 		splx(s);
   1897  1.1.1.2  fvdl 		return (-1);
   1898  1.1.1.2  fvdl 	}
   1899  1.1.1.2  fvdl 	if (c == '\n')
   1900  1.1.1.2  fvdl 		(void)ttyoutput('\r', tp);
   1901  1.1.1.2  fvdl 	(void)ttyoutput(c, tp);
   1902  1.1.1.2  fvdl 	ttstart(tp);
   1903  1.1.1.2  fvdl 	splx(s);
   1904  1.1.1.2  fvdl 	return (0);
   1905  1.1.1.2  fvdl }
   1906  1.1.1.2  fvdl 
   1907  1.1.1.2  fvdl /*
   1908  1.1.1.2  fvdl  * Sleep on chan, returning ERESTART if tty changed while we napped and
   1909  1.1.1.2  fvdl  * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep.  If
   1910  1.1.1.2  fvdl  * the tty is revoked, restarting a pending call will redo validation done
   1911  1.1.1.2  fvdl  * at the start of the call.
   1912  1.1.1.2  fvdl  */
   1913  1.1.1.2  fvdl int
   1914  1.1.1.2  fvdl ttysleep(tp, chan, pri, wmesg, timo)
   1915  1.1.1.2  fvdl 	struct tty *tp;
   1916  1.1.1.2  fvdl 	void *chan;
   1917  1.1.1.2  fvdl 	int pri, timo;
   1918  1.1.1.2  fvdl 	char *wmesg;
   1919  1.1.1.2  fvdl {
   1920  1.1.1.2  fvdl 	int error;
   1921  1.1.1.2  fvdl 	short gen;
   1922  1.1.1.2  fvdl 
   1923  1.1.1.2  fvdl 	gen = tp->t_gen;
   1924  1.1.1.2  fvdl 	if (error = tsleep(chan, pri, wmesg, timo))
   1925  1.1.1.2  fvdl 		return (error);
   1926  1.1.1.2  fvdl 	return (tp->t_gen == gen ? 0 : ERESTART);
   1927  1.1.1.2  fvdl }
   1928