The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/tty.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /* Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved */
   26 /*-
   27  * Copyright (c) 1982, 1986, 1990, 1991, 1993
   28  *      The Regents of the University of California.  All rights reserved.
   29  * (c) UNIX System Laboratories, Inc.
   30  * All or some portions of this file are derived from material licensed
   31  * to the University of California by American Telephone and Telegraph
   32  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   33  * the permission of UNIX System Laboratories, Inc.
   34  *
   35  * Redistribution and use in source and binary forms, with or without
   36  * modification, are permitted provided that the following conditions
   37  * are met:
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  * 3. All advertising materials mentioning features or use of this software
   44  *    must display the following acknowledgement:
   45  *      This product includes software developed by the University of
   46  *      California, Berkeley and its contributors.
   47  * 4. Neither the name of the University nor the names of its contributors
   48  *    may be used to endorse or promote products derived from this software
   49  *    without specific prior written permission.
   50  *
   51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   61  * SUCH DAMAGE.
   62  *
   63  *      @(#)tty.c       8.8 (Berkeley) 1/21/94
   64  */
   65 /*-
   66  * TODO:
   67  *      o Fix races for sending the start char in ttyflush().
   68  *      o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttyselect().
   69  *        With luck, there will be MIN chars before select() returns().
   70  *      o Handle CLOCAL consistently for ptys.  Perhaps disallow setting it.
   71  *      o Don't allow input in TS_ZOMBIE case.  It would be visible through
   72  *        FIONREAD.
   73  *      o Do the new sio locking stuff here and use it to avoid special
   74  *        case for EXTPROC?
   75  *      o Lock PENDIN too?
   76  *      o Move EXTPROC and/or PENDIN to t_state?
   77  *      o Wrap most of ttioctl in spltty/splx.
   78  *      o Implement TIOCNOTTY or remove it from <sys/ioctl.h>.
   79  *      o Send STOP if IXOFF is toggled off while TS_TBLOCK is set.
   80  *      o Don't allow certain termios flags to affect disciplines other
   81  *        than TTYDISC.  Cancel their effects before switch disciplines
   82  *        and ignore them if they are set while we are in another
   83  *        discipline.
   84  *      o Handle c_ispeed = 0 to c_ispeed = c_ospeed conversion here instead
   85  *        of in drivers and fix drivers that write to tp->t_termios.
   86  *      o Check for TS_CARR_ON being set while everything is closed and not
   87  *        waiting for carrier.  TS_CARR_ON isn't cleared if nothing is open,
   88  *        so it would live until the next open even if carrier drops.
   89  *      o Restore TS_WOPEN since it is useful in pstat.  It must be cleared
   90  *        only when _all_ openers leave open().
   91  */
   92 #ifdef NeXT
   93 #define NSNP            0
   94 #else
   95 #include "snp.h"
   96 #include "opt_uconsole.h"
   97 #endif
   98 
   99 #include <sys/param.h>
  100 #define TTYDEFCHARS 1
  101 #include <sys/systm.h>
  102 #undef  TTYDEFCHARS
  103 #include <sys/ioctl.h>
  104 #include <sys/proc.h>
  105 #include <sys/file.h>
  106 #include <sys/conf.h>
  107 #include <sys/dkstat.h>
  108 #include <sys/uio.h>
  109 #include <sys/kernel.h>
  110 #include <sys/vnode.h>
  111 #include <sys/syslog.h>
  112 #include <sys/user.h>
  113 #include <sys/signalvar.h>
  114 #include <sys/signalvar.h>
  115 #ifndef NeXT
  116 #include <sys/resourcevar.h>
  117 #endif
  118 #include <sys/malloc.h>
  119 #if NSNP > 0
  120 #include <sys/snoop.h>
  121 #endif
  122 
  123 #ifndef NeXT
  124 #include <vm/vm.h>
  125 #include <vm/vm_param.h>
  126 #include <vm/vm_prot.h>
  127 #include <vm/lock.h>
  128 #include <vm/pmap.h>
  129 #include <vm/vm_map.h>
  130 #else
  131 #include <dev/kmreg_com.h>
  132 #include <machine/cons.h>
  133 #include <machine/spl.h>
  134 #if 0 /* [ */
  135 #include <machdep/machine/pmap.h>
  136 #endif  /* 0 ] */
  137 #endif /* !NeXT */
  138 
  139 #ifndef NeXT
  140 static int      proc_compare __P((struct proc *p1, struct proc *p2));
  141 #endif /* NeXT */
  142 static int      ttnread __P((struct tty *tp));
  143 static void     ttyecho __P((int c, struct tty *tp));
  144 static int      ttyoutput __P((int c, register struct tty *tp));
  145 static void     ttypend __P((struct tty *tp));
  146 static void     ttyretype __P((struct tty *tp));
  147 static void     ttyrub __P((int c, struct tty *tp));
  148 static void     ttyrubo __P((struct tty *tp, int cnt));
  149 static void     ttystop __P((struct tty *tp, int rw));
  150 static void     ttyunblock __P((struct tty *tp));
  151 static int      ttywflush __P((struct tty *tp));
  152 
  153 /*
  154  * Table with character classes and parity. The 8th bit indicates parity,
  155  * the 7th bit indicates the character is an alphameric or underscore (for
  156  * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
  157  * are 0 then the character needs no special processing on output; classes
  158  * other than 0 might be translated or (not currently) require delays.
  159  */
  160 #define E       0x00    /* Even parity. */
  161 #define O       0x80    /* Odd parity. */
  162 #define PARITY(c)       (char_type[c] & O)
  163 
  164 #define ALPHA   0x40    /* Alpha or underscore. */
  165 #define ISALPHA(c)      (char_type[(c) & TTY_CHARMASK] & ALPHA)
  166 
  167 #define CCLASSMASK      0x3f
  168 #define CCLASS(c)       (char_type[c] & CCLASSMASK)
  169 
  170 #define BS      BACKSPACE
  171 #define CC      CONTROL
  172 #define CR      RETURN
  173 #define NA      ORDINARY | ALPHA
  174 #define NL      NEWLINE
  175 #define NO      ORDINARY
  176 #define TB      TAB
  177 #define VT      VTAB
  178 
  179 static u_char const char_type[] = {
  180         E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
  181         O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
  182         O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
  183         E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
  184         O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
  185         E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
  186         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
  187         O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
  188         O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
  189         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
  190         E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
  191         O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
  192         E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
  193         O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
  194         O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
  195         E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
  196         /*
  197          * Meta chars; should be settable per character set;
  198          * for now, treat them all as normal characters.
  199          */
  200         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  201         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  202         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  203         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  204         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  205         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  206         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  207         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  208         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  209         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  210         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  211         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  212         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  213         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  214         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  215         NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
  216 };
  217 #undef  BS
  218 #undef  CC
  219 #undef  CR
  220 #undef  NA
  221 #undef  NL
  222 #undef  NO
  223 #undef  TB
  224 #undef  VT
  225 
  226 /* Macros to clear/set/test flags. */
  227 #define SET(t, f)       (t) |= (f)
  228 #define CLR(t, f)       (t) &= ~(f)
  229 #define ISSET(t, f)     ((t) & (f))
  230 
  231 /*
  232  * Input control starts when we would not be able to fit the maximum
  233  * contents of the ping-pong buffers and finishes when we would be able
  234  * to fit that much plus 1/8 more.
  235  */
  236 #define I_HIGH_WATER    (TTYHOG - 2 * 256)      /* XXX */
  237 #define I_LOW_WATER     ((TTYHOG - 2 * 256) * 7 / 8)    /* XXX */
  238 
  239 #undef MAX_INPUT                /* XXX wrong in <sys/syslimits.h> */
  240 #define MAX_INPUT       TTYHOG
  241 
  242 /*
  243  * Initial open of tty, or (re)entry to standard tty line discipline.
  244  */
  245 int
  246 ttyopen(device, tp)
  247         dev_t device;
  248         register struct tty *tp;
  249 {
  250         int s;
  251         boolean_t funnel_state;
  252 
  253         funnel_state = thread_funnel_set(kernel_flock, TRUE);
  254         s = spltty();
  255         tp->t_dev = device;
  256         if (!ISSET(tp->t_state, TS_ISOPEN)) {
  257                 SET(tp->t_state, TS_ISOPEN);
  258                 if (ISSET(tp->t_cflag, CLOCAL)) {
  259                         SET(tp->t_state, TS_CONNECTED); }
  260                 bzero(&tp->t_winsize, sizeof(tp->t_winsize));
  261         }
  262 
  263 #ifndef NeXT
  264         /*
  265          * Initialize or restore a cblock allocation policy suitable for
  266          * the standard line discipline.
  267          */
  268         clist_alloc_cblocks(&tp->t_canq, TTYHOG, 512);
  269         clist_alloc_cblocks(&tp->t_outq, TTMAXHIWAT + OBUFSIZ + 100,
  270                             TTMAXHIWAT + OBUFSIZ + 100);
  271         clist_alloc_cblocks(&tp->t_rawq, TTYHOG, TTYHOG);
  272 #endif /* !NeXT */
  273 
  274         splx(s);
  275         thread_funnel_set(kernel_flock, funnel_state);
  276         return (0);
  277 }
  278 
  279 /*
  280  * Handle close() on a tty line: flush and set to initial state,
  281  * bumping generation number so that pending read/write calls
  282  * can detect recycling of the tty.
  283  * XXX our caller should have done `spltty(); l_close(); ttyclose();'
  284  * and l_close() should have flushed, but we repeat the spltty() and
  285  * the flush in case there are buggy callers.
  286  */
  287 int
  288 ttyclose(tp)
  289         register struct tty *tp;
  290 {
  291         int s;
  292 
  293         s = spltty();
  294         if (constty == tp) {
  295                 constty = NULL;
  296 
  297 splx(s);
  298 spltty();
  299 
  300 #ifdef NeXT
  301                 /*
  302                  * Closing current console tty; disable printing of console
  303                  * messages at bottom-level driver. 
  304                  */
  305                 (*cdevsw[major(tp->t_dev)].d_ioctl)
  306                         (tp->t_dev, KMIOCDISABLCONS, NULL, 0, current_proc());
  307 #endif  /* NeXT */
  308         }
  309 
  310         ttyflush(tp, FREAD | FWRITE);
  311 #ifndef NeXT
  312         clist_free_cblocks(&tp->t_canq);
  313         clist_free_cblocks(&tp->t_outq);
  314         clist_free_cblocks(&tp->t_rawq);
  315 #endif
  316 
  317 #if NSNP > 0
  318         if (ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)
  319                 snpdown((struct snoop *)tp->t_sc);
  320 #endif
  321 
  322         tp->t_gen++;
  323         tp->t_line = TTYDISC;
  324         tp->t_pgrp = NULL;
  325         tp->t_session = NULL;
  326         tp->t_state = 0;
  327 #if NeXT
  328         selthreadclear(&tp->t_wsel);
  329         selthreadclear(&tp->t_rsel);
  330 #endif
  331         splx(s);
  332         return (0);
  333 }
  334 
  335 #define FLUSHQ(q) {                                                     \
  336         if ((q)->c_cc)                                                  \
  337                 ndflush(q, (q)->c_cc);                                  \
  338 }
  339 
  340 /* Is 'c' a line delimiter ("break" character)? */
  341 #define TTBREAKC(c, lflag)                                                      \
  342         ((c) == '\n' || (((c) == cc[VEOF] ||                            \
  343           (c) == cc[VEOL] || ((c) == cc[VEOL2] && lflag & IEXTEN)) &&   \
  344          (c) != _POSIX_VDISABLE))
  345 
  346 /*
  347  * Process input of a single character received on a tty.
  348  */
  349 int
  350 ttyinput(c, tp)
  351         register int c;
  352         register struct tty *tp;
  353 {
  354         register tcflag_t iflag, lflag;
  355         register cc_t *cc;
  356         int i, err, retval;
  357         boolean_t funnel_state;
  358 
  359         funnel_state = thread_funnel_set(kernel_flock, TRUE);
  360         
  361         /*
  362          * If input is pending take it first.
  363          */
  364         lflag = tp->t_lflag;
  365         if (ISSET(lflag, PENDIN))
  366                 ttypend(tp);
  367         /*
  368          * Gather stats.
  369          */
  370         if (ISSET(lflag, ICANON)) {
  371                 ++tk_cancc;
  372                 ++tp->t_cancc;
  373         } else {
  374                 ++tk_rawcc;
  375                 ++tp->t_rawcc;
  376         }
  377         ++tk_nin;
  378 
  379         /*
  380          * Block further input iff:
  381          * current input > threshold AND input is available to user program
  382          * AND input flow control is enabled and not yet invoked.
  383          * The 3 is slop for PARMRK.
  384          */
  385         iflag = tp->t_iflag;
  386         if (tp->t_rawq.c_cc + tp->t_canq.c_cc > I_HIGH_WATER - 3 &&
  387             (!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) &&
  388             (ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) &&
  389             !ISSET(tp->t_state, TS_TBLOCK))
  390                 ttyblock(tp);
  391 
  392         /* Handle exceptional conditions (break, parity, framing). */
  393         cc = tp->t_cc;
  394         err = (ISSET(c, TTY_ERRORMASK));
  395         if (err) {
  396                 CLR(c, TTY_ERRORMASK);
  397                 if (ISSET(err, TTY_BI)) {
  398                         if (ISSET(iflag, IGNBRK)) {
  399                                 thread_funnel_set(kernel_flock, funnel_state);
  400                                 return (0);
  401                         }
  402                         if (ISSET(iflag, BRKINT)) {
  403                                 ttyflush(tp, FREAD | FWRITE);
  404                                 pgsignal(tp->t_pgrp, SIGINT, 1);
  405                                 goto endcase;
  406                         }
  407                         if (ISSET(iflag, PARMRK))
  408                                 goto parmrk;
  409                 } else if ((ISSET(err, TTY_PE) && ISSET(iflag, INPCK))
  410                         || ISSET(err, TTY_FE)) {
  411                         if (ISSET(iflag, IGNPAR)) {
  412                                 thread_funnel_set(kernel_flock, funnel_state);
  413                                 return (0);
  414                         }
  415                         else if (ISSET(iflag, PARMRK)) {
  416 parmrk:
  417                                 if (tp->t_rawq.c_cc + tp->t_canq.c_cc >
  418                                     MAX_INPUT - 3)
  419                                         goto input_overflow;
  420                                 (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
  421                                 (void)putc(0 | TTY_QUOTE, &tp->t_rawq);
  422                                 (void)putc(c | TTY_QUOTE, &tp->t_rawq);
  423                                 goto endcase;
  424                         } else
  425                                 c = 0;
  426                 }
  427         }
  428 
  429         if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
  430                 CLR(c, 0x80);
  431         if (!ISSET(lflag, EXTPROC)) {
  432                 /*
  433                  * Check for literal nexting very first
  434                  */
  435                 if (ISSET(tp->t_state, TS_LNCH)) {
  436                         SET(c, TTY_QUOTE);
  437                         CLR(tp->t_state, TS_LNCH);
  438                 }
  439                 /*
  440                  * Scan for special characters.  This code
  441                  * is really just a big case statement with
  442                  * non-constant cases.  The bottom of the
  443                  * case statement is labeled ``endcase'', so goto
  444                  * it after a case match, or similar.
  445                  */
  446 
  447                 /*
  448                  * Control chars which aren't controlled
  449                  * by ICANON, ISIG, or IXON.
  450                  */
  451                 if (ISSET(lflag, IEXTEN)) {
  452                         if (CCEQ(cc[VLNEXT], c)) {
  453                                 if (ISSET(lflag, ECHO)) {
  454                                         if (ISSET(lflag, ECHOE)) {
  455                                                 (void)ttyoutput('^', tp);
  456                                                 (void)ttyoutput('\b', tp);
  457                                         } else
  458                                                 ttyecho(c, tp);
  459                                 }
  460                                 SET(tp->t_state, TS_LNCH);
  461                                 goto endcase;
  462                         }
  463                         if (CCEQ(cc[VDISCARD], c)) {
  464                                 if (ISSET(lflag, FLUSHO))
  465                                         CLR(tp->t_lflag, FLUSHO);
  466                                 else {
  467                                         ttyflush(tp, FWRITE);
  468                                         ttyecho(c, tp);
  469                                         if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
  470                                                 ttyretype(tp);
  471                                         SET(tp->t_lflag, FLUSHO);
  472                                 }
  473                                 goto startoutput;
  474                         }
  475                 }
  476                 /*
  477                  * Signals.
  478                  */
  479                 if (ISSET(lflag, ISIG)) {
  480                         if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
  481                                 if (!ISSET(lflag, NOFLSH))
  482                                         ttyflush(tp, FREAD | FWRITE);
  483                                 ttyecho(c, tp);
  484                                 pgsignal(tp->t_pgrp,
  485                                     CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
  486                                 goto endcase;
  487                         }
  488                         if (CCEQ(cc[VSUSP], c)) {
  489                                 if (!ISSET(lflag, NOFLSH))
  490                                         ttyflush(tp, FREAD);
  491                                 ttyecho(c, tp);
  492                                 pgsignal(tp->t_pgrp, SIGTSTP, 1);
  493                                 goto endcase;
  494                         }
  495                 }
  496                 /*
  497                  * Handle start/stop characters.
  498                  */
  499                 if (ISSET(iflag, IXON)) {
  500                         if (CCEQ(cc[VSTOP], c)) {
  501                                 if (!ISSET(tp->t_state, TS_TTSTOP)) {
  502                                         SET(tp->t_state, TS_TTSTOP);
  503                                         ttystop(tp, 0);
  504                                         thread_funnel_set(kernel_flock, funnel_state);
  505                                         return (0);
  506                                 }
  507                                 if (!CCEQ(cc[VSTART], c)) {
  508                                         thread_funnel_set(kernel_flock, funnel_state);
  509                                         return (0);
  510                                 }
  511                                 /*
  512                                  * if VSTART == VSTOP then toggle
  513                                  */
  514                                 goto endcase;
  515                         }
  516                         if (CCEQ(cc[VSTART], c))
  517                                 goto restartoutput;
  518                 }
  519                 /*
  520                  * IGNCR, ICRNL, & INLCR
  521                  */
  522                 if (c == '\r') {
  523                         if (ISSET(iflag, IGNCR)) {
  524                                 thread_funnel_set(kernel_flock, funnel_state);
  525                                 return (0);
  526                         }
  527                         else if (ISSET(iflag, ICRNL))
  528                                 c = '\n';
  529                 } else if (c == '\n' && ISSET(iflag, INLCR))
  530                         c = '\r';
  531         }
  532         if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
  533                 /*
  534                  * From here on down canonical mode character
  535                  * processing takes place.
  536                  */
  537                 /*
  538                  * erase (^H / ^?)
  539                  */
  540                 if (CCEQ(cc[VERASE], c)) {
  541                         if (tp->t_rawq.c_cc)
  542                                 ttyrub(unputc(&tp->t_rawq), tp);
  543                         goto endcase;
  544                 }
  545                 /*
  546                  * kill (^U)
  547                  */
  548                 if (CCEQ(cc[VKILL], c)) {
  549                         if (ISSET(lflag, ECHOKE) &&
  550                             tp->t_rawq.c_cc == tp->t_rocount &&
  551                             !ISSET(lflag, ECHOPRT))
  552                                 while (tp->t_rawq.c_cc)
  553                                         ttyrub(unputc(&tp->t_rawq), tp);
  554                         else {
  555                                 ttyecho(c, tp);
  556                                 if (ISSET(lflag, ECHOK) ||
  557                                     ISSET(lflag, ECHOKE))
  558                                         ttyecho('\n', tp);
  559                                 FLUSHQ(&tp->t_rawq);
  560                                 tp->t_rocount = 0;
  561                         }
  562                         CLR(tp->t_state, TS_LOCAL);
  563                         goto endcase;
  564                 }
  565                 /*
  566                  * word erase (^W)
  567                  */
  568                 if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) {
  569                         int ctype;
  570 
  571                         /*
  572                          * erase whitespace
  573                          */
  574                         while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
  575                                 ttyrub(c, tp);
  576                         if (c == -1)
  577                                 goto endcase;
  578                         /*
  579                          * erase last char of word and remember the
  580                          * next chars type (for ALTWERASE)
  581                          */
  582                         ttyrub(c, tp);
  583                         c = unputc(&tp->t_rawq);
  584                         if (c == -1)
  585                                 goto endcase;
  586                         if (c == ' ' || c == '\t') {
  587                                 (void)putc(c, &tp->t_rawq);
  588                                 goto endcase;
  589                         }
  590                         ctype = ISALPHA(c);
  591                         /*
  592                          * erase rest of word
  593                          */
  594                         do {
  595                                 ttyrub(c, tp);
  596                                 c = unputc(&tp->t_rawq);
  597                                 if (c == -1)
  598                                         goto endcase;
  599                         } while (c != ' ' && c != '\t' &&
  600                             (!ISSET(lflag, ALTWERASE) || ISALPHA(c) == ctype));
  601                         (void)putc(c, &tp->t_rawq);
  602                         goto endcase;
  603                 }
  604                 /*
  605                  * reprint line (^R)
  606                  */
  607                 if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
  608                         ttyretype(tp);
  609                         goto endcase;
  610                 }
  611                 /*
  612                  * ^T - kernel info and generate SIGINFO
  613                  */
  614                 if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) {
  615                         if (ISSET(lflag, ISIG))
  616                                 pgsignal(tp->t_pgrp, SIGINFO, 1);
  617                         if (!ISSET(lflag, NOKERNINFO))
  618                                 ttyinfo(tp);
  619                         goto endcase;
  620                 }
  621         }
  622         /*
  623          * Check for input buffer overflow
  624          */
  625         if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= MAX_INPUT) {
  626 input_overflow:
  627                 if (ISSET(iflag, IMAXBEL)) {
  628                         if (tp->t_outq.c_cc < tp->t_hiwat)
  629                                 (void)ttyoutput(CTRL('g'), tp);
  630                 }
  631                 goto endcase;
  632         }
  633 
  634         if (   c == 0377 && ISSET(iflag, PARMRK) && !ISSET(iflag, ISTRIP)
  635              && ISSET(iflag, IGNBRK|IGNPAR) != (IGNBRK|IGNPAR))
  636                 (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
  637 
  638         /*
  639          * Put data char in q for user and
  640          * wakeup on seeing a line delimiter.
  641          */
  642         if (putc(c, &tp->t_rawq) >= 0) {
  643                 if (!ISSET(lflag, ICANON)) {
  644                         ttwakeup(tp);
  645                         ttyecho(c, tp);
  646                         goto endcase;
  647                 }
  648                 if (TTBREAKC(c, lflag)) {
  649                         tp->t_rocount = 0;
  650                         catq(&tp->t_rawq, &tp->t_canq);
  651                         ttwakeup(tp);
  652                 } else if (tp->t_rocount++ == 0)
  653                         tp->t_rocol = tp->t_column;
  654                 if (ISSET(tp->t_state, TS_ERASE)) {
  655                         /*
  656                          * end of prterase \.../
  657                          */
  658                         CLR(tp->t_state, TS_ERASE);
  659                         (void)ttyoutput('/', tp);
  660                 }
  661                 i = tp->t_column;
  662                 ttyecho(c, tp);
  663                 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
  664                         /*
  665                          * Place the cursor over the '^' of the ^D.
  666                          */
  667                         i = min(2, tp->t_column - i);
  668                         while (i > 0) {
  669                                 (void)ttyoutput('\b', tp);
  670                                 i--;
  671                         }
  672                 }
  673         }
  674 endcase:
  675         /*
  676          * IXANY means allow any character to restart output.
  677          */
  678         if (ISSET(tp->t_state, TS_TTSTOP) &&
  679             !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP]) {
  680                 thread_funnel_set(kernel_flock, funnel_state);
  681                 return (0);
  682         }
  683 restartoutput:
  684         CLR(tp->t_lflag, FLUSHO);
  685         CLR(tp->t_state, TS_TTSTOP);
  686 startoutput:
  687     retval = ttstart(tp);
  688         thread_funnel_set(kernel_flock, funnel_state);
  689         return (retval);
  690 }
  691 
  692 /*
  693  * Output a single character on a tty, doing output processing
  694  * as needed (expanding tabs, newline processing, etc.).
  695  * Returns < 0 if succeeds, otherwise returns char to resend.
  696  * Must be recursive.
  697  */
  698 static int
  699 ttyoutput(c, tp)
  700         register int c;
  701         register struct tty *tp;
  702 {
  703         register tcflag_t oflag;
  704         register int col, s;
  705 
  706         oflag = tp->t_oflag;
  707         if (!ISSET(oflag, OPOST)) {
  708                 if (ISSET(tp->t_lflag, FLUSHO))
  709                         return (-1);
  710                 if (putc(c, &tp->t_outq))
  711                         return (c);
  712                 tk_nout++;
  713                 tp->t_outcc++;
  714                 return (-1);
  715         }
  716         /*
  717          * Do tab expansion if OXTABS is set.  Special case if we external
  718          * processing, we don't do the tab expansion because we'll probably
  719          * get it wrong.  If tab expansion needs to be done, let it happen
  720          * externally.
  721          */
  722         CLR(c, ~TTY_CHARMASK);
  723         if (c == '\t' &&
  724             ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
  725                 c = 8 - (tp->t_column & 7);
  726                 if (!ISSET(tp->t_lflag, FLUSHO)) {
  727                         s = spltty();           /* Don't interrupt tabs. */
  728                         c -= b_to_q("        ", c, &tp->t_outq);
  729                         tk_nout += c;
  730                         tp->t_outcc += c;
  731                         splx(s);
  732                 }
  733                 tp->t_column += c;
  734                 return (c ? -1 : '\t');
  735         }
  736         if (c == CEOT && ISSET(oflag, ONOEOT))
  737                 return (-1);
  738 
  739         /*
  740          * Newline translation: if ONLCR is set,
  741          * translate newline into "\r\n".
  742          */
  743         if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
  744                 tk_nout++;
  745                 tp->t_outcc++;
  746                 if (putc('\r', &tp->t_outq))
  747                         return (c);
  748         }
  749         tk_nout++;
  750         tp->t_outcc++;
  751         if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
  752                 return (c);
  753 
  754         col = tp->t_column;
  755         switch (CCLASS(c)) {
  756         case BACKSPACE:
  757                 if (col > 0)
  758                         --col;
  759                 break;
  760         case CONTROL:
  761                 break;
  762         case NEWLINE:
  763         case RETURN:
  764                 col = 0;
  765                 break;
  766         case ORDINARY:
  767                 ++col;
  768                 break;
  769         case TAB:
  770                 col = (col + 8) & ~7;
  771                 break;
  772         }
  773         tp->t_column = col;
  774         return (-1);
  775 }
  776 
  777 /*
  778  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
  779  * has been called to do discipline-specific functions and/or reject any
  780  * of these ioctl commands.
  781  */
  782 /* ARGSUSED */
  783 int
  784 #ifndef NeXT
  785 ttioctl(tp, cmd, data, flag)
  786         register struct tty *tp;
  787         int cmd, flag;
  788         void *data;
  789 #else
  790 ttioctl(tp, cmd, data, flag, p)
  791         register struct tty *tp;
  792         u_long cmd;
  793         caddr_t data;
  794         int flag;
  795         struct proc *p;
  796 #endif
  797 {
  798 #ifndef NeXT
  799         register struct proc *p = curproc;      /* XXX */
  800 #endif
  801         int s, error;
  802         struct uthread *ut;
  803 
  804         ut = (struct uthread *)get_bsdthread_info(current_act());
  805         /* If the ioctl involves modification, hang if in the background. */
  806         switch (cmd) {
  807         case  TIOCFLUSH:
  808         case  TIOCSETA:
  809         case  TIOCSETD:
  810         case  TIOCSETAF:
  811         case  TIOCSETAW:
  812 #ifdef notdef
  813         case  TIOCSPGRP:
  814 #endif
  815         case  TIOCSTAT:
  816         case  TIOCSTI:
  817         case  TIOCSWINSZ:
  818 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
  819         case  TIOCLBIC:
  820         case  TIOCLBIS:
  821         case  TIOCLSET:
  822         case  TIOCSETC:
  823         case OTIOCSETD:
  824         case  TIOCSETN:
  825         case  TIOCSETP:
  826         case  TIOCSLTC:
  827 #endif
  828                 while (isbackground(p, tp) &&
  829                     (p->p_flag & P_PPWAIT) == 0 &&
  830                     (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
  831                     (ut->uu_sigmask & sigmask(SIGTTOU)) == 0) {
  832                         if (p->p_pgrp->pg_jobc == 0)
  833                                 return (EIO);
  834                         pgsignal(p->p_pgrp, SIGTTOU, 1);
  835                         error = ttysleep(tp, &lbolt, TTOPRI | PCATCH | PTTYBLOCK, "ttybg1",
  836                                          0);
  837                         if (error)
  838                                 return (error);
  839                 }
  840                 break;
  841         }
  842 
  843         switch (cmd) {                  /* Process the ioctl. */
  844         case FIOASYNC:                  /* set/clear async i/o */
  845                 s = spltty();
  846                 if (*(int *)data)
  847                         SET(tp->t_state, TS_ASYNC);
  848                 else
  849                         CLR(tp->t_state, TS_ASYNC);
  850                 splx(s);
  851                 break;
  852         case FIONBIO:                   /* set/clear non-blocking i/o */
  853                 break;                  /* XXX: delete. */
  854         case FIONREAD:                  /* get # bytes to read */
  855                 s = spltty();
  856                 *(int *)data = ttnread(tp);
  857                 splx(s);
  858                 break;
  859         case TIOCEXCL:                  /* set exclusive use of tty */
  860                 s = spltty();
  861                 SET(tp->t_state, TS_XCLUDE);
  862                 splx(s);
  863                 break;
  864         case TIOCFLUSH: {               /* flush buffers */
  865                 register int flags = *(int *)data;
  866 
  867                 if (flags == 0)
  868                         flags = FREAD | FWRITE;
  869                 else
  870                         flags &= FREAD | FWRITE;
  871                 ttyflush(tp, flags);
  872                 break;
  873         }
  874 #ifdef  NeXT
  875         case TIOCSCONS: {
  876                 /* Set current console device to this line */
  877                 int bogusData = 1;
  878                 data = (caddr_t) &bogusData;
  879 
  880                 /* No break - Fall through to BSD code */
  881         }
  882 #endif /* NeXT */
  883         case TIOCCONS: {                        /* become virtual console */
  884                 if (*(int *)data) {
  885                         if (constty && constty != tp &&
  886                             ISSET(constty->t_state, TS_CONNECTED)) {
  887                                 return (EBUSY);
  888                         }
  889 #if defined(NeXT) || !defined(UCONSOLE)
  890                         if ( (error = suser(p->p_ucred, &p->p_acflag)) )
  891                                 return (error);
  892 #endif
  893                         constty = tp;
  894                 } else if (tp == constty) {
  895                         constty = NULL;
  896                 }
  897 #ifdef  NeXT
  898                 if (constty) {
  899                         (*cdevsw[major(cons.t_dev)].d_ioctl)
  900                                 (cons.t_dev, KMIOCDISABLCONS, NULL, 0, p);
  901                 } else {
  902                         (*cdevsw[major(tp->t_dev)].d_ioctl)
  903                                 (tp->t_dev, KMIOCDISABLCONS, NULL, 0, p);
  904                 }
  905 #endif /* NeXT */
  906                 break;
  907         }
  908         case TIOCDRAIN:                 /* wait till output drained */
  909                 error = ttywait(tp);
  910                 if (error)
  911                         return (error);
  912                 break;
  913         case TIOCGETA: {                /* get termios struct */
  914                 struct termios *t = (struct termios *)data;
  915 
  916                 bcopy(&tp->t_termios, t, sizeof(struct termios));
  917                 break;
  918         }
  919         case TIOCGETD:                  /* get line discipline */
  920                 *(int *)data = tp->t_line;
  921                 break;
  922         case TIOCGWINSZ:                /* get window size */
  923                 *(struct winsize *)data = tp->t_winsize;
  924                 break;
  925         case TIOCGPGRP:                 /* get pgrp of tty */
  926                 if (!isctty(p, tp))
  927                         return (ENOTTY);
  928                 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
  929                 break;
  930 #ifdef TIOCHPCL
  931         case TIOCHPCL:                  /* hang up on last close */
  932                 s = spltty();
  933                 SET(tp->t_cflag, HUPCL);
  934                 splx(s);
  935                 break;
  936 #endif
  937         case TIOCNXCL:                  /* reset exclusive use of tty */
  938                 s = spltty();
  939                 CLR(tp->t_state, TS_XCLUDE);
  940                 splx(s);
  941                 break;
  942         case TIOCOUTQ:                  /* output queue size */
  943                 *(int *)data = tp->t_outq.c_cc;
  944                 break;
  945         case TIOCSETA:                  /* set termios struct */
  946         case TIOCSETAW:                 /* drain output, set */
  947         case TIOCSETAF: {               /* drn out, fls in, set */
  948                 register struct termios *t = (struct termios *)data;
  949 
  950                 if (t->c_ispeed < 0 || t->c_ospeed < 0)
  951                         return (EINVAL);
  952                 s = spltty();
  953                 if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
  954                         error = ttywait(tp);
  955                         if (error) {
  956                                 splx(s);
  957                                 return (error);
  958                         }
  959                         if (cmd == TIOCSETAF)
  960                                 ttyflush(tp, FREAD);
  961                 }
  962                 if (!ISSET(t->c_cflag, CIGNORE)) {
  963                         /*
  964                          * Set device hardware.
  965                          */
  966                         if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
  967                                 splx(s);
  968                                 return (error);
  969                         }
  970                         if (ISSET(t->c_cflag, CLOCAL) &&
  971                             !ISSET(tp->t_cflag, CLOCAL)) {
  972                                 /*
  973                                  * XXX disconnections would be too hard to
  974                                  * get rid of without this kludge.  The only
  975                                  * way to get rid of controlling terminals
  976                                  * is to exit from the session leader.
  977                                  */
  978                                 CLR(tp->t_state, TS_ZOMBIE);
  979 
  980                                 wakeup(TSA_CARR_ON(tp));
  981                                 ttwakeup(tp);
  982                                 ttwwakeup(tp);
  983                         }
  984                         if ((ISSET(tp->t_state, TS_CARR_ON) ||
  985                              ISSET(t->c_cflag, CLOCAL)) &&
  986                             !ISSET(tp->t_state, TS_ZOMBIE))
  987                                 SET(tp->t_state, TS_CONNECTED);
  988                         else
  989                                 CLR(tp->t_state, TS_CONNECTED);
  990                         tp->t_cflag = t->c_cflag;
  991                         tp->t_ispeed = t->c_ispeed;
  992                         tp->t_ospeed = t->c_ospeed;
  993                         ttsetwater(tp);
  994                 }
  995                 if (ISSET(t->c_lflag, ICANON) != ISSET(tp->t_lflag, ICANON) &&
  996                     cmd != TIOCSETAF) {
  997                         if (ISSET(t->c_lflag, ICANON))
  998                                 SET(tp->t_lflag, PENDIN);
  999                         else {
 1000                                 /*
 1001                                  * XXX we really shouldn't allow toggling
 1002                                  * ICANON while we're in a non-termios line
 1003                                  * discipline.  Now we have to worry about
 1004                                  * panicing for a null queue.
 1005                                  */
 1006 #ifndef NeXT
 1007                                 if (tp->t_canq.c_cbreserved > 0 &&
 1008                                     tp->t_rawq.c_cbreserved > 0) {
 1009                                         catq(&tp->t_rawq, &tp->t_canq);
 1010                                         /*
 1011                                          * XXX the queue limits may be
 1012                                          * different, so the old queue
 1013                                          * swapping method no longer works.
 1014                                          */
 1015                                         catq(&tp->t_canq, &tp->t_rawq);
 1016                                 }
 1017 #else
 1018                                 if (tp->t_rawq.c_cs && tp->t_canq.c_cs) {
 1019                                     struct clist tq;
 1020 
 1021                                     catq(&tp->t_rawq, &tp->t_canq);
 1022                                     tq = tp->t_rawq;
 1023                                     tp->t_rawq = tp->t_canq;
 1024                                     tp->t_canq = tq;
 1025                                 }
 1026 #endif /* !NeXT */
 1027                                 CLR(tp->t_lflag, PENDIN);
 1028                         }
 1029                         ttwakeup(tp);
 1030                 }
 1031                 tp->t_iflag = t->c_iflag;
 1032                 tp->t_oflag = t->c_oflag;
 1033                 /*
 1034                  * Make the EXTPROC bit read only.
 1035                  */
 1036                 if (ISSET(tp->t_lflag, EXTPROC))
 1037                         SET(t->c_lflag, EXTPROC);
 1038                 else
 1039                         CLR(t->c_lflag, EXTPROC);
 1040                 tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
 1041                 if (t->c_cc[VMIN] != tp->t_cc[VMIN] ||
 1042                     t->c_cc[VTIME] != tp->t_cc[VTIME])
 1043                         ttwakeup(tp);
 1044                 bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
 1045                 splx(s);
 1046                 break;
 1047         }
 1048         case TIOCSETD: {                /* set line discipline */
 1049                 register int t = *(int *)data;
 1050                 dev_t device = tp->t_dev;
 1051                 extern int nlinesw;
 1052 
 1053                 if ((u_int)t >= nlinesw)
 1054                         return (ENXIO);
 1055                 if (t != tp->t_line) {
 1056                         s = spltty();
 1057                         (*linesw[tp->t_line].l_close)(tp, flag);
 1058                         error = (*linesw[t].l_open)(device, tp);
 1059                         if (error) {
 1060                                 (void)(*linesw[tp->t_line].l_open)(device, tp);
 1061                                 splx(s);
 1062                                 return (error);
 1063                         }
 1064                         tp->t_line = t;
 1065                         splx(s);
 1066                 }
 1067                 break;
 1068         }
 1069         case TIOCSTART:                 /* start output, like ^Q */
 1070                 s = spltty();
 1071                 if (ISSET(tp->t_state, TS_TTSTOP) ||
 1072                     ISSET(tp->t_lflag, FLUSHO)) {
 1073                         CLR(tp->t_lflag, FLUSHO);
 1074                         CLR(tp->t_state, TS_TTSTOP);
 1075                         ttstart(tp);
 1076                 }
 1077                 splx(s);
 1078                 break;
 1079         case TIOCSTI:                   /* simulate terminal input */
 1080                 if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
 1081                         return (EPERM);
 1082                 if (p->p_ucred->cr_uid && !isctty(p, tp))
 1083                         return (EACCES);
 1084                 s = spltty();
 1085                 (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
 1086                 splx(s);
 1087                 break;
 1088         case TIOCSTOP:                  /* stop output, like ^S */
 1089                 s = spltty();
 1090                 if (!ISSET(tp->t_state, TS_TTSTOP)) {
 1091                         SET(tp->t_state, TS_TTSTOP);
 1092                         ttystop(tp, 0);
 1093                 }
 1094                 splx(s);
 1095                 break;
 1096         case TIOCSCTTY:                 /* become controlling tty */
 1097                 /* Session ctty vnode pointer set in vnode layer. */
 1098                 if (!SESS_LEADER(p) ||
 1099                     ((p->p_session->s_ttyvp || tp->t_session) &&
 1100                     (tp->t_session != p->p_session)))
 1101                         return (EPERM);
 1102                 tp->t_session = p->p_session;
 1103                 tp->t_pgrp = p->p_pgrp;
 1104                 p->p_session->s_ttyp = tp;
 1105                 p->p_flag |= P_CONTROLT;
 1106                 /* The backgrounded process blocking on tty now 
 1107                  * could be foregound process. Wake such processes
 1108                  */
 1109                 tty_pgsignal(tp->t_pgrp, SIGCONT);
 1110                 break;
 1111         case TIOCSPGRP: {               /* set pgrp of tty */
 1112                 register struct pgrp *pgrp = pgfind(*(int *)data);
 1113 
 1114                 if (!isctty(p, tp))
 1115                         return (ENOTTY);
 1116                 else if (pgrp == NULL || pgrp->pg_session != p->p_session)
 1117                         return (EPERM);
 1118                 tp->t_pgrp = pgrp;
 1119                 /* The backgrounded process blocking on tty now 
 1120                  * could be foregound process. Wake such processes
 1121                  */
 1122                 tty_pgsignal(tp->t_pgrp, SIGCONT);
 1123                 break;
 1124         }
 1125         case TIOCSTAT:                  /* simulate control-T */
 1126                 s = spltty();
 1127                 ttyinfo(tp);
 1128                 splx(s);
 1129                 break;
 1130         case TIOCSWINSZ:                /* set window size */
 1131                 if (bcmp((caddr_t)&tp->t_winsize, data,
 1132                     sizeof (struct winsize))) {
 1133                         tp->t_winsize = *(struct winsize *)data;
 1134                         pgsignal(tp->t_pgrp, SIGWINCH, 1);
 1135                 }
 1136                 break;
 1137         case TIOCSDRAINWAIT:
 1138                 error = suser(p->p_ucred, &p->p_acflag);
 1139                 if (error)
 1140                         return (error);
 1141                 tp->t_timeout = *(int *)data * hz;
 1142                 wakeup(TSA_OCOMPLETE(tp));
 1143                 wakeup(TSA_OLOWAT(tp));
 1144                 break;
 1145         case TIOCGDRAINWAIT:
 1146                 *(int *)data = tp->t_timeout / hz;
 1147                 break;
 1148         default:
 1149 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1150 #ifdef NeXT
 1151                 return (ttcompat(tp, cmd, data, flag, p));
 1152 #else
 1153                 return (ttcompat(tp, cmd, data, flag));
 1154 #endif /* NeXT */
 1155 #else
 1156                 return (-1);
 1157 #endif
 1158         }
 1159 
 1160         return (0);
 1161 }
 1162 
 1163 int
 1164 ttyselect(tp, rw, wql, p)
 1165         struct tty *tp;
 1166         int rw;
 1167         void * wql;
 1168         struct proc *p;
 1169 {
 1170         int s;
 1171 
 1172         if (tp == NULL)
 1173                 return (ENXIO);
 1174 
 1175         s = spltty();
 1176         switch (rw) {
 1177         case FREAD:
 1178                 if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE))
 1179                         goto win;
 1180                 selrecord(p, &tp->t_rsel, wql);
 1181                 break;
 1182         case FWRITE:
 1183                 if ((tp->t_outq.c_cc <= tp->t_lowat &&
 1184                      ISSET(tp->t_state, TS_CONNECTED))
 1185                     || ISSET(tp->t_state, TS_ZOMBIE)) {
 1186 win:                    splx(s);
 1187                         return (1);
 1188                 }
 1189                 selrecord(p, &tp->t_wsel, wql);
 1190                 break;
 1191         }
 1192         splx(s);
 1193         return (0);
 1194 }
 1195 
 1196 /*
 1197  * This is a wrapper for compatibility with the select vector used by
 1198  * cdevsw.  It relies on a proper xxxdevtotty routine.
 1199  */
 1200 int
 1201 ttselect(dev, rw, wql, p)
 1202         dev_t dev;
 1203         int rw;
 1204         void * wql;
 1205         struct proc *p;
 1206 {
 1207 #ifndef NeXT
 1208         return ttyselect((*cdevsw[major(dev)]->d_devtotty)(dev), rw, wql, p);
 1209 #else
 1210         return ttyselect(cdevsw[major(dev)].d_ttys[minor(dev)], rw, wql, p);
 1211 #endif
 1212 }
 1213 
 1214 /*
 1215  * Must be called at spltty().
 1216  */
 1217 static int
 1218 ttnread(tp)
 1219         struct tty *tp;
 1220 {
 1221         int nread;
 1222 
 1223         if (ISSET(tp->t_lflag, PENDIN))
 1224                 ttypend(tp);
 1225         nread = tp->t_canq.c_cc;
 1226         if (!ISSET(tp->t_lflag, ICANON)) {
 1227                 nread += tp->t_rawq.c_cc;
 1228                 if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
 1229                         nread = 0;
 1230         }
 1231         return (nread);
 1232 }
 1233 
 1234 /*
 1235  * Wait for output to drain.
 1236  */
 1237 int
 1238 ttywait(tp)
 1239         register struct tty *tp;
 1240 {
 1241         int error, s;
 1242 
 1243         error = 0;
 1244         s = spltty();
 1245         while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
 1246                ISSET(tp->t_state, TS_CONNECTED) && tp->t_oproc) {
 1247                 (*tp->t_oproc)(tp);
 1248                 if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
 1249                     ISSET(tp->t_state, TS_CONNECTED)) {
 1250                         SET(tp->t_state, TS_SO_OCOMPLETE);
 1251                         error = ttysleep(tp, TSA_OCOMPLETE(tp),
 1252                                          TTOPRI | PCATCH, "ttywai",
 1253                                          tp->t_timeout);
 1254                         if (error) {
 1255                                 if (error == EWOULDBLOCK)
 1256                                         error = EIO;
 1257                                 break;
 1258                         }
 1259                 } else
 1260                         break;
 1261         }
 1262         if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)))
 1263                 error = EIO;
 1264         splx(s);
 1265         return (error);
 1266 }
 1267 
 1268 static void
 1269 ttystop(tp, rw)
 1270         struct tty *tp;
 1271         int rw;
 1272 {
 1273 #ifdef sun4c                                            /* XXX */
 1274         (*tp->t_stop)(tp, rw);
 1275 #elif defined(NeXT)
 1276         (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
 1277 #else
 1278         (*cdevsw[major(tp->t_dev)]->d_stop)(tp, rw);
 1279 #endif
 1280 }
 1281 
 1282 /*
 1283  * Flush if successfully wait.
 1284  */
 1285 static int
 1286 ttywflush(tp)
 1287         struct tty *tp;
 1288 {
 1289         int error;
 1290 
 1291         if ((error = ttywait(tp)) == 0)
 1292                 ttyflush(tp, FREAD);
 1293         return (error);
 1294 }
 1295 
 1296 /*
 1297  * Flush tty read and/or write queues, notifying anyone waiting.
 1298  */
 1299 void
 1300 ttyflush(tp, rw)
 1301         register struct tty *tp;
 1302         int rw;
 1303 {
 1304         register int s;
 1305 
 1306         s = spltty();
 1307 #if 0
 1308 again:
 1309 #endif
 1310         if (rw & FWRITE) {
 1311                 FLUSHQ(&tp->t_outq);
 1312                 CLR(tp->t_state, TS_TTSTOP);
 1313         }
 1314         ttystop(tp, rw);
 1315         if (rw & FREAD) {
 1316                 FLUSHQ(&tp->t_canq);
 1317                 FLUSHQ(&tp->t_rawq);
 1318                 CLR(tp->t_lflag, PENDIN);
 1319                 tp->t_rocount = 0;
 1320                 tp->t_rocol = 0;
 1321                 CLR(tp->t_state, TS_LOCAL);
 1322                 ttwakeup(tp);
 1323                 if (ISSET(tp->t_state, TS_TBLOCK)) {
 1324                         if (rw & FWRITE)
 1325                                 FLUSHQ(&tp->t_outq);
 1326                         ttyunblock(tp);
 1327 
 1328                         /*
 1329                          * Don't let leave any state that might clobber the
 1330                          * next line discipline (although we should do more
 1331                          * to send the START char).  Not clearing the state
 1332                          * may have caused the "putc to a clist with no
 1333                          * reserved cblocks" panic/printf.
 1334                          */
 1335                         CLR(tp->t_state, TS_TBLOCK);
 1336 
 1337 #if 0 /* forget it, sleeping isn't always safe and we don't know when it is */
 1338                         if (ISSET(tp->t_iflag, IXOFF)) {
 1339                                 /*
 1340                                  * XXX wait a bit in the hope that the stop
 1341                                  * character (if any) will go out.  Waiting
 1342                                  * isn't good since it allows races.  This
 1343                                  * will be fixed when the stop character is
 1344                                  * put in a special queue.  Don't bother with
 1345                                  * the checks in ttywait() since the timeout
 1346                                  * will save us.
 1347                                  */
 1348                                 SET(tp->t_state, TS_SO_OCOMPLETE);
 1349                                 ttysleep(tp, TSA_OCOMPLETE(tp), TTOPRI,
 1350                                          "ttyfls", hz / 10);
 1351                                 /*
 1352                                  * Don't try sending the stop character again.
 1353                                  */
 1354                                 CLR(tp->t_state, TS_TBLOCK);
 1355                                 goto again;
 1356                         }
 1357 #endif
 1358                 }
 1359         }
 1360         if (rw & FWRITE) {
 1361                 FLUSHQ(&tp->t_outq);
 1362                 ttwwakeup(tp);
 1363         }
 1364         splx(s);
 1365 }
 1366 
 1367 /*
 1368  * Copy in the default termios characters.
 1369  */
 1370 void
 1371 termioschars(t)
 1372         struct termios *t;
 1373 {
 1374 
 1375         bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
 1376 }
 1377 
 1378 /*
 1379  * Old interface.
 1380  */
 1381 void
 1382 ttychars(tp)
 1383         struct tty *tp;
 1384 {
 1385 
 1386         termioschars(&tp->t_termios);
 1387 }
 1388 
 1389 /*
 1390  * Handle input high water.  Send stop character for the IXOFF case.  Turn
 1391  * on our input flow control bit and propagate the changes to the driver.
 1392  * XXX the stop character should be put in a special high priority queue.
 1393  */
 1394 void
 1395 ttyblock(tp)
 1396         struct tty *tp;
 1397 {
 1398 
 1399         SET(tp->t_state, TS_TBLOCK);
 1400         if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
 1401             putc(tp->t_cc[VSTOP], &tp->t_outq) != 0)
 1402                 CLR(tp->t_state, TS_TBLOCK);    /* try again later */
 1403         ttstart(tp);
 1404 }
 1405 
 1406 /*
 1407  * Handle input low water.  Send start character for the IXOFF case.  Turn
 1408  * off our input flow control bit and propagate the changes to the driver.
 1409  * XXX the start character should be put in a special high priority queue.
 1410  */
 1411 static void
 1412 ttyunblock(tp)
 1413         struct tty *tp;
 1414 {
 1415 
 1416         CLR(tp->t_state, TS_TBLOCK);
 1417         if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE &&
 1418             putc(tp->t_cc[VSTART], &tp->t_outq) != 0)
 1419                 SET(tp->t_state, TS_TBLOCK);    /* try again later */
 1420         ttstart(tp);
 1421 }
 1422 
 1423 #if defined(NeXT) || defined(notyet)
 1424 /* FreeBSD: Not used by any current (i386) drivers. */
 1425 /*
 1426  * Restart after an inter-char delay.
 1427  */
 1428 void
 1429 ttrstrt(tp_arg)
 1430         void *tp_arg;
 1431 {
 1432         struct tty *tp;
 1433         int s;
 1434 
 1435 #if DIAGNOSTIC
 1436         if (tp_arg == NULL)
 1437                 panic("ttrstrt");
 1438 #endif
 1439         tp = tp_arg;
 1440         s = spltty();
 1441 
 1442         CLR(tp->t_state, TS_TIMEOUT);
 1443         ttstart(tp);
 1444 
 1445         splx(s);
 1446 }
 1447 #endif /* NeXT || notyet */
 1448 
 1449 int
 1450 ttstart(tp)
 1451         struct tty *tp;
 1452 {
 1453         boolean_t funnel_state;
 1454 
 1455         funnel_state = thread_funnel_set(kernel_flock, TRUE);
 1456 
 1457         if (tp->t_oproc != NULL)        /* XXX: Kludge for pty. */
 1458                 (*tp->t_oproc)(tp);
 1459         thread_funnel_set(kernel_flock, funnel_state);
 1460         return (0);
 1461 }
 1462 
 1463 /*
 1464  * "close" a line discipline
 1465  */
 1466 int
 1467 ttylclose(tp, flag)
 1468         struct tty *tp;
 1469         int flag;
 1470 {
 1471         boolean_t funnel_state;
 1472 
 1473         funnel_state = thread_funnel_set(kernel_flock, TRUE);
 1474         if ( (flag & FNONBLOCK) || ttywflush(tp))
 1475                 ttyflush(tp, FREAD | FWRITE);
 1476         thread_funnel_set(kernel_flock, funnel_state);
 1477         return (0);
 1478 }
 1479 
 1480 /*
 1481  * Handle modem control transition on a tty.
 1482  * Flag indicates new state of carrier.
 1483  * Returns 0 if the line should be turned off, otherwise 1.
 1484  */
 1485 int
 1486 ttymodem(tp, flag)
 1487         register struct tty *tp;
 1488         int flag;
 1489 {
 1490         boolean_t funnel_state;
 1491 
 1492         funnel_state = thread_funnel_set(kernel_flock, TRUE);
 1493 
 1494         if (ISSET(tp->t_state, TS_CARR_ON) && ISSET(tp->t_cflag, MDMBUF)) {
 1495                 /*
 1496                  * MDMBUF: do flow control according to carrier flag
 1497                  * XXX TS_CAR_OFLOW doesn't do anything yet.  TS_TTSTOP
 1498                  * works if IXON and IXANY are clear.
 1499                  */
 1500                 if (flag) {
 1501                         CLR(tp->t_state, TS_CAR_OFLOW);
 1502                         CLR(tp->t_state, TS_TTSTOP);
 1503                         ttstart(tp);
 1504                 } else if (!ISSET(tp->t_state, TS_CAR_OFLOW)) {
 1505                         SET(tp->t_state, TS_CAR_OFLOW);
 1506                         SET(tp->t_state, TS_TTSTOP);
 1507                         ttystop(tp, 0);
 1508                 }
 1509         } else if (flag == 0) {
 1510                 /*
 1511                  * Lost carrier.
 1512                  */
 1513                 CLR(tp->t_state, TS_CARR_ON);
 1514                 if (ISSET(tp->t_state, TS_ISOPEN) &&
 1515                     !ISSET(tp->t_cflag, CLOCAL)) {
 1516                         SET(tp->t_state, TS_ZOMBIE);
 1517                         CLR(tp->t_state, TS_CONNECTED);
 1518                         if (tp->t_session && tp->t_session->s_leader)
 1519                                 psignal(tp->t_session->s_leader, SIGHUP);
 1520                         ttyflush(tp, FREAD | FWRITE);
 1521                         thread_funnel_set(kernel_flock, funnel_state);
 1522                         return (0);
 1523                 }
 1524         } else {
 1525                 /*
 1526                  * Carrier now on.
 1527                  */
 1528                 SET(tp->t_state, TS_CARR_ON);
 1529                 if (!ISSET(tp->t_state, TS_ZOMBIE))
 1530                         SET(tp->t_state, TS_CONNECTED);
 1531                 wakeup(TSA_CARR_ON(tp));
 1532                 ttwakeup(tp);
 1533                 ttwwakeup(tp);
 1534         }
 1535         thread_funnel_set(kernel_flock, funnel_state);
 1536         return (1);
 1537 }
 1538 
 1539 /*
 1540  * Reinput pending characters after state switch
 1541  * call at spltty().
 1542  */
 1543 static void
 1544 ttypend(tp)
 1545         register struct tty *tp;
 1546 {
 1547         struct clist tq;
 1548         register int c;
 1549 
 1550         CLR(tp->t_lflag, PENDIN);
 1551         SET(tp->t_state, TS_TYPEN);
 1552 #ifndef NeXT
 1553         /*
 1554          * XXX this assumes too much about clist internals.  It may even
 1555          * fail if the cblock slush pool is empty.  We can't allocate more
 1556          * cblocks here because we are called from an interrupt handler
 1557          * and clist_alloc_cblocks() can wait.
 1558          */
 1559         tq = tp->t_rawq;
 1560         bzero(&tp->t_rawq, sizeof tp->t_rawq);
 1561         tp->t_rawq.c_cbmax = tq.c_cbmax;
 1562         tp->t_rawq.c_cbreserved = tq.c_cbreserved;
 1563 #else
 1564         tq = tp->t_rawq;
 1565         tp->t_rawq.c_cc = 0;
 1566         tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
 1567 #endif /* !NeXT */
 1568         while ((c = getc(&tq)) >= 0)
 1569                 ttyinput(c, tp);
 1570         CLR(tp->t_state, TS_TYPEN);
 1571 }
 1572 
 1573 /*
 1574  * Process a read call on a tty device.
 1575  */
 1576 int
 1577 ttread(tp, uio, flag)
 1578         register struct tty *tp;
 1579         struct uio *uio;
 1580         int flag;
 1581 {
 1582         register struct clist *qp;
 1583         register int c;
 1584         register tcflag_t lflag;
 1585         register cc_t *cc = tp->t_cc;
 1586         register struct proc *p = current_proc();
 1587         int s, first, error = 0;
 1588         int has_etime = 0, last_cc = 0;
 1589         long slp = 0;           /* XXX this should be renamed `timo'. */
 1590         boolean_t funnel_state;
 1591         struct uthread *ut;
 1592 
 1593         funnel_state = thread_funnel_set(kernel_flock, TRUE);
 1594 
 1595         ut = (struct uthread *)get_bsdthread_info(current_act());
 1596 
 1597 loop:
 1598         s = spltty();
 1599         lflag = tp->t_lflag;
 1600         /*
 1601          * take pending input first
 1602          */
 1603         if (ISSET(lflag, PENDIN)) {
 1604                 ttypend(tp);
 1605                 splx(s);        /* reduce latency */
 1606                 s = spltty();
 1607                 lflag = tp->t_lflag;    /* XXX ttypend() clobbers it */
 1608         }
 1609 
 1610         /*
 1611          * Hang process if it's in the background.
 1612          */
 1613         if (isbackground(p, tp)) {
 1614                 splx(s);
 1615                 if ((p->p_sigignore & sigmask(SIGTTIN)) ||
 1616                    (ut->uu_sigmask & sigmask(SIGTTIN)) ||
 1617                     p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0) {
 1618                         thread_funnel_set(kernel_flock, funnel_state);
 1619                         return (EIO);
 1620                 }
 1621                 pgsignal(p->p_pgrp, SIGTTIN, 1);
 1622                 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PTTYBLOCK, "ttybg2", 0);
 1623                 if (error){
 1624                         thread_funnel_set(kernel_flock, funnel_state);
 1625                         return (error);
 1626                 }
 1627                 goto loop;
 1628         }
 1629 
 1630         if (ISSET(tp->t_state, TS_ZOMBIE)) {
 1631                 splx(s);
 1632                 thread_funnel_set(kernel_flock, funnel_state);
 1633                 return (0);     /* EOF */
 1634         }
 1635 
 1636         /*
 1637          * If canonical, use the canonical queue,
 1638          * else use the raw queue.
 1639          *
 1640          * (should get rid of clists...)
 1641          */
 1642         qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
 1643 
 1644         if (flag & IO_NDELAY) {
 1645                 if (qp->c_cc > 0)
 1646                         goto read;
 1647                 if (!ISSET(lflag, ICANON) && cc[VMIN] == 0) {
 1648                         splx(s);
 1649                         thread_funnel_set(kernel_flock, funnel_state);
 1650                         return (0);
 1651                 }
 1652                 splx(s);
 1653                 thread_funnel_set(kernel_flock, funnel_state);
 1654                 return (EWOULDBLOCK);
 1655         }
 1656         if (!ISSET(lflag, ICANON)) {
 1657                 int m = cc[VMIN];
 1658                 long t = cc[VTIME];
 1659                 struct timeval etime, timecopy;
 1660                 int x;
 1661 
 1662                 /*
 1663                  * Check each of the four combinations.
 1664                  * (m > 0 && t == 0) is the normal read case.
 1665                  * It should be fairly efficient, so we check that and its
 1666                  * companion case (m == 0 && t == 0) first.
 1667                  * For the other two cases, we compute the target sleep time
 1668                  * into slp.
 1669                  */
 1670                 if (t == 0) {
 1671                         if (qp->c_cc < m)
 1672                                 goto sleep;
 1673                         if (qp->c_cc > 0)
 1674                                 goto read;
 1675 
 1676                         /* m, t and qp->c_cc are all 0.  0 is enough input. */
 1677                         splx(s);
 1678                         thread_funnel_set(kernel_flock, funnel_state);
 1679                         return (0);
 1680                 }
 1681                 t *= 100000;            /* time in us */
 1682 #define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \
 1683                          ((t1).tv_usec - (t2).tv_usec))
 1684                 if (m > 0) {
 1685                         if (qp->c_cc <= 0)
 1686                                 goto sleep;
 1687                         if (qp->c_cc >= m)
 1688                                 goto read;
 1689                         x = splclock();
 1690                         timecopy = time;
 1691                         splx(x);
 1692                         if (!has_etime) {
 1693                                 /* first character, start timer */
 1694                                 has_etime = 1;
 1695 
 1696                                 etime.tv_sec = t / 1000000;
 1697                                 etime.tv_usec = (t - (etime.tv_sec * 1000000));
 1698                                 timeradd(&etime, &timecopy, &etime);
 1699                                 
 1700                                 slp = t;
 1701                         } else if (qp->c_cc > last_cc) {
 1702                                 /* got a character, restart timer */
 1703 
 1704                                 etime.tv_sec = t / 1000000;
 1705                                 etime.tv_usec = (t - (etime.tv_sec * 1000000));
 1706                                 timeradd(&etime, &timecopy, &etime);
 1707 
 1708                                 slp = t;
 1709                         } else {
 1710                                 /* nothing, check expiration */
 1711                                 if (timercmp(&etime, &timecopy, <=))
 1712                                         goto read;
 1713 
 1714                                 slp = diff(etime, timecopy);
 1715                         }
 1716                         last_cc = qp->c_cc;
 1717                 } else {        /* m == 0 */
 1718                         if (qp->c_cc > 0)
 1719                                 goto read;
 1720                         x = splclock();
 1721                         timecopy = time;
 1722                         splx(x);
 1723                         if (!has_etime) {
 1724                                 has_etime = 1;
 1725 
 1726                                 etime.tv_sec = t / 1000000;
 1727                                 etime.tv_usec = (t - (etime.tv_sec * 1000000));
 1728                                 timeradd(&etime, &timecopy, &etime);
 1729 
 1730                                 slp = t;
 1731                         } else {
 1732                                 if (timercmp(&etime, &timecopy, <=)) {
 1733                                         /* Timed out, but 0 is enough input. */
 1734                                         splx(s);
 1735                                         thread_funnel_set(kernel_flock, funnel_state);
 1736                                         return (0);
 1737                                 }
 1738                                 slp = diff(etime, timecopy);
 1739                         }
 1740                 }
 1741 #undef diff
 1742                 /*
 1743                  * Rounding down may make us wake up just short
 1744                  * of the target, so we round up.
 1745                  * The formula is ceiling(slp * hz/1000000).
 1746                  * 32-bit arithmetic is enough for hz < 169.
 1747                  * XXX see hzto() for how to avoid overflow if hz
 1748                  * is large (divide by `tick' and/or arrange to
 1749                  * use hzto() if hz is large).
 1750                  */
 1751                 slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
 1752                 goto sleep;
 1753         }
 1754         if (qp->c_cc <= 0) {
 1755 sleep:
 1756                 /*
 1757                  * There is no input, or not enough input and we can block.
 1758                  */
 1759                 error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH,
 1760                                  ISSET(tp->t_state, TS_CONNECTED) ?
 1761                                  "ttyin" : "ttyhup", (int)slp);
 1762                 splx(s);
 1763                 if (error == EWOULDBLOCK)
 1764                         error = 0;
 1765                 else if (error) {
 1766                         thread_funnel_set(kernel_flock, funnel_state);
 1767                         return (error);
 1768                 }
 1769                 /*
 1770                  * XXX what happens if another process eats some input
 1771                  * while we are asleep (not just here)?  It would be
 1772                  * safest to detect changes and reset our state variables
 1773                  * (has_stime and last_cc).
 1774                  */
 1775                 slp = 0;
 1776                 goto loop;
 1777         }
 1778 read:
 1779         splx(s);
 1780         /*
 1781          * Input present, check for input mapping and processing.
 1782          */
 1783         first = 1;
 1784 #ifdef NeXT
 1785         if (ISSET(lflag, ICANON)
 1786         || (ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) )
 1787 #else
 1788         if (ISSET(lflag, ICANON | ISIG))
 1789 #endif
 1790                 goto slowcase;
 1791         for (;;) {
 1792                 char ibuf[IBUFSIZ];
 1793                 int icc;
 1794 
 1795                 icc = min(uio->uio_resid, IBUFSIZ);
 1796                 icc = q_to_b(qp, ibuf, icc);
 1797                 if (icc <= 0) {
 1798                         if (first)
 1799                                 goto loop;
 1800                         break;
 1801                 }
 1802                 error = uiomove(ibuf, icc, uio);
 1803                 /*
 1804                  * XXX if there was an error then we should ungetc() the
 1805                  * unmoved chars and reduce icc here.
 1806                  */
 1807 #if NSNP > 0
 1808                 if (ISSET(tp->t_lflag, ECHO) &&
 1809                     ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)
 1810                         snpin((struct snoop *)tp->t_sc, ibuf, icc);
 1811 #endif
 1812                 if (error)
 1813                         break;
 1814                 if (uio->uio_resid == 0)
 1815                         break;
 1816                 first = 0;
 1817         }
 1818         goto out;
 1819 slowcase:
 1820         for (;;) {
 1821                 c = getc(qp);
 1822                 if (c < 0) {
 1823                         if (first)
 1824                                 goto loop;
 1825                         break;
 1826                 }
 1827                 /*
 1828                  * delayed suspend (^Y)
 1829                  */
 1830                 if (CCEQ(cc[VDSUSP], c) &&
 1831                     ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) {
 1832                         pgsignal(tp->t_pgrp, SIGTSTP, 1);
 1833                         if (first) {
 1834                                 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH,
 1835                                                  "ttybg3", 0);
 1836                                 if (error)
 1837                                         break;
 1838                                 goto loop;
 1839                         }
 1840                         break;
 1841                 }
 1842                 /*
 1843                  * Interpret EOF only in canonical mode.
 1844                  */
 1845                 if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
 1846                         break;
 1847                 /*
 1848                  * Give user character.
 1849                  */
 1850                 error = ureadc(c, uio);
 1851                 if (error)
 1852                         /* XXX should ungetc(c, qp). */
 1853                         break;
 1854 #if NSNP > 0
 1855                 /*
 1856                  * Only snoop directly on input in echo mode.  Non-echoed
 1857                  * input will be snooped later iff the application echoes it.
 1858                  */
 1859                 if (ISSET(tp->t_lflag, ECHO) &&
 1860                     ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)
 1861                         snpinc((struct snoop *)tp->t_sc, (char)c);
 1862 #endif
 1863                 if (uio->uio_resid == 0)
 1864                         break;
 1865                 /*
 1866                  * In canonical mode check for a "break character"
 1867                  * marking the end of a "line of input".
 1868                  */
 1869                 if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
 1870                         break;
 1871                 first = 0;
 1872         }
 1873 
 1874 out:
 1875         /*
 1876          * Look to unblock input now that (presumably)
 1877          * the input queue has gone down.
 1878          */
 1879         s = spltty();
 1880         if (ISSET(tp->t_state, TS_TBLOCK) &&
 1881             tp->t_rawq.c_cc + tp->t_canq.c_cc <= I_LOW_WATER)
 1882                 ttyunblock(tp);
 1883         splx(s);
 1884 
 1885         thread_funnel_set(kernel_flock, funnel_state);
 1886         return (error);
 1887 }
 1888 
 1889 /*
 1890  * Check the output queue on tp for space for a kernel message (from uprintf
 1891  * or tprintf).  Allow some space over the normal hiwater mark so we don't
 1892  * lose messages due to normal flow control, but don't let the tty run amok.
 1893  * Sleeps here are not interruptible, but we return prematurely if new signals
 1894  * arrive.
 1895  */
 1896 int
 1897 ttycheckoutq(tp, wait)
 1898         register struct tty *tp;
 1899         int wait;
 1900 {
 1901         int hiwat, s, oldsig;
 1902         struct uthread *ut;
 1903 
 1904         ut = (struct uthread *)get_bsdthread_info(current_act());
 1905 
 1906         hiwat = tp->t_hiwat;
 1907         s = spltty();
 1908         oldsig = wait ? ut->uu_siglist : 0;
 1909         if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100)
 1910                 while (tp->t_outq.c_cc > hiwat) {
 1911                         ttstart(tp);
 1912                         if (tp->t_outq.c_cc <= hiwat)
 1913                                 break;
 1914                         if (wait == 0 || ut->uu_siglist != oldsig) {
 1915                                 splx(s);
 1916                                 return (0);
 1917                         }
 1918                         SET(tp->t_state, TS_SO_OLOWAT);
 1919                         tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", hz);
 1920                 }
 1921         splx(s);
 1922         return (1);
 1923 }
 1924 
 1925 /*
 1926  * Process a write call on a tty device.
 1927  */
 1928 int
 1929 ttwrite(tp, uio, flag)
 1930         register struct tty *tp;
 1931         register struct uio *uio;
 1932         int flag;
 1933 {
 1934         register char *cp = NULL;
 1935         register int cc, ce;
 1936         register struct proc *p;
 1937         int i, hiwat, cnt, error, s;
 1938         char obuf[OBUFSIZ];
 1939         boolean_t funnel_state;
 1940         struct uthread *ut;
 1941 
 1942         funnel_state = thread_funnel_set(kernel_flock, TRUE);
 1943 
 1944         ut = (struct uthread *)get_bsdthread_info(current_act());
 1945         hiwat = tp->t_hiwat;
 1946         cnt = uio->uio_resid;
 1947         error = 0;
 1948         cc = 0;
 1949 loop:
 1950         s = spltty();
 1951         if (ISSET(tp->t_state, TS_ZOMBIE)) {
 1952                 splx(s);
 1953                 if (uio->uio_resid == cnt)
 1954                         error = EIO;
 1955                 goto out;
 1956         }
 1957         if (!ISSET(tp->t_state, TS_CONNECTED)) {
 1958                 if (flag & IO_NDELAY) {
 1959                         splx(s);
 1960                         error = EWOULDBLOCK;
 1961                         goto out;
 1962                 }
 1963                 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
 1964                                  "ttydcd", 0);
 1965                 splx(s);
 1966                 if (error) {
 1967                         goto out; }
 1968                 goto loop;
 1969         }
 1970         splx(s);
 1971         /*
 1972          * Hang the process if it's in the background.
 1973          */
 1974         p = current_proc();
 1975         if (isbackground(p, tp) &&
 1976             ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
 1977             (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
 1978             (ut->uu_sigmask & sigmask(SIGTTOU)) == 0) {
 1979                 if (p->p_pgrp->pg_jobc == 0) {
 1980                         error = EIO;
 1981                         goto out;
 1982                 }
 1983                 pgsignal(p->p_pgrp, SIGTTOU, 1);
 1984                 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PTTYBLOCK, "ttybg4", 0);
 1985                 if (error)
 1986                         goto out;
 1987                 goto loop;
 1988         }
 1989         /*
 1990          * Process the user's data in at most OBUFSIZ chunks.  Perform any
 1991          * output translation.  Keep track of high water mark, sleep on
 1992          * overflow awaiting device aid in acquiring new space.
 1993          */
 1994         while (uio->uio_resid > 0 || cc > 0) {
 1995                 if (ISSET(tp->t_lflag, FLUSHO)) {
 1996                         uio->uio_resid = 0;
 1997                         thread_funnel_set(kernel_flock, funnel_state);
 1998                         return (0);
 1999                 }
 2000                 if (tp->t_outq.c_cc > hiwat)
 2001                         goto ovhiwat;
 2002                 /*
 2003                  * Grab a hunk of data from the user, unless we have some
 2004                  * leftover from last time.
 2005                  */
 2006                 if (cc == 0) {
 2007                         cc = min(uio->uio_resid, OBUFSIZ);
 2008                         cp = obuf;
 2009                         error = uiomove(cp, cc, uio);
 2010                         if (error) {
 2011                                 cc = 0;
 2012                                 break;
 2013                         }
 2014 #if NSNP > 0
 2015                         if (ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)
 2016                                 snpin((struct snoop *)tp->t_sc, cp, cc);
 2017 #endif
 2018                 }
 2019                 /*
 2020                  * If nothing fancy need be done, grab those characters we
 2021                  * can handle without any of ttyoutput's processing and
 2022                  * just transfer them to the output q.  For those chars
 2023                  * which require special processing (as indicated by the
 2024                  * bits in char_type), call ttyoutput.  After processing
 2025                  * a hunk of data, look for FLUSHO so ^O's will take effect
 2026                  * immediately.
 2027                  */
 2028                 while (cc > 0) {
 2029                         if (!ISSET(tp->t_oflag, OPOST))
 2030                                 ce = cc;
 2031                         else {
 2032                                 ce = cc - scanc((u_int)cc, (u_char *)cp,
 2033                                                 (u_char *)char_type, CCLASSMASK);
 2034                                 /*
 2035                                  * If ce is zero, then we're processing
 2036                                  * a special character through ttyoutput.
 2037                                  */
 2038                                 if (ce == 0) {
 2039                                         tp->t_rocount = 0;
 2040                                         if (ttyoutput(*cp, tp) >= 0) {
 2041 #ifdef NeXT
 2042                                                 /* out of space */
 2043                                                 goto overfull;
 2044 #else
 2045                                                 /* No Clists, wait a bit. */
 2046                                                 ttstart(tp);
 2047                                                 if (flag & IO_NDELAY) {
 2048                                                         error = EWOULDBLOCK;
 2049                                                         goto out;
 2050                                                 }
 2051                                                 error = ttysleep(tp, &lbolt,
 2052                                                                  TTOPRI|PCATCH,
 2053                                                                  "ttybf1", 0);
 2054                                                 if (error)
 2055                                                         goto out;
 2056                                                 goto loop;
 2057 #endif /* NeXT */
 2058                                         }
 2059                                         cp++;
 2060                                         cc--;
 2061                                         if (ISSET(tp->t_lflag, FLUSHO) ||
 2062                                             tp->t_outq.c_cc > hiwat)
 2063                                                 goto ovhiwat;
 2064                                         continue;
 2065                                 }
 2066                         }
 2067                         /*
 2068                          * A bunch of normal characters have been found.
 2069                          * Transfer them en masse to the output queue and
 2070                          * continue processing at the top of the loop.
 2071                          * If there are any further characters in this
 2072                          * <= OBUFSIZ chunk, the first should be a character
 2073                          * requiring special handling by ttyoutput.
 2074                          */
 2075                         tp->t_rocount = 0;
 2076                         i = b_to_q(cp, ce, &tp->t_outq);
 2077                         ce -= i;
 2078                         tp->t_column += ce;
 2079                         cp += ce, cc -= ce, tk_nout += ce;
 2080                         tp->t_outcc += ce;
 2081                         if (i > 0) {
 2082 #ifdef NeXT
 2083                                 /* out of space */
 2084                                 goto overfull;
 2085 #else
 2086                                 /* No Clists, wait a bit. */
 2087                                 ttstart(tp);
 2088                                 if (flag & IO_NDELAY) {
 2089                                         error = EWOULDBLOCK;
 2090                                         goto out;
 2091                                 }
 2092                                 error = ttysleep(tp, &lbolt, TTOPRI | PCATCH,
 2093                                                  "ttybf2", 0);
 2094                                 if (error)
 2095                                         goto out;
 2096                                 goto loop;
 2097 #endif /* NeXT */
 2098                         }
 2099                         if (ISSET(tp->t_lflag, FLUSHO) ||
 2100                             tp->t_outq.c_cc > hiwat)
 2101                                 break;
 2102                 }
 2103                 ttstart(tp);
 2104         }
 2105 out:
 2106         /*
 2107          * If cc is nonzero, we leave the uio structure inconsistent, as the
 2108          * offset and iov pointers have moved forward, but it doesn't matter
 2109          * (the call will either return short or restart with a new uio).
 2110          */
 2111         uio->uio_resid += cc;
 2112         thread_funnel_set(kernel_flock, funnel_state);
 2113         return (error);
 2114 
 2115 #ifdef NeXT
 2116 overfull:
 2117 
 2118         /*
 2119          * Since we are using ring buffers, if we can't insert any more into
 2120          * the output queue, we can assume the ring is full and that someone
 2121          * forgot to set the high water mark correctly.  We set it and then
 2122          * proceed as normal.
 2123          */
 2124         hiwat = tp->t_outq.c_cc - 1;
 2125 #endif
 2126 
 2127 ovhiwat:
 2128         ttstart(tp);
 2129         s = spltty();
 2130         /*
 2131          * This can only occur if FLUSHO is set in t_lflag,
 2132          * or if ttstart/oproc is synchronous (or very fast).
 2133          */
 2134         if (tp->t_outq.c_cc <= hiwat) {
 2135                 splx(s);
 2136                 goto loop;
 2137         }
 2138         if (flag & IO_NDELAY) {
 2139                 splx(s);
 2140                 uio->uio_resid += cc;
 2141                 thread_funnel_set(kernel_flock, funnel_state);
 2142                 return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
 2143         }
 2144         SET(tp->t_state, TS_SO_OLOWAT);
 2145         error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttywri",
 2146                          tp->t_timeout);
 2147         splx(s);
 2148         if (error == EWOULDBLOCK)
 2149                 error = EIO;
 2150         if (error)
 2151                 goto out;
 2152         goto loop;
 2153 }
 2154 
 2155 /*
 2156  * Rubout one character from the rawq of tp
 2157  * as cleanly as possible.
 2158  */
 2159 static void
 2160 ttyrub(c, tp)
 2161         register int c;
 2162         register struct tty *tp;
 2163 {
 2164         register u_char *cp;
 2165         register int savecol;
 2166         int tabc, s;
 2167 
 2168         if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
 2169                 return;
 2170         CLR(tp->t_lflag, FLUSHO);
 2171         if (ISSET(tp->t_lflag, ECHOE)) {
 2172                 if (tp->t_rocount == 0) {
 2173                         /*
 2174                          * Messed up by ttwrite; retype
 2175                          */
 2176                         ttyretype(tp);
 2177                         return;
 2178                 }
 2179                 if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
 2180                         ttyrubo(tp, 2);
 2181                 else {
 2182                         CLR(c, ~TTY_CHARMASK);
 2183                         switch (CCLASS(c)) {
 2184                         case ORDINARY:
 2185                                 ttyrubo(tp, 1);
 2186                                 break;
 2187                         case BACKSPACE:
 2188                         case CONTROL:
 2189                         case NEWLINE:
 2190                         case RETURN:
 2191                         case VTAB:
 2192                                 if (ISSET(tp->t_lflag, ECHOCTL))
 2193                                         ttyrubo(tp, 2);
 2194                                 break;
 2195                         case TAB:
 2196                                 if (tp->t_rocount < tp->t_rawq.c_cc) {
 2197                                         ttyretype(tp);
 2198                                         return;
 2199                                 }
 2200                                 s = spltty();
 2201                                 savecol = tp->t_column;
 2202                                 SET(tp->t_state, TS_CNTTB);
 2203                                 SET(tp->t_lflag, FLUSHO);
 2204                                 tp->t_column = tp->t_rocol;
 2205 #ifndef NeXT
 2206                                 cp = tp->t_rawq.c_cf;
 2207                                 if (cp)
 2208                                         tabc = *cp;     /* XXX FIX NEXTC */
 2209                                 for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
 2210                                         ttyecho(tabc, tp);
 2211 #else
 2212                                 for (cp = firstc(&tp->t_rawq, &tabc); cp;
 2213                                     cp = nextc(&tp->t_rawq, cp, &tabc))
 2214                                         ttyecho(tabc, tp);
 2215 #endif /* !NeXT */
 2216                                 CLR(tp->t_lflag, FLUSHO);
 2217                                 CLR(tp->t_state, TS_CNTTB);
 2218                                 splx(s);
 2219 
 2220                                 /* savecol will now be length of the tab. */
 2221                                 savecol -= tp->t_column;
 2222                                 tp->t_column += savecol;
 2223                                 if (savecol > 8)
 2224                                         savecol = 8;    /* overflow fixup */
 2225                                 while (--savecol >= 0)
 2226                                         (void)ttyoutput('\b', tp);
 2227                                 break;
 2228                         default:                        /* XXX */
 2229 #define PANICSTR        "ttyrub: would panic c = %d, val = %d\n"
 2230                                 (void)printf(PANICSTR, c, CCLASS(c));
 2231 #ifdef notdef
 2232                                 panic(PANICSTR, c, CCLASS(c));
 2233 #endif
 2234                         }
 2235                 }
 2236         } else if (ISSET(tp->t_lflag, ECHOPRT)) {
 2237                 if (!ISSET(tp->t_state, TS_ERASE)) {
 2238                         SET(tp->t_state, TS_ERASE);
 2239                         (void)ttyoutput('\\', tp);
 2240                 }
 2241                 ttyecho(c, tp);
 2242         } else
 2243                 ttyecho(tp->t_cc[VERASE], tp);
 2244         --tp->t_rocount;
 2245 }
 2246 
 2247 /*
 2248  * Back over cnt characters, erasing them.
 2249  */
 2250 static void
 2251 ttyrubo(tp, cnt)
 2252         register struct tty *tp;
 2253         int cnt;
 2254 {
 2255 
 2256         while (cnt-- > 0) {
 2257                 (void)ttyoutput('\b', tp);
 2258                 (void)ttyoutput(' ', tp);
 2259                 (void)ttyoutput('\b', tp);
 2260         }
 2261 }
 2262 
 2263 /*
 2264  * ttyretype --
 2265  *      Reprint the rawq line.  Note, it is assumed that c_cc has already
 2266  *      been checked.
 2267  */
 2268 static void
 2269 ttyretype(tp)
 2270         register struct tty *tp;
 2271 {
 2272         register u_char *cp;
 2273         int s, c;
 2274 
 2275         /* Echo the reprint character. */
 2276         if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
 2277                 ttyecho(tp->t_cc[VREPRINT], tp);
 2278 
 2279         (void)ttyoutput('\n', tp);
 2280 
 2281         /*
 2282          * FREEBSD XXX
 2283          * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
 2284          * BIT OF FIRST CHAR.
 2285          */
 2286         s = spltty();
 2287 #ifndef NeXT
 2288         for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
 2289             cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
 2290                 ttyecho(c, tp);
 2291         for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
 2292             cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
 2293                 ttyecho(c, tp);
 2294 #else NeXT
 2295         for (cp = firstc(&tp->t_canq, &c); cp; cp = nextc(&tp->t_canq, cp, &c))
 2296                 ttyecho(c, tp);
 2297         for (cp = firstc(&tp->t_rawq, &c); cp; cp = nextc(&tp->t_rawq, cp, &c))
 2298                 ttyecho(c, tp);
 2299 #endif /* !NeXT */
 2300         CLR(tp->t_state, TS_ERASE);
 2301         splx(s);
 2302 
 2303         tp->t_rocount = tp->t_rawq.c_cc;
 2304         tp->t_rocol = 0;
 2305 }
 2306 
 2307 /*
 2308  * Echo a typed character to the terminal.
 2309  */
 2310 static void
 2311 ttyecho(c, tp)
 2312         register int c;
 2313         register struct tty *tp;
 2314 {
 2315 
 2316         if (!ISSET(tp->t_state, TS_CNTTB))
 2317                 CLR(tp->t_lflag, FLUSHO);
 2318         if ((!ISSET(tp->t_lflag, ECHO) &&
 2319              (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) ||
 2320             ISSET(tp->t_lflag, EXTPROC))
 2321                 return;
 2322         if (ISSET(tp->t_lflag, ECHOCTL) &&
 2323             ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') ||
 2324             ISSET(c, TTY_CHARMASK) == 0177)) {
 2325                 (void)ttyoutput('^', tp);
 2326                 CLR(c, ~TTY_CHARMASK);
 2327                 if (c == 0177)
 2328                         c = '?';
 2329                 else
 2330                         c += 'A' - 1;
 2331         }
 2332         (void)ttyoutput(c, tp);
 2333 }
 2334 
 2335 /*
 2336  * Wake up any readers on a tty.
 2337  */
 2338 void
 2339 ttwakeup(tp)
 2340         register struct tty *tp;
 2341 {
 2342 
 2343 #ifndef NeXT
 2344         if (tp->t_rsel.si_pid != 0)
 2345 #endif
 2346                 selwakeup(&tp->t_rsel);
 2347         if (ISSET(tp->t_state, TS_ASYNC))
 2348                 pgsignal(tp->t_pgrp, SIGIO, 1);
 2349         wakeup(TSA_HUP_OR_INPUT(tp));
 2350 }
 2351 
 2352 /*
 2353  * Wake up any writers on a tty.
 2354  */
 2355 void
 2356 ttwwakeup(tp)
 2357         register struct tty *tp;
 2358 {
 2359 #ifndef NeXT
 2360         if (tp->t_wsel.si_pid != 0 && tp->t_outq.c_cc <= tp->t_lowat)
 2361 #else
 2362         if (tp->t_outq.c_cc <= tp->t_lowat)
 2363 #endif
 2364                 selwakeup(&tp->t_wsel);
 2365         if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
 2366             TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
 2367                 CLR(tp->t_state, TS_SO_OCOMPLETE);
 2368                 wakeup(TSA_OCOMPLETE(tp));
 2369         }
 2370         if (ISSET(tp->t_state, TS_SO_OLOWAT) &&
 2371             tp->t_outq.c_cc <= tp->t_lowat) {
 2372                 CLR(tp->t_state, TS_SO_OLOWAT);
 2373                 wakeup(TSA_OLOWAT(tp));
 2374         }
 2375 }
 2376 
 2377 /*
 2378  * Look up a code for a specified speed in a conversion table;
 2379  * used by drivers to map software speed values to hardware parameters.
 2380  */
 2381 int
 2382 ttspeedtab(speed, table)
 2383         int speed;
 2384         register struct speedtab *table;
 2385 {
 2386 
 2387         for ( ; table->sp_speed != -1; table++)
 2388                 if (table->sp_speed == speed)
 2389                         return (table->sp_code);
 2390         return (-1);
 2391 }
 2392 
 2393 /*
 2394  * Set tty hi and low water marks.
 2395  *
 2396  * Try to arrange the dynamics so there's about one second
 2397  * from hi to low water.
 2398  *
 2399  */
 2400 void
 2401 ttsetwater(tp)
 2402         struct tty *tp;
 2403 {
 2404         register int cps, x;
 2405 
 2406 #define CLAMP(x, h, l)  ((x) > h ? h : ((x) < l) ? l : (x))
 2407 
 2408         cps = tp->t_ospeed / 10;
 2409         tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
 2410         x += cps;
 2411         x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
 2412         tp->t_hiwat = roundup(x, CBSIZE);
 2413 #undef  CLAMP
 2414 }
 2415 
 2416 /* NeXT ttyinfo has been converted to the MACH kernel */
 2417 #include <mach/thread_info.h>
 2418 
 2419 /*
 2420  * Report on state of foreground process group.
 2421  */
 2422 void
 2423 ttyinfo(tp)
 2424         register struct tty *tp;
 2425 {
 2426   /* NOT IMPLEMENTED FOR MACH */
 2427 }
 2428 
 2429 #ifndef NeXT
 2430 /*
 2431  * Returns 1 if p2 is "better" than p1
 2432  *
 2433  * The algorithm for picking the "interesting" process is thus:
 2434  *
 2435  *      1) Only foreground processes are eligible - implied.
 2436  *      2) Runnable processes are favored over anything else.  The runner
 2437  *         with the highest cpu utilization is picked (p_estcpu).  Ties are
 2438  *         broken by picking the highest pid.
 2439  *      3) The sleeper with the shortest sleep time is next.  With ties,
 2440  *         we pick out just "short-term" sleepers (P_SINTR == 0).
 2441  *      4) Further ties are broken by picking the highest pid.
 2442  */
 2443 #define ISRUN(p)        (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
 2444 #define TESTAB(a, b)    ((a)<<1 | (b))
 2445 #define ONLYA   2
 2446 #define ONLYB   1
 2447 #define BOTH    3
 2448 
 2449 static int
 2450 proc_compare(p1, p2)
 2451         register struct proc *p1, *p2;
 2452 {
 2453 
 2454         if (p1 == NULL)
 2455                 return (1);
 2456         /*
 2457          * see if at least one of them is runnable
 2458          */
 2459         switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
 2460         case ONLYA:
 2461                 return (0);
 2462         case ONLYB:
 2463                 return (1);
 2464         case BOTH:
 2465                 /*
 2466                  * tie - favor one with highest recent cpu utilization
 2467                  */
 2468                 if (p2->p_estcpu > p1->p_estcpu)
 2469                         return (1);
 2470                 if (p1->p_estcpu > p2->p_estcpu)
 2471                         return (0);
 2472                 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
 2473         }
 2474         /*
 2475          * weed out zombies
 2476          */
 2477         switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
 2478         case ONLYA:
 2479                 return (1);
 2480         case ONLYB:
 2481                 return (0);
 2482         case BOTH:
 2483                 return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
 2484         }
 2485         /*
 2486          * pick the one with the smallest sleep time
 2487          */
 2488         if (p2->p_slptime > p1->p_slptime)
 2489                 return (0);
 2490         if (p1->p_slptime > p2->p_slptime)
 2491                 return (1);
 2492         /*
 2493          * favor one sleeping in a non-interruptible sleep
 2494          */
 2495         if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
 2496                 return (1);
 2497         if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
 2498                 return (0);
 2499         return (p2->p_pid > p1->p_pid);         /* tie - return highest pid */
 2500 }
 2501 #endif /* NeXT */
 2502 
 2503 /*
 2504  * Output char to tty; console putchar style.
 2505  */
 2506 int
 2507 tputchar(c, tp)
 2508         int c;
 2509         struct tty *tp;
 2510 {
 2511         register int s;
 2512 
 2513         s = spltty();
 2514         if (!ISSET(tp->t_state, TS_CONNECTED)) {
 2515                 splx(s);
 2516                 return (-1);
 2517         }
 2518         if (c == '\n')
 2519                 (void)ttyoutput('\r', tp);
 2520         (void)ttyoutput(c, tp);
 2521         ttstart(tp);
 2522         splx(s);
 2523         return (0);
 2524 }
 2525 
 2526 /*
 2527  * Sleep on chan, returning ERESTART if tty changed while we napped and
 2528  * returning any errors (e.g. EINTR/EWOULDBLOCK) reported by tsleep.  If
 2529  * the tty is revoked, restarting a pending call will redo validation done
 2530  * at the start of the call.
 2531  */
 2532 int
 2533 ttysleep(tp, chan, pri, wmesg, timo)
 2534         struct tty *tp;
 2535         void *chan;
 2536         int pri, timo;
 2537         char *wmesg;
 2538 {
 2539         int error;
 2540         int gen;
 2541 
 2542         gen = tp->t_gen;
 2543         error = tsleep(chan, pri, wmesg, timo);
 2544         if (error)
 2545                 return (error);
 2546         return (tp->t_gen == gen ? 0 : ERESTART);
 2547 }
 2548 
 2549 #ifdef NeXT
 2550 /*
 2551  * Allocate a tty structure and its associated buffers.
 2552  */
 2553 struct tty *
 2554 ttymalloc()
 2555 {
 2556         struct tty *tp;
 2557 
 2558         MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
 2559         bzero(tp, sizeof *tp);
 2560         /* XXX: default to TTYCLSIZE(1024) chars for now */
 2561         clalloc(&tp->t_rawq, TTYCLSIZE, 1);
 2562         clalloc(&tp->t_canq, TTYCLSIZE, 1);
 2563         /* output queue doesn't need quoting */
 2564         clalloc(&tp->t_outq, TTYCLSIZE, 0);
 2565         return(tp);
 2566 }
 2567 
 2568 /*
 2569  * Free a tty structure and its buffers.
 2570  */
 2571 void
 2572 ttyfree(tp)
 2573 struct tty *tp;
 2574 {
 2575         clfree(&tp->t_rawq);
 2576         clfree(&tp->t_canq);
 2577         clfree(&tp->t_outq);
 2578         FREE(tp, M_TTYS);
 2579 }
 2580 
 2581 #else /* !NeXT */
 2582 
 2583 #ifdef notyet
 2584 /*
 2585  * XXX this is usable not useful or used.  Most tty drivers have
 2586  * ifdefs for using ttymalloc() but assume a different interface.
 2587  */
 2588 /*
 2589  * Allocate a tty struct.  Clists in the struct will be allocated by
 2590  * ttyopen().
 2591  */
 2592 struct tty *
 2593 ttymalloc()
 2594 {
 2595         struct tty *tp;
 2596 
 2597         tp = _MALLOC(sizeof *tp, M_TTYS, M_WAITOK);
 2598         bzero(tp, sizeof *tp);
 2599         return (tp);
 2600 }
 2601 #endif
 2602 
 2603 #if 0 /* XXX not yet usable: session leader holds a ref (see kern_exit.c). */
 2604 /*
 2605  * Free a tty struct.  Clists in the struct should have been freed by
 2606  * ttyclose().
 2607  */
 2608 void
 2609 ttyfree(tp)
 2610         struct tty *tp;
 2611 {
 2612         FREE(tp, M_TTYS);
 2613 }
 2614 #endif /* 0 */
 2615 #endif /* NeXT */

Cache object: c782e15e994b346bc0094952ada9650e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.