[BACK]Return to tty.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/tty.c, Revision 1.125.2.2

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

CVSweb <webmaster@jp.NetBSD.org>