123387Smckusick /* 229107Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323387Smckusick * All rights reserved. The Berkeley software License Agreement 423387Smckusick * specifies the terms and conditions for redistribution. 523387Smckusick * 6*37584Smarc * @(#)tty.c 7.16 (Berkeley) 05/01/89 723387Smckusick */ 839Sbill 917095Sbloom #include "param.h" 1017095Sbloom #include "systm.h" 1117095Sbloom #include "dir.h" 1217095Sbloom #include "user.h" 1317095Sbloom #include "ioctl.h" 1417095Sbloom #include "tty.h" 1535811Smarc #define TTYDEFCHARS 1635811Smarc #include "ttydefaults.h" 1735811Smarc #undef TTYDEFCHARS 1835811Smarc #include "termios.h" 1917095Sbloom #include "proc.h" 2017095Sbloom #include "file.h" 2117095Sbloom #include "conf.h" 2229946Skarels #include "dkstat.h" 2317095Sbloom #include "uio.h" 2417095Sbloom #include "kernel.h" 2535811Smarc #include "syslog.h" 2639Sbill 2737525Smckusick #include "machine/reg.h" 2837525Smckusick 297436Skre /* 307436Skre * Table giving parity for characters and indicating 3135811Smarc * character classes to tty driver. The 8th bit 3235811Smarc * indicates parity, the 7th bit indicates the character 3335811Smarc * is an alphameric or underscore (for ALTWERASE), and the 3435811Smarc * low 6 bits indicate delay type. If the low 6 bits are 0 3535811Smarc * then the character needs no special processing on output. 367436Skre */ 3739Sbill 387436Skre char partab[] = { 3935811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* nul - bel */ 4035811Smarc 0202,0004,0003,0201,0005,0206,0201,0001, /* bs - si */ 4135811Smarc 0201,0001,0001,0201,0001,0201,0201,0001, /* dle - etb */ 4235811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* can - us */ 4335811Smarc 0200,0000,0000,0200,0000,0200,0200,0000, /* sp - ' */ 4435811Smarc 0000,0200,0200,0000,0200,0000,0000,0200, /* ( - / */ 4535811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* 0 - 7 */ 4635811Smarc 0300,0100,0000,0200,0000,0200,0200,0000, /* 8 - ? */ 4735811Smarc 0200,0100,0100,0300,0100,0300,0300,0100, /* @ - G */ 4835811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* H - O */ 4935811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* P - W */ 5035811Smarc 0300,0100,0100,0200,0000,0200,0200,0300, /* X - _ */ 5135811Smarc 0000,0300,0300,0100,0300,0100,0100,0300, /* ` - g */ 5235811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* h - o */ 5335811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* p - w */ 5435811Smarc 0100,0300,0300,0000,0200,0000,0000,0201, /* x - del */ 557436Skre /* 5635811Smarc * meta chars 577436Skre */ 5835811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* nul - bel */ 5935811Smarc 0202,0004,0003,0201,0005,0206,0201,0001, /* bs - si */ 6035811Smarc 0201,0001,0001,0201,0001,0201,0201,0001, /* dle - etb */ 6135811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* can - us */ 6235811Smarc 0200,0000,0000,0200,0000,0200,0200,0000, /* sp - ' */ 6335811Smarc 0000,0200,0200,0000,0200,0000,0000,0200, /* ( - / */ 6435811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* 0 - 7 */ 6535811Smarc 0300,0100,0000,0200,0000,0200,0200,0000, /* 8 - ? */ 6635811Smarc 0200,0100,0100,0300,0100,0300,0300,0100, /* @ - G */ 6735811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* H - O */ 6835811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* P - W */ 6935811Smarc 0300,0100,0100,0200,0000,0200,0200,0300, /* X - _ */ 7035811Smarc 0000,0300,0300,0100,0300,0100,0100,0300, /* ` - g */ 7135811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* h - o */ 7235811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* p - w */ 7335811Smarc 0100,0300,0300,0000,0200,0000,0000,0201, /* x - del */ 747436Skre }; 757436Skre 7635811Smarc extern struct tty *constty; /* temporary virtual console */ 7735811Smarc extern char partab[], maptab[]; 7835811Smarc 79146Sbill /* 8035811Smarc * Is 'c' a line delimiter ("break" character)? 8139Sbill */ 8235811Smarc #define ttbreakc(c) (c == '\n' || CCEQ(cc[VEOF], c) || \ 8335811Smarc CCEQ(cc[VEOL], c) || CCEQ(cc[VEOL2], c)) 8439Sbill 8539Sbill ttychars(tp) 869578Ssam struct tty *tp; 8739Sbill { 8835811Smarc bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 8939Sbill } 9039Sbill 9139Sbill /* 92903Sbill * Wait for output to drain, then flush input waiting. 9339Sbill */ 9412752Ssam ttywflush(tp) 95*37584Smarc struct tty *tp; 9639Sbill { 9739Sbill 9812752Ssam ttywait(tp); 9912752Ssam ttyflush(tp, FREAD); 10012752Ssam } 10112752Ssam 10235811Smarc /* 10335811Smarc * Wait for output to drain. 10435811Smarc */ 10512752Ssam ttywait(tp) 10612752Ssam register struct tty *tp; 10712752Ssam { 108*37584Smarc int s = spltty(); 10912752Ssam 11013809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 111*37584Smarc (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 112*37584Smarc tp->t_oproc) { 113903Sbill (*tp->t_oproc)(tp); 1145408Swnj tp->t_state |= TS_ASLEEP; 115903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 116903Sbill } 1179859Ssam splx(s); 11839Sbill } 11939Sbill 12039Sbill /* 1219578Ssam * Flush all TTY queues 12239Sbill */ 12312752Ssam ttyflush(tp, rw) 1247625Ssam register struct tty *tp; 12539Sbill { 126903Sbill register s; 127903Sbill 12817545Skarels s = spltty(); 129903Sbill if (rw & FREAD) { 130903Sbill while (getc(&tp->t_canq) >= 0) 131903Sbill ; 132*37584Smarc ttwakeup(tp); 133903Sbill } 134903Sbill if (rw & FWRITE) { 135*37584Smarc wakeup((caddr_t)&tp->t_outq); /* XXX? what about selwakeup? */ 1365408Swnj tp->t_state &= ~TS_TTSTOP; 1375426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 138903Sbill while (getc(&tp->t_outq) >= 0) 139903Sbill ; 140903Sbill } 141903Sbill if (rw & FREAD) { 142903Sbill while (getc(&tp->t_rawq) >= 0) 143903Sbill ; 1449578Ssam tp->t_rocount = 0; 145903Sbill tp->t_rocol = 0; 1469578Ssam tp->t_state &= ~TS_LOCAL; 147903Sbill } 148903Sbill splx(s); 14939Sbill } 15039Sbill 151903Sbill /* 152903Sbill * Send stop character on input overflow. 153903Sbill */ 154903Sbill ttyblock(tp) 1557625Ssam register struct tty *tp; 15639Sbill { 157903Sbill register x; 1589578Ssam 159903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 160903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 16112752Ssam ttyflush(tp, FREAD|FWRITE); 1625408Swnj tp->t_state &= ~TS_TBLOCK; 163903Sbill } 16415118Skarels /* 16515118Skarels * Block further input iff: 16615118Skarels * Current input > threshold AND input is available to user program 16715118Skarels */ 16816055Skarels if (x >= TTYHOG/2 && 16935811Smarc (!(tp->t_lflag&ICANON)) || (tp->t_canq.c_cc > 0) && 17035811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 17135811Smarc if (putc(tp->t_cc[VSTOP], &tp->t_outq)==0) { 17215118Skarels tp->t_state |= TS_TBLOCK; 17315118Skarels ttstart(tp); 17415118Skarels } 175903Sbill } 17639Sbill } 17739Sbill 17839Sbill /* 179903Sbill * Restart typewriter output following a delay 180903Sbill * timeout. 181903Sbill * The name of the routine is passed to the timeout 182903Sbill * subroutine and it is called during a clock interrupt. 183121Sbill */ 184903Sbill ttrstrt(tp) 185*37584Smarc struct tty *tp; 186121Sbill { 187121Sbill 1889578Ssam if (tp == 0) 1899578Ssam panic("ttrstrt"); 1905408Swnj tp->t_state &= ~TS_TIMEOUT; 191903Sbill ttstart(tp); 192121Sbill } 193121Sbill 194121Sbill /* 195903Sbill * Start output on the typewriter. It is used from the top half 196903Sbill * after some characters have been put on the output queue, 197903Sbill * from the interrupt routine to transmit the next 198903Sbill * character, and after a timeout has finished. 19939Sbill */ 200903Sbill ttstart(tp) 201*37584Smarc struct tty *tp; 20239Sbill { 20339Sbill 20432067Skarels if (tp->t_oproc) /* kludge for pty */ 205903Sbill (*tp->t_oproc)(tp); 20639Sbill } 20739Sbill 20839Sbill /* 209903Sbill * Common code for tty ioctls. 21039Sbill */ 2111780Sbill /*ARGSUSED*/ 2127625Ssam ttioctl(tp, com, data, flag) 2137625Ssam register struct tty *tp; 2147625Ssam caddr_t data; 21539Sbill { 21639Sbill extern int nldisp; 21735811Smarc int softset = 0; 21837554Smckusick int s, error; 21939Sbill 22030534Skarels 221903Sbill /* 222903Sbill * If the ioctl involves modification, 22317545Skarels * hang if in the background. 224903Sbill */ 2257625Ssam switch (com) { 22639Sbill 22735811Smarc case TIOCSETD: 228903Sbill case TIOCFLUSH: 22935811Smarc /*case TIOCSPGRP:*/ 2309325Ssam case TIOCSTI: 23117598Sbloom case TIOCSWINSZ: 23235811Smarc case TIOCSETA: 23335811Smarc case TIOCSETAW: 23435811Smarc case TIOCSETAF: 23535811Smarc case TIOCSETAS: 23635811Smarc case TIOCSETAWS: 23735811Smarc case TIOCSETAFS: 23835811Smarc while (u.u_procp->p_pgid != tp->t_pgid && 23935811Smarc tp == u.u_ttyp && 24035811Smarc u.u_procp->p_pgrp->pg_jobc && 241903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 24224392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 24324392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 24435811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU); 245903Sbill sleep((caddr_t)&lbolt, TTOPRI); 246903Sbill } 247903Sbill break; 248903Sbill } 249903Sbill 2509578Ssam /* 2519578Ssam * Process the ioctl. 2529578Ssam */ 2537625Ssam switch (com) { 254903Sbill 2558556Sroot /* get discipline number */ 25639Sbill case TIOCGETD: 2577625Ssam *(int *)data = tp->t_line; 25839Sbill break; 25939Sbill 2608556Sroot /* set line discipline */ 2617625Ssam case TIOCSETD: { 2627625Ssam register int t = *(int *)data; 26335811Smarc dev_t dev = tp->t_dev; 2649578Ssam int error = 0; 2657625Ssam 26635811Smarc if ((unsigned)t >= nldisp) 26710851Ssam return (ENXIO); 26825584Skarels if (t != tp->t_line) { 26925584Skarels s = spltty(); 27025584Skarels (*linesw[tp->t_line].l_close)(tp); 27125584Skarels error = (*linesw[t].l_open)(dev, tp); 27225584Skarels if (error) { 27335811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 27425584Skarels splx(s); 27525584Skarels return (error); 27625584Skarels } 27725584Skarels tp->t_line = t; 27810851Ssam splx(s); 27910851Ssam } 28039Sbill break; 2817625Ssam } 28239Sbill 2838556Sroot /* prevent more opens on channel */ 2845614Swnj case TIOCEXCL: 2855614Swnj tp->t_state |= TS_XCLUDE; 2865614Swnj break; 2875614Swnj 2885614Swnj case TIOCNXCL: 2895614Swnj tp->t_state &= ~TS_XCLUDE; 2905614Swnj break; 2915614Swnj 29239Sbill case TIOCHPCL: 29335811Smarc tp->t_cflag |= HUPCL; 29439Sbill break; 29539Sbill 2963942Sbugs case TIOCFLUSH: { 2977625Ssam register int flags = *(int *)data; 2987625Ssam 2997625Ssam if (flags == 0) 3003942Sbugs flags = FREAD|FWRITE; 3017625Ssam else 3027625Ssam flags &= FREAD|FWRITE; 30312752Ssam ttyflush(tp, flags); 30439Sbill break; 3053944Sbugs } 30639Sbill 307*37584Smarc case FIOASYNC: 308*37584Smarc if (*(int *)data) 309*37584Smarc tp->t_state |= TS_ASYNC; 310*37584Smarc else 311*37584Smarc tp->t_state &= ~TS_ASYNC; 312*37584Smarc break; 313*37584Smarc 314*37584Smarc case FIONBIO: 315*37584Smarc break; /* XXX remove */ 316*37584Smarc 3178556Sroot /* return number of characters immediately available */ 3187625Ssam case FIONREAD: 3197625Ssam *(off_t *)data = ttnread(tp); 320174Sbill break; 321174Sbill 32213077Ssam case TIOCOUTQ: 32313077Ssam *(int *)data = tp->t_outq.c_cc; 32413077Ssam break; 32513077Ssam 3268589Sroot case TIOCSTOP: 32717545Skarels s = spltty(); 3289578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3295573Swnj tp->t_state |= TS_TTSTOP; 3305573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3315573Swnj } 3327625Ssam splx(s); 3335573Swnj break; 3345573Swnj 3358589Sroot case TIOCSTART: 33617545Skarels s = spltty(); 33735811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 3385573Swnj tp->t_state &= ~TS_TTSTOP; 33935811Smarc tp->t_lflag &= ~FLUSHO; 3405573Swnj ttstart(tp); 3415573Swnj } 3427625Ssam splx(s); 3435573Swnj break; 3445573Swnj 3459325Ssam /* 3469325Ssam * Simulate typing of a character at the terminal. 3479325Ssam */ 3489325Ssam case TIOCSTI: 34917183Smckusick if (u.u_uid && (flag & FREAD) == 0) 35017183Smckusick return (EPERM); 3519325Ssam if (u.u_uid && u.u_ttyp != tp) 3529325Ssam return (EACCES); 3539578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3549325Ssam break; 3559325Ssam 35635811Smarc case TIOCGETA: { 35735811Smarc struct termios *t = (struct termios *)data; 35812752Ssam 35935811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 36035811Smarc break; 36135811Smarc } 36235811Smarc 36335811Smarc case TIOCSETAS: 36435811Smarc case TIOCSETAWS: 36535811Smarc case TIOCSETAFS: 36635811Smarc softset = 1; 36735811Smarc /*FALLTHROUGH*/ 36835811Smarc case TIOCSETA: 36935811Smarc case TIOCSETAW: 370*37584Smarc case TIOCSETAF: { 37135811Smarc register struct termios *t = (struct termios *)data; 37235811Smarc int error; 37335811Smarc 37417545Skarels s = spltty(); 37535811Smarc if (!softset) { 37635811Smarc /* 37735811Smarc * set device hardware 37835811Smarc */ 379*37584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 380*37584Smarc splx(s); 38135811Smarc return (error); 382*37584Smarc } else { 383*37584Smarc if (!(tp->t_state&TS_CARR_ON) && 384*37584Smarc (tp->t_cflag&CLOCAL) && 385*37584Smarc !(t->c_cflag&CLOCAL)) { 386*37584Smarc tp->t_state &= ~TS_ISOPEN; 387*37584Smarc tp->t_state |= TS_WOPEN; 388*37584Smarc ttwakeup(tp); 389*37584Smarc } 39035811Smarc tp->t_cflag = t->c_cflag; 39135811Smarc tp->t_ispeed = t->c_ispeed; 39235811Smarc tp->t_ospeed = t->c_ospeed; 39334492Skarels } 39435811Smarc ttsetwater(tp); 39512752Ssam } 39635811Smarc if (com == TIOCSETAF || com == TIOCSETAFS) 39735811Smarc ttywflush(tp); 39835811Smarc else { 39935811Smarc if (com == TIOCSETAW || com == TIOCSETAWS) 40035811Smarc ttywait(tp); 40135811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 40235811Smarc if (t->c_lflag&ICANON) { 40335811Smarc tp->t_lflag |= PENDIN; 40435811Smarc ttwakeup(tp); 40535811Smarc } 40635811Smarc else { 40735811Smarc struct clist tq; 40835811Smarc 40935811Smarc catq(&tp->t_rawq, &tp->t_canq); 41035811Smarc tq = tp->t_rawq; 41135811Smarc tp->t_rawq = tp->t_canq; 41235811Smarc tp->t_canq = tq; 41335811Smarc } 41412752Ssam } 41535811Smarc tp->t_iflag = t->c_iflag; 41635811Smarc tp->t_oflag = t->c_oflag; 41735811Smarc tp->t_lflag = t->c_lflag; 41835811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 41912752Ssam splx(s); 42012752Ssam break; 42112752Ssam } 42212752Ssam 42312752Ssam /* 42435811Smarc * Acquire controlling terminal. 42534492Skarels */ 42635811Smarc case TIOCSCTTY: { 42735811Smarc register struct proc *p = u.u_procp; 42834492Skarels 42935811Smarc /* RETHINK - whether non-session leader 43035811Smarc * can allocate a new ctty for a session. 43135811Smarc */ 43235811Smarc if (u.u_ttyp || 43335811Smarc (tp->t_session && tp->t_session != p->p_session) || 43435811Smarc (!tp->t_session && !SESS_LEADER(p))) 43535811Smarc return(EPERM); 43635811Smarc u.u_ttyp = tp; 43735811Smarc u.u_ttyd = tp->t_dev; 43835811Smarc if (tp->t_pgid == 0) 43935811Smarc tp->t_pgid = p->p_pgrp->pg_id; 44035811Smarc tp->t_session = p->p_session; 44134492Skarels break; 44235811Smarc } 44334492Skarels 44434492Skarels /* 44535811Smarc * Set terminal process group. 44617545Skarels */ 44718650Sbloom case TIOCSPGRP: { 44835811Smarc register struct proc *p = u.u_procp; 44935811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 45017545Skarels 45135811Smarc if (u.u_uid && 45235811Smarc (tp != u.u_ttyp || 45335811Smarc (pgrp && pgrp->pg_session != p->p_session))) { 45435811Smarc if (u.u_ttyp == NULL) 45535811Smarc return (ENOTTY); 45635811Smarc else 45735811Smarc return (EPERM); 45835811Smarc } 45935811Smarc tp->t_pgid = *(int *)data; 46012752Ssam break; 46118650Sbloom } 46212752Ssam 46312752Ssam case TIOCGPGRP: 46435811Smarc *(int *)data = tp->t_pgid; 46512752Ssam break; 46612752Ssam 46717598Sbloom case TIOCSWINSZ: 46818650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 46918650Sbloom sizeof (struct winsize))) { 47017598Sbloom tp->t_winsize = *(struct winsize *)data; 47135811Smarc gsignal(tp->t_pgid, SIGWINCH); 47217598Sbloom } 47317598Sbloom break; 47417598Sbloom 47517598Sbloom case TIOCGWINSZ: 47617598Sbloom *(struct winsize *)data = tp->t_winsize; 47717598Sbloom break; 47817598Sbloom 47930534Skarels case TIOCCONS: 48030534Skarels if (*(int *)data) { 48130534Skarels if (constty != NULL) 48230534Skarels return (EBUSY); 48330534Skarels #ifndef UCONSOLE 48437554Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 48537554Smckusick return (error); 48630534Skarels #endif 48730534Skarels constty = tp; 48830534Skarels } else if (tp == constty) 48933404Skarels constty = NULL; 49030534Skarels break; 49130534Skarels 49235811Smarc #ifdef COMPAT_43 49335811Smarc case TIOCGETP: 49435811Smarc case TIOCSETP: 49535811Smarc case TIOCSETN: 49635811Smarc case TIOCGETC: 49735811Smarc case TIOCSETC: 49835811Smarc case TIOCSLTC: 49935811Smarc case TIOCGLTC: 50035811Smarc case TIOCLBIS: 50135811Smarc case TIOCLBIC: 50235811Smarc case TIOCLSET: 50335811Smarc case TIOCLGET: 50435811Smarc case TIOCGETDCOMPAT: 50535811Smarc case TIOCSETDCOMPAT: 50635811Smarc return(ttcompat(tp, com, data, flag)); 50735811Smarc #endif 50835811Smarc 50939Sbill default: 5108556Sroot return (-1); 51139Sbill } 5128556Sroot return (0); 51339Sbill } 5144484Swnj 5154484Swnj ttnread(tp) 5164484Swnj struct tty *tp; 5174484Swnj { 5184484Swnj int nread = 0; 5194484Swnj 52035811Smarc if (tp->t_lflag & PENDIN) 5214484Swnj ttypend(tp); 5224484Swnj nread = tp->t_canq.c_cc; 52335811Smarc if ((tp->t_lflag & ICANON) == 0) 5244484Swnj nread += tp->t_rawq.c_cc; 5254484Swnj return (nread); 5264484Swnj } 5274484Swnj 5285408Swnj ttselect(dev, rw) 5294484Swnj dev_t dev; 5305408Swnj int rw; 5314484Swnj { 5324484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5334484Swnj int nread; 53417545Skarels int s = spltty(); 5354484Swnj 5365408Swnj switch (rw) { 5374484Swnj 5384484Swnj case FREAD: 5394484Swnj nread = ttnread(tp); 540*37584Smarc if (nread > 0 || 541*37584Smarc (!(tp->t_cflag&CLOCAL) && !(tp->t_state&TS_CARR_ON))) 5425408Swnj goto win; 5434938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5445408Swnj tp->t_state |= TS_RCOLL; 5454484Swnj else 5464484Swnj tp->t_rsel = u.u_procp; 5475408Swnj break; 5484484Swnj 5495408Swnj case FWRITE: 55035811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 5515408Swnj goto win; 5525408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5535408Swnj tp->t_state |= TS_WCOLL; 5545408Swnj else 5555408Swnj tp->t_wsel = u.u_procp; 5565408Swnj break; 5574484Swnj } 5585408Swnj splx(s); 5595408Swnj return (0); 5605408Swnj win: 5615408Swnj splx(s); 5625408Swnj return (1); 5634484Swnj } 5647436Skre 5657502Sroot /* 56625391Skarels * Initial open of tty, or (re)entry to line discipline. 5677502Sroot */ 5687502Sroot ttyopen(dev, tp) 5697625Ssam dev_t dev; 5707625Ssam register struct tty *tp; 5717502Sroot { 5727502Sroot register struct proc *pp; 5737502Sroot 5747502Sroot tp->t_dev = dev; 57535811Smarc 5767502Sroot tp->t_state &= ~TS_WOPEN; 57717545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 57817545Skarels tp->t_state |= TS_ISOPEN; 57917598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 58017545Skarels } 5818556Sroot return (0); 5827502Sroot } 5837502Sroot 5847502Sroot /* 58525391Skarels * "close" a line discipline 58625391Skarels */ 58725391Skarels ttylclose(tp) 58825391Skarels register struct tty *tp; 58925391Skarels { 59025391Skarels 59125391Skarels ttywflush(tp); 59225391Skarels } 59325391Skarels 59425391Skarels /* 5957502Sroot * clean tp on last close 5967502Sroot */ 5977502Sroot ttyclose(tp) 5987625Ssam register struct tty *tp; 5997502Sroot { 60030534Skarels if (constty == tp) 60130534Skarels constty = NULL; 60225391Skarels ttyflush(tp, FREAD|FWRITE); 60335811Smarc tp->t_pgid = 0; 6047502Sroot tp->t_state = 0; 6057502Sroot } 6067502Sroot 6077502Sroot /* 60825391Skarels * Handle modem control transition on a tty. 60925391Skarels * Flag indicates new state of carrier. 61025391Skarels * Returns 0 if the line should be turned off, otherwise 1. 61125391Skarels */ 61225391Skarels ttymodem(tp, flag) 61325391Skarels register struct tty *tp; 61425391Skarels { 61525391Skarels 61635811Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag & MDMBUF)) { 61725391Skarels /* 61825391Skarels * MDMBUF: do flow control according to carrier flag 61925391Skarels */ 62025391Skarels if (flag) { 62125391Skarels tp->t_state &= ~TS_TTSTOP; 62225391Skarels ttstart(tp); 62325391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 62425391Skarels tp->t_state |= TS_TTSTOP; 62525391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 62625391Skarels } 62725391Skarels } else if (flag == 0) { 62825391Skarels /* 62925391Skarels * Lost carrier. 63025391Skarels */ 63125391Skarels tp->t_state &= ~TS_CARR_ON; 63225391Skarels if (tp->t_state & TS_ISOPEN) { 63335811Smarc if ((tp->t_lflag & NOHANG) == 0) { 63435811Smarc gsignal(tp->t_pgid, SIGHUP); 63535811Smarc gsignal(tp->t_pgid, SIGCONT); 63625391Skarels ttyflush(tp, FREAD|FWRITE); 63725391Skarels return (0); 63825391Skarels } 63925391Skarels } 64025391Skarels } else { 64125391Skarels /* 64225391Skarels * Carrier now on. 64325391Skarels */ 64425391Skarels tp->t_state |= TS_CARR_ON; 645*37584Smarc ttwakeup(tp); 64625391Skarels } 64725391Skarels return (1); 64825391Skarels } 64925391Skarels 65025391Skarels /* 65125404Skarels * Default modem control routine (for other line disciplines). 65225404Skarels * Return argument flag, to turn off device on carrier drop. 65325404Skarels */ 65425415Skarels nullmodem(tp, flag) 65525415Skarels register struct tty *tp; 65625404Skarels int flag; 65725404Skarels { 65825404Skarels 65925404Skarels if (flag) 66025404Skarels tp->t_state |= TS_CARR_ON; 66125404Skarels else 66225404Skarels tp->t_state &= ~TS_CARR_ON; 66325404Skarels return (flag); 66425404Skarels } 66525404Skarels 66625404Skarels /* 6677502Sroot * reinput pending characters after state switch 66817545Skarels * call at spltty(). 6697502Sroot */ 6707502Sroot ttypend(tp) 6717625Ssam register struct tty *tp; 6727502Sroot { 6737502Sroot struct clist tq; 6747502Sroot register c; 6757502Sroot 67635811Smarc tp->t_lflag &= ~PENDIN; 6779578Ssam tp->t_state |= TS_TYPEN; 6787502Sroot tq = tp->t_rawq; 6797502Sroot tp->t_rawq.c_cc = 0; 6807502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6817502Sroot while ((c = getc(&tq)) >= 0) 6827502Sroot ttyinput(c, tp); 6839578Ssam tp->t_state &= ~TS_TYPEN; 6847502Sroot } 6857502Sroot 6867502Sroot /* 68735811Smarc * 6889578Ssam * Place a character on raw TTY input queue, 6899578Ssam * putting in delimiters and waking up top 6909578Ssam * half as needed. Also echo if required. 6919578Ssam * The arguments are the character and the 6929578Ssam * appropriate tty structure. 6937502Sroot */ 6947502Sroot ttyinput(c, tp) 6957625Ssam register c; 6967625Ssam register struct tty *tp; 6977502Sroot { 69835811Smarc register int iflag = tp->t_iflag; 69935811Smarc register int lflag = tp->t_lflag; 70035811Smarc register u_char *cc = tp->t_cc; 70135811Smarc int i, err; 7027502Sroot 7039578Ssam /* 7049578Ssam * If input is pending take it first. 7059578Ssam */ 70635811Smarc if (lflag&PENDIN) 7077502Sroot ttypend(tp); 70835811Smarc /* 70935811Smarc * Gather stats. 71035811Smarc */ 7117502Sroot tk_nin++; 71235811Smarc if (lflag&ICANON) { 71335811Smarc tk_cancc++; 71435811Smarc tp->t_cancc++; 71535811Smarc } else { 71635811Smarc tk_rawcc++; 71735811Smarc tp->t_rawcc++; 71835811Smarc } 7199578Ssam /* 72035811Smarc * Handle exceptional conditions (break, parity, framing). 7219578Ssam */ 72235811Smarc if (err = (c&TTY_ERRORMASK)) { 72335811Smarc c &= ~TTY_ERRORMASK; 72435811Smarc if (err&TTY_FE && !c) { /* break */ 72535811Smarc if (iflag&IGNBRK) 72635811Smarc goto endcase; 72735811Smarc else if (iflag&BRKINT && lflag&ISIG && 72835811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 72935811Smarc c = cc[VINTR]; 73035811Smarc else { 73135811Smarc c = 0; 73235811Smarc if (iflag&PARMRK) 73335811Smarc goto parmrk; 73435811Smarc } 73535811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 73635811Smarc if (iflag&IGNPAR) 73735811Smarc goto endcase; 73835811Smarc else if (iflag&PARMRK) { 73935811Smarc parmrk: 74035811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 74135811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 74235811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 74335811Smarc goto endcase; 74435811Smarc } else 74535811Smarc c = 0; 7467502Sroot } 7479578Ssam } 7489578Ssam /* 74935811Smarc * In tandem mode, check high water mark. 7509578Ssam */ 75135811Smarc if (iflag&IXOFF) 75235811Smarc ttyblock(tp); 75335811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 7549578Ssam c &= 0177; 7559578Ssam /* 7569578Ssam * Check for literal nexting very first 7579578Ssam */ 7589578Ssam if (tp->t_state&TS_LNCH) { 75935811Smarc c |= TTY_QUOTE; 7609578Ssam tp->t_state &= ~TS_LNCH; 7619578Ssam } 7629578Ssam /* 7639578Ssam * Scan for special characters. This code 7649578Ssam * is really just a big case statement with 7659578Ssam * non-constant cases. The bottom of the 7669578Ssam * case statement is labeled ``endcase'', so goto 7679578Ssam * it after a case match, or similar. 7689578Ssam */ 76935811Smarc /* 77035811Smarc * Control chars which aren't controlled 77135811Smarc * by ICANON, ISIG, or IXON. 77235811Smarc */ 77335811Smarc if (iflag&IEXTEN) { 77435811Smarc if (CCEQ(cc[VLNEXT],c)) { 77535811Smarc if (lflag&ECHO) { 77635811Smarc if (lflag&ECHOE) 77735811Smarc ttyout("^\b", tp); 77835811Smarc else 77935811Smarc ttyecho(c, tp); 78035811Smarc } 7819578Ssam tp->t_state |= TS_LNCH; 7829578Ssam goto endcase; 7839578Ssam } 78435811Smarc if (CCEQ(cc[VFLUSHO],c)) { 78535811Smarc if (lflag&FLUSHO) 78635811Smarc tp->t_lflag &= ~FLUSHO; 7877502Sroot else { 78812752Ssam ttyflush(tp, FWRITE); 7897502Sroot ttyecho(c, tp); 7909578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7917502Sroot ttyretype(tp); 79235811Smarc tp->t_lflag |= FLUSHO; 7937502Sroot } 7949578Ssam goto startoutput; 7959578Ssam } 79635811Smarc } 79735811Smarc /* 79835811Smarc * Signals. 79935811Smarc */ 80035811Smarc if (lflag&ISIG) { 80135811Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 80235811Smarc if ((lflag&NOFLSH) == 0) 80335811Smarc ttyflush(tp, FREAD|FWRITE); 80435811Smarc ttyecho(c, tp); 80535811Smarc gsignal(tp->t_pgid, CCEQ(cc[VINTR],c) ? 80635811Smarc SIGINT : SIGQUIT); 80735811Smarc goto endcase; 80835811Smarc } 80935811Smarc if (CCEQ(cc[VSUSP],c)) { 81035811Smarc if ((lflag&NOFLSH) == 0) 81112752Ssam ttyflush(tp, FREAD); 8129578Ssam ttyecho(c, tp); 81335811Smarc gsignal(tp->t_pgid, SIGTSTP); 8149578Ssam goto endcase; 8159578Ssam } 8169578Ssam } 8179578Ssam /* 8189578Ssam * Handle start/stop characters. 8199578Ssam */ 82035811Smarc if (iflag&IXON) { 82135811Smarc if (CCEQ(cc[VSTOP],c)) { 82235811Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 82335811Smarc tp->t_state |= TS_TTSTOP; 82435811Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 82535811Smarc return; 82635811Smarc } 82735811Smarc if (!CCEQ(cc[VSTART], c)) 82835811Smarc return; 82935811Smarc /* 83035811Smarc * if VSTART == VSTOP then toggle 83135811Smarc */ 83235811Smarc goto endcase; 8339578Ssam } 83435811Smarc if (CCEQ(cc[VSTART], c)) 83535811Smarc goto restartoutput; 8369578Ssam } 8379578Ssam /* 83835811Smarc * IGNCR, ICRNL, & INLCR 8399578Ssam */ 84035811Smarc if (c == '\r') { 84135811Smarc if (iflag&IGNCR) 84235811Smarc goto endcase; 84335811Smarc else if (iflag&ICRNL) 84435811Smarc c = '\n'; 8459578Ssam } 84635811Smarc else if (c == '\n' && iflag&INLCR) 84735811Smarc c = '\r'; 8489578Ssam /* 84935811Smarc * Non canonical mode; don't process line editing 8509578Ssam * characters; check high water mark for wakeup. 85135811Smarc * 8529578Ssam */ 85335811Smarc if (!(lflag&ICANON)) { 8549578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 85535811Smarc if (iflag&IMAXBEL) { 85635811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 85735811Smarc (void) ttyoutput(CTRL('g'), tp); 85835811Smarc } else 85935811Smarc ttyflush(tp, FREAD | FWRITE); 86035811Smarc } else { 86135811Smarc if (putc(c, &tp->t_rawq) >= 0) { 86235811Smarc ttwakeup(tp); 86335811Smarc ttyecho(c, tp); 86435811Smarc } 8657502Sroot } 8669578Ssam goto endcase; 8679578Ssam } 8689578Ssam /* 86935811Smarc * From here on down canonical mode character 8709578Ssam * processing takes place. 8719578Ssam */ 87235811Smarc /* 87335811Smarc * erase (^H / ^?) 87435811Smarc */ 87535811Smarc if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c)) { 8769578Ssam if (tp->t_rawq.c_cc) 8779578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8789578Ssam goto endcase; 8799578Ssam } 88035811Smarc /* 88135811Smarc * kill (^U) 88235811Smarc */ 88335811Smarc if (CCEQ(cc[VKILL], c)) { 884*37584Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 885*37584Smarc !(lflag&ECHOPRT)) { 8869578Ssam while (tp->t_rawq.c_cc) 8879578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8889578Ssam } else { 8899578Ssam ttyecho(c, tp); 89035811Smarc if (lflag&ECHOK || lflag&ECHOKE) 89135811Smarc ttyecho('\n', tp); 8929578Ssam while (getc(&tp->t_rawq) > 0) 8939578Ssam ; 8949578Ssam tp->t_rocount = 0; 8959578Ssam } 8969578Ssam tp->t_state &= ~TS_LOCAL; 8979578Ssam goto endcase; 8989578Ssam } 8999578Ssam /* 90035811Smarc * word erase (^W) 9019578Ssam */ 90235811Smarc if (CCEQ(cc[VWERASE], c)) { 90335811Smarc int ctype; 90435811Smarc 90535811Smarc #define CTYPE(c) ((lflag&ALTWERASE) ? (partab[(c)&TTY_CHARMASK]&0100) : 0) 90635811Smarc /* 90735811Smarc * erase whitespace 90835811Smarc */ 90935811Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 91035811Smarc ttyrub(c, tp); 91135811Smarc if (c == -1) 91234492Skarels goto endcase; 91335811Smarc /* 91435811Smarc * special case last char of token 91535811Smarc */ 91635811Smarc ttyrub(c, tp); 91735811Smarc c = unputc(&tp->t_rawq); 91835811Smarc if (c == -1 || c == ' ' || c == '\t') { 91935811Smarc if (c != -1) 92035811Smarc (void) putc(c, &tp->t_rawq); 92134492Skarels goto endcase; 92234492Skarels } 92335811Smarc /* 92435811Smarc * erase rest of token 92535811Smarc */ 92635811Smarc ctype = CTYPE(c); 92735811Smarc do { 92835811Smarc ttyrub(c, tp); 92935811Smarc c = unputc(&tp->t_rawq); 93035811Smarc if (c == -1) 93135811Smarc goto endcase; 93235811Smarc } while (c != ' ' && c != '\t' && CTYPE(c) == ctype); 93335811Smarc (void) putc(c, &tp->t_rawq); 93435811Smarc goto endcase; 93535811Smarc #undef CTYPE 9369578Ssam } 9379578Ssam /* 93835811Smarc * reprint line (^R) 93935811Smarc */ 94035811Smarc if (CCEQ(cc[VREPRINT], c)) { 94135811Smarc ttyretype(tp); 94235811Smarc goto endcase; 94335811Smarc } 94435811Smarc /* 9459578Ssam * Check for input buffer overflow 9469578Ssam */ 94710391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 94835811Smarc if (iflag&IMAXBEL) { 94935811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 95035811Smarc (void) ttyoutput(CTRL('g'), tp); 95135811Smarc } else 95235811Smarc ttyflush(tp, FREAD | FWRITE); 9539578Ssam goto endcase; 95410391Ssam } 9559578Ssam /* 9569578Ssam * Put data char in q for user and 9579578Ssam * wakeup on seeing a line delimiter. 9589578Ssam */ 9599578Ssam if (putc(c, &tp->t_rawq) >= 0) { 96035811Smarc if (ttbreakc(c)) { 9619578Ssam tp->t_rocount = 0; 9629578Ssam catq(&tp->t_rawq, &tp->t_canq); 9637502Sroot ttwakeup(tp); 9649578Ssam } else if (tp->t_rocount++ == 0) 9659578Ssam tp->t_rocol = tp->t_col; 9669578Ssam if (tp->t_state&TS_ERASE) { 96735811Smarc /* 96835811Smarc * end of prterase \.../ 96935811Smarc */ 9709578Ssam tp->t_state &= ~TS_ERASE; 9719578Ssam (void) ttyoutput('/', tp); 9729578Ssam } 9739578Ssam i = tp->t_col; 9747502Sroot ttyecho(c, tp); 97535811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 97635811Smarc /* 97735811Smarc * Place the cursor over the '^' of the ^D. 97835811Smarc */ 9799578Ssam i = MIN(2, tp->t_col - i); 9809578Ssam while (i > 0) { 9819578Ssam (void) ttyoutput('\b', tp); 9829578Ssam i--; 9839578Ssam } 9849578Ssam } 9857502Sroot } 9869578Ssam endcase: 9879578Ssam /* 98835811Smarc * IXANY means allow any character to restart output. 9899578Ssam */ 99035811Smarc if ((tp->t_state&TS_TTSTOP) && !(iflag&IXANY) 99135811Smarc && cc[VSTART] != cc[VSTOP]) 9927502Sroot return; 9939578Ssam restartoutput: 9947502Sroot tp->t_state &= ~TS_TTSTOP; 99535811Smarc tp->t_lflag &= ~FLUSHO; 9969578Ssam startoutput: 9977502Sroot ttstart(tp); 9987502Sroot } 9997502Sroot 10007502Sroot /* 10019578Ssam * Put character on TTY output queue, adding delays, 10027502Sroot * expanding tabs, and handling the CR/NL bit. 10039578Ssam * This is called both from the top half for output, 10049578Ssam * and from interrupt level for echoing. 10057502Sroot * The arguments are the character and the tty structure. 10067502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 10077502Sroot * Must be recursive. 10087502Sroot */ 10097502Sroot ttyoutput(c, tp) 10107502Sroot register c; 10117502Sroot register struct tty *tp; 10127502Sroot { 10137502Sroot register char *colp; 10147502Sroot register ctype; 101535811Smarc register long oflag = tp->t_oflag; 101635811Smarc 101735811Smarc if (!(oflag&OPOST)) { 101835811Smarc if (tp->t_lflag&FLUSHO) 10197502Sroot return (-1); 10207502Sroot if (putc(c, &tp->t_outq)) 10217625Ssam return (c); 10227502Sroot tk_nout++; 102335811Smarc tp->t_outcc++; 10247502Sroot return (-1); 10257502Sroot } 102635811Smarc c &= TTY_CHARMASK; 10277502Sroot /* 10287502Sroot * Turn tabs to spaces as required 10297502Sroot */ 103035811Smarc if (c == '\t' && oflag&OXTABS ) { 10317502Sroot register int s; 10327502Sroot 10337502Sroot c = 8 - (tp->t_col&7); 103435811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 103517545Skarels s = spltty(); /* don't interrupt tabs */ 10367502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10377502Sroot tk_nout += c; 103835811Smarc tp->t_outcc += c; 10397502Sroot splx(s); 10407502Sroot } 10417502Sroot tp->t_col += c; 10427502Sroot return (c ? -1 : '\t'); 10437502Sroot } 104435811Smarc if (c == CEOT && oflag&ONOEOT) 104535811Smarc return(-1); 10467502Sroot tk_nout++; 104735811Smarc tp->t_outcc++; 10487502Sroot /* 10497502Sroot * turn <nl> to <cr><lf> if desired. 10507502Sroot */ 105135811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 10527502Sroot return (c); 105335811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 105435811Smarc return (c); 10557502Sroot /* 10567502Sroot * Calculate delays. 10577502Sroot * The numbers here represent clock ticks 10587502Sroot * and are not necessarily optimal for all terminals. 10599578Ssam * 10609578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 106135811Smarc * 106235811Smarc * (actually, should THROW AWAY terminals which need delays) 10637502Sroot */ 10647502Sroot colp = &tp->t_col; 10657502Sroot ctype = partab[c]; 10667502Sroot c = 0; 10677502Sroot switch (ctype&077) { 10687502Sroot 10697502Sroot case ORDINARY: 10707502Sroot (*colp)++; 10717502Sroot 10727502Sroot case CONTROL: 10737502Sroot break; 10747502Sroot 10757502Sroot case BACKSPACE: 10767502Sroot if (*colp) 10777502Sroot (*colp)--; 10787502Sroot break; 10797502Sroot 108013821Ssam /* 108113821Ssam * This macro is close enough to the correct thing; 108213821Ssam * it should be replaced by real user settable delays 108313821Ssam * in any event... 108413821Ssam */ 108513821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10867502Sroot case NEWLINE: 10877502Sroot ctype = (tp->t_flags >> 8) & 03; 10887625Ssam if (ctype == 1) { /* tty 37 */ 108926357Skarels if (*colp > 0) { 109026357Skarels c = (((unsigned)*colp) >> 4) + 3; 109126357Skarels if ((unsigned)c > 6) 109226357Skarels c = 6; 109326357Skarels } 10949578Ssam } else if (ctype == 2) /* vt05 */ 109513821Ssam c = mstohz(100); 10967502Sroot *colp = 0; 10977502Sroot break; 10987502Sroot 10997502Sroot case TAB: 11007502Sroot ctype = (tp->t_flags >> 10) & 03; 11017625Ssam if (ctype == 1) { /* tty 37 */ 11027502Sroot c = 1 - (*colp | ~07); 11037625Ssam if (c < 5) 11047502Sroot c = 0; 11057502Sroot } 11067502Sroot *colp |= 07; 11077502Sroot (*colp)++; 11087502Sroot break; 11097502Sroot 11107502Sroot case VTAB: 11119578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 11127502Sroot c = 0177; 11137502Sroot break; 11147502Sroot 11157502Sroot case RETURN: 11167502Sroot ctype = (tp->t_flags >> 12) & 03; 11179578Ssam if (ctype == 1) /* tn 300 */ 111813821Ssam c = mstohz(83); 11199578Ssam else if (ctype == 2) /* ti 700 */ 112013821Ssam c = mstohz(166); 11219578Ssam else if (ctype == 3) { /* concept 100 */ 11227502Sroot int i; 11239578Ssam 11247502Sroot if ((i = *colp) >= 0) 11259578Ssam for (; i < 9; i++) 11267502Sroot (void) putc(0177, &tp->t_outq); 11277502Sroot } 11287502Sroot *colp = 0; 11297502Sroot } 113035811Smarc if (c && (tp->t_lflag&FLUSHO) == 0) 113135811Smarc (void) putc(c|TTY_QUOTE, &tp->t_outq); 11327502Sroot return (-1); 11337502Sroot } 113413821Ssam #undef mstohz 11357502Sroot 11367502Sroot /* 11377502Sroot * Called from device's read routine after it has 11387502Sroot * calculated the tty-structure given as argument. 11397502Sroot */ 1140*37584Smarc ttread(tp, uio, flag) 11417625Ssam register struct tty *tp; 11427722Swnj struct uio *uio; 11437502Sroot { 11447502Sroot register struct clist *qp; 114535811Smarc register int c; 114635811Smarc register long lflag = tp->t_lflag; 114735811Smarc register long iflag = tp->t_iflag; 114835811Smarc register u_char *cc = tp->t_cc; 11499859Ssam int s, first, error = 0; 11507502Sroot 11517502Sroot loop: 1152*37584Smarc s = spltty(); 11539578Ssam /* 1154*37584Smarc * take pending input first 11559578Ssam */ 115635811Smarc if (lflag&PENDIN) 11577502Sroot ttypend(tp); 1158*37584Smarc /* 1159*37584Smarc * Handle carrier. 1160*37584Smarc */ 1161*37584Smarc if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) { 1162*37584Smarc if (tp->t_state&TS_ISOPEN) { 1163*37584Smarc splx(s); 1164*37584Smarc return (0); /* EOF */ 1165*37584Smarc } else if (flag&FNDELAY) { 1166*37584Smarc splx(s); 1167*37584Smarc return (EWOULDBLOCK); 1168*37584Smarc } else { 1169*37584Smarc /* 1170*37584Smarc * sleep awaiting carrier 1171*37584Smarc */ 1172*37584Smarc sleep((caddr_t)&tp->t_rawq, TTIPRI); 1173*37584Smarc splx(s); 1174*37584Smarc goto loop; 1175*37584Smarc } 1176*37584Smarc } 11779859Ssam splx(s); 11789578Ssam /* 11799578Ssam * Hang process if it's in the background. 11809578Ssam */ 118135811Smarc if (u.u_ttyp == tp && u.u_procp->p_pgid != tp->t_pgid) { 118224392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 118324392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 118435811Smarc u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0) 11858520Sroot return (EIO); 118635811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTIN); 11877502Sroot sleep((caddr_t)&lbolt, TTIPRI); 118823165Sbloom goto loop; 11897502Sroot } 11909578Ssam /* 119135811Smarc * If canonical, use the canonical queue, 119235811Smarc * else use the raw queue. 1193*37584Smarc * 1194*37584Smarc * XXX - should get rid of canonical queue. 1195*37584Smarc * (actually, should get rid of clists...) 11969578Ssam */ 119735811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 11989578Ssam /* 11999578Ssam * No input, sleep on rawq awaiting hardware 12009578Ssam * receipt and notification. 12019578Ssam */ 120217545Skarels s = spltty(); 12039578Ssam if (qp->c_cc <= 0) { 1204*37584Smarc /** XXX ??? ask mike why TS_CARR_ON was (once) necessary here 12059578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 12069578Ssam (tp->t_state&TS_NBIO)) { 12079859Ssam splx(s); 12089578Ssam return (EWOULDBLOCK); 12097502Sroot } 1210*37584Smarc **/ 1211*37584Smarc if (flag&FNDELAY) { 1212*37584Smarc splx(s); 1213*37584Smarc return (EWOULDBLOCK); 1214*37584Smarc } 12159578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 12169859Ssam splx(s); 12179578Ssam goto loop; 12189578Ssam } 12199859Ssam splx(s); 12209578Ssam /* 122135811Smarc * Input present, check for input mapping and processing. 12229578Ssam */ 12239578Ssam first = 1; 12249578Ssam while ((c = getc(qp)) >= 0) { 12259578Ssam /* 122635811Smarc * delayed suspend (^Y) 12279578Ssam */ 122835811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 122935811Smarc gsignal(tp->t_pgid, SIGTSTP); 12309578Ssam if (first) { 12319578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12329578Ssam goto loop; 12339578Ssam } 12349578Ssam break; 12357502Sroot } 12369578Ssam /* 123735811Smarc * Interpret EOF only in canonical mode. 12389578Ssam */ 123935811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12409578Ssam break; 12419578Ssam /* 12429578Ssam * Give user character. 12439578Ssam */ 124435811Smarc error = ureadc(c , uio); 12459578Ssam if (error) 12469578Ssam break; 124714938Smckusick if (uio->uio_resid == 0) 12489578Ssam break; 12499578Ssam /* 125035811Smarc * In canonical mode check for a "break character" 12519578Ssam * marking the end of a "line of input". 12529578Ssam */ 125335811Smarc if (lflag&ICANON && ttbreakc(c)) { 12549578Ssam break; 125535811Smarc } 12569578Ssam first = 0; 12577502Sroot } 12589859Ssam checktandem: 12599578Ssam /* 12609578Ssam * Look to unblock output now that (presumably) 12619578Ssam * the input queue has gone down. 12629578Ssam */ 126335811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 126435811Smarc if (cc[VSTART] != _POSIX_VDISABLE 126535811Smarc && putc(cc[VSTART], &tp->t_outq) == 0) { 12667502Sroot tp->t_state &= ~TS_TBLOCK; 12677502Sroot ttstart(tp); 12687502Sroot } 126935811Smarc } 12708520Sroot return (error); 12717502Sroot } 12727502Sroot 12737502Sroot /* 127425391Skarels * Check the output queue on tp for space for a kernel message 127525391Skarels * (from uprintf/tprintf). Allow some space over the normal 127625391Skarels * hiwater mark so we don't lose messages due to normal flow 127725391Skarels * control, but don't let the tty run amok. 127830695Skarels * Sleeps here are not interruptible, but we return prematurely 127930695Skarels * if new signals come in. 128025391Skarels */ 128125391Skarels ttycheckoutq(tp, wait) 128225391Skarels register struct tty *tp; 128325391Skarels int wait; 128425391Skarels { 128530695Skarels int hiwat, s, oldsig; 128625391Skarels 128735811Smarc hiwat = tp->t_hiwat; 128825391Skarels s = spltty(); 128930695Skarels oldsig = u.u_procp->p_sig; 129025391Skarels if (tp->t_outq.c_cc > hiwat + 200) 129129946Skarels while (tp->t_outq.c_cc > hiwat) { 129229946Skarels ttstart(tp); 129330695Skarels if (wait == 0 || u.u_procp->p_sig != oldsig) { 129429946Skarels splx(s); 129529946Skarels return (0); 129629946Skarels } 129730695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 129829946Skarels tp->t_state |= TS_ASLEEP; 129930695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 130025391Skarels } 130125391Skarels splx(s); 130225391Skarels return (1); 130325391Skarels } 130425391Skarels 130525391Skarels /* 13067502Sroot * Called from the device's write routine after it has 13077502Sroot * calculated the tty-structure given as argument. 13087502Sroot */ 1309*37584Smarc ttwrite(tp, uio, flag) 13107625Ssam register struct tty *tp; 13119578Ssam register struct uio *uio; 13127502Sroot { 13137502Sroot register char *cp; 13149578Ssam register int cc, ce, c; 13159578Ssam int i, hiwat, cnt, error, s; 13167502Sroot char obuf[OBUFSIZ]; 13177502Sroot 131835811Smarc hiwat = tp->t_hiwat; 13199578Ssam cnt = uio->uio_resid; 13209578Ssam error = 0; 13217502Sroot loop: 1322*37584Smarc s = spltty(); 1323*37584Smarc if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) { 1324*37584Smarc if (tp->t_state&TS_ISOPEN) { 1325*37584Smarc splx(s); 1326*37584Smarc return (EIO); 1327*37584Smarc } else if (flag&FNDELAY) { 1328*37584Smarc splx(s); 1329*37584Smarc return (EWOULDBLOCK); 1330*37584Smarc } else { 1331*37584Smarc /* 1332*37584Smarc * sleep awaiting carrier 1333*37584Smarc */ 1334*37584Smarc sleep((caddr_t)&tp->t_rawq, TTIPRI); 1335*37584Smarc splx(s); 1336*37584Smarc goto loop; 1337*37584Smarc } 1338*37584Smarc } 1339*37584Smarc splx(s); 13409578Ssam /* 13419578Ssam * Hang the process if it's in the background. 13429578Ssam */ 134335811Smarc if (u.u_ttyp == tp && 134435811Smarc u.u_procp->p_pgid != tp->t_pgid && 134535811Smarc (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 134624392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 134735811Smarc !(u.u_procp->p_sigmask & sigmask(SIGTTOU)) && 134835811Smarc u.u_procp->p_pgrp->pg_jobc) { 134935811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU); 13507502Sroot sleep((caddr_t)&lbolt, TTIPRI); 135121776Sbloom goto loop; 13527502Sroot } 13539578Ssam /* 13549578Ssam * Process the user's data in at most OBUFSIZ 13559578Ssam * chunks. Perform lower case simulation and 13569578Ssam * similar hacks. Keep track of high water 13579578Ssam * mark, sleep on overflow awaiting device aid 13589578Ssam * in acquiring new space. 13599578Ssam */ 13607822Sroot while (uio->uio_resid > 0) { 136132067Skarels if (tp->t_outq.c_cc > hiwat) { 136232067Skarels cc = 0; 136332067Skarels goto ovhiwat; 136432067Skarels } 13659578Ssam /* 13669578Ssam * Grab a hunk of data from the user. 13679578Ssam */ 13687822Sroot cc = uio->uio_iov->iov_len; 13697822Sroot if (cc == 0) { 13707822Sroot uio->uio_iovcnt--; 13717822Sroot uio->uio_iov++; 137221776Sbloom if (uio->uio_iovcnt <= 0) 13737822Sroot panic("ttwrite"); 13747822Sroot continue; 13757822Sroot } 13767822Sroot if (cc > OBUFSIZ) 13777822Sroot cc = OBUFSIZ; 13787502Sroot cp = obuf; 137912752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13808520Sroot if (error) 13817502Sroot break; 138235811Smarc if (tp->t_lflag&FLUSHO) 13837502Sroot continue; 13849578Ssam /* 13859578Ssam * If nothing fancy need be done, grab those characters we 13869578Ssam * can handle without any of ttyoutput's processing and 13879578Ssam * just transfer them to the output q. For those chars 13889578Ssam * which require special processing (as indicated by the 13899578Ssam * bits in partab), call ttyoutput. After processing 13909578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13919578Ssam * immediately. 13929578Ssam */ 13939578Ssam while (cc > 0) { 139435811Smarc if (!(tp->t_oflag&OPOST)) 13957502Sroot ce = cc; 13967502Sroot else { 139734492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 139834492Skarels (u_char *)partab, 077); 13999578Ssam /* 14009578Ssam * If ce is zero, then we're processing 14019578Ssam * a special character through ttyoutput. 14029578Ssam */ 14039578Ssam if (ce == 0) { 14047502Sroot tp->t_rocount = 0; 14057502Sroot if (ttyoutput(*cp, tp) >= 0) { 140621776Sbloom /* no c-lists, wait a bit */ 140721776Sbloom ttstart(tp); 140821776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 140921776Sbloom if (cc != 0) { 141021776Sbloom uio->uio_iov->iov_base -= cc; 141121776Sbloom uio->uio_iov->iov_len += cc; 141221776Sbloom uio->uio_resid += cc; 141321776Sbloom uio->uio_offset -= cc; 141421776Sbloom } 141521776Sbloom goto loop; 14167502Sroot } 14179578Ssam cp++, cc--; 141835811Smarc if ((tp->t_lflag&FLUSHO) || 14199578Ssam tp->t_outq.c_cc > hiwat) 14207502Sroot goto ovhiwat; 14219578Ssam continue; 14227502Sroot } 14237502Sroot } 14249578Ssam /* 14259578Ssam * A bunch of normal characters have been found, 14269578Ssam * transfer them en masse to the output queue and 14279578Ssam * continue processing at the top of the loop. 14289578Ssam * If there are any further characters in this 14299578Ssam * <= OBUFSIZ chunk, the first should be a character 14309578Ssam * requiring special handling by ttyoutput. 14319578Ssam */ 14327502Sroot tp->t_rocount = 0; 14339578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14349578Ssam ce -= i; 14359578Ssam tp->t_col += ce; 14369578Ssam cp += ce, cc -= ce, tk_nout += ce; 143735811Smarc tp->t_outcc += ce; 14389578Ssam if (i > 0) { 14399578Ssam /* out of c-lists, wait a bit */ 14407502Sroot ttstart(tp); 14417502Sroot sleep((caddr_t)&lbolt, TTOPRI); 144221776Sbloom uio->uio_iov->iov_base -= cc; 144321776Sbloom uio->uio_iov->iov_len += cc; 144421776Sbloom uio->uio_resid += cc; 144521776Sbloom uio->uio_offset -= cc; 144621776Sbloom goto loop; 14477502Sroot } 144835811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 14497502Sroot goto ovhiwat; 14507502Sroot } 145135811Smarc ttstart(tp); 14527502Sroot } 14538520Sroot return (error); 14547502Sroot ovhiwat: 14559578Ssam if (cc != 0) { 14569578Ssam uio->uio_iov->iov_base -= cc; 14579578Ssam uio->uio_iov->iov_len += cc; 14589578Ssam uio->uio_resid += cc; 14599578Ssam uio->uio_offset -= cc; 14609578Ssam } 146132067Skarels ttstart(tp); 146232067Skarels s = spltty(); 14639578Ssam /* 146435811Smarc * This can only occur if FLUSHO is set in t_lflag, 146532067Skarels * or if ttstart/oproc is synchronous (or very fast). 14669578Ssam */ 14677502Sroot if (tp->t_outq.c_cc <= hiwat) { 14689578Ssam splx(s); 14697502Sroot goto loop; 14707502Sroot } 1471*37584Smarc if (flag&FNDELAY) { 147217545Skarels splx(s); 14737822Sroot if (uio->uio_resid == cnt) 14748520Sroot return (EWOULDBLOCK); 14758520Sroot return (0); 14767502Sroot } 14777502Sroot tp->t_state |= TS_ASLEEP; 14787502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14799578Ssam splx(s); 14807502Sroot goto loop; 14817502Sroot } 14827502Sroot 14837502Sroot /* 14847502Sroot * Rubout one character from the rawq of tp 14857502Sroot * as cleanly as possible. 14867502Sroot */ 14877502Sroot ttyrub(c, tp) 14887625Ssam register c; 14897625Ssam register struct tty *tp; 14907502Sroot { 14917502Sroot register char *cp; 14927502Sroot register int savecol; 14937502Sroot int s; 14947502Sroot char *nextc(); 14957502Sroot 149635811Smarc if ((tp->t_lflag&ECHO) == 0) 14977502Sroot return; 149835811Smarc tp->t_lflag &= ~FLUSHO; 149935811Smarc if (tp->t_lflag&ECHOE) { 15007502Sroot if (tp->t_rocount == 0) { 15017502Sroot /* 15027502Sroot * Screwed by ttwrite; retype 15037502Sroot */ 15047502Sroot ttyretype(tp); 15057502Sroot return; 15067502Sroot } 150735811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 15087502Sroot ttyrubo(tp, 2); 150935811Smarc else switch (partab[c&=0377]&077) { 15107502Sroot 15117502Sroot case ORDINARY: 151235811Smarc ttyrubo(tp, 1); 15137502Sroot break; 15147502Sroot 15157502Sroot case VTAB: 15167502Sroot case BACKSPACE: 15177502Sroot case CONTROL: 15187502Sroot case RETURN: 151935811Smarc if (tp->t_lflag&ECHOCTL) 15207502Sroot ttyrubo(tp, 2); 15217502Sroot break; 15227502Sroot 152335811Smarc case TAB: { 152435811Smarc int c; 152535811Smarc 15267502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15277502Sroot ttyretype(tp); 15287502Sroot return; 15297502Sroot } 153017545Skarels s = spltty(); 15317502Sroot savecol = tp->t_col; 15329578Ssam tp->t_state |= TS_CNTTB; 153335811Smarc tp->t_lflag |= FLUSHO; 15347502Sroot tp->t_col = tp->t_rocol; 15359578Ssam cp = tp->t_rawq.c_cf; 153635811Smarc c = *cp; /* XXX FIX NEXTC */ 153735811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 153835811Smarc ttyecho(c, tp); 153935811Smarc tp->t_lflag &= ~FLUSHO; 15409578Ssam tp->t_state &= ~TS_CNTTB; 15417502Sroot splx(s); 15427502Sroot /* 15437502Sroot * savecol will now be length of the tab 15447502Sroot */ 15457502Sroot savecol -= tp->t_col; 15467502Sroot tp->t_col += savecol; 15477502Sroot if (savecol > 8) 15487502Sroot savecol = 8; /* overflow screw */ 15497502Sroot while (--savecol >= 0) 15507502Sroot (void) ttyoutput('\b', tp); 15517502Sroot break; 155235811Smarc } 15537502Sroot 15547502Sroot default: 1555*37584Smarc /* XXX */ 155635811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 155735811Smarc c, partab[c&=0377]&077); 155835811Smarc /*panic("ttyrub");*/ 15597502Sroot } 156035811Smarc } else if (tp->t_lflag&ECHOPRT) { 15619578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15627502Sroot (void) ttyoutput('\\', tp); 15639578Ssam tp->t_state |= TS_ERASE; 15647502Sroot } 15657502Sroot ttyecho(c, tp); 15667502Sroot } else 156735811Smarc ttyecho(tp->t_cc[VERASE], tp); 15687502Sroot tp->t_rocount--; 15697502Sroot } 15707502Sroot 15717502Sroot /* 15727502Sroot * Crt back over cnt chars perhaps 15737502Sroot * erasing them. 15747502Sroot */ 15757502Sroot ttyrubo(tp, cnt) 15767625Ssam register struct tty *tp; 15777625Ssam int cnt; 15787502Sroot { 15797502Sroot 15807502Sroot while (--cnt >= 0) 158135811Smarc ttyout("\b \b", tp); 15827502Sroot } 15837502Sroot 15847502Sroot /* 15857502Sroot * Reprint the rawq line. 15867502Sroot * We assume c_cc has already been checked. 15877502Sroot */ 15887502Sroot ttyretype(tp) 15897625Ssam register struct tty *tp; 15907502Sroot { 15917502Sroot register char *cp; 15927502Sroot char *nextc(); 159335811Smarc int s, c; 15947502Sroot 159535811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 159635811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 15977502Sroot (void) ttyoutput('\n', tp); 159817545Skarels s = spltty(); 159935811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 160035811Smarc BIT OF FIRST CHAR ****/ 160135811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 160235811Smarc ttyecho(c, tp); 160335811Smarc } 160435811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 160535811Smarc ttyecho(c, tp); 160635811Smarc } 16079578Ssam tp->t_state &= ~TS_ERASE; 16087502Sroot splx(s); 16097502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16107502Sroot tp->t_rocol = 0; 16117502Sroot } 16127502Sroot 16137502Sroot /* 161435811Smarc * Echo a typed character to the terminal. 16157502Sroot */ 16167502Sroot ttyecho(c, tp) 16177625Ssam register c; 16187625Ssam register struct tty *tp; 16197502Sroot { 16209578Ssam if ((tp->t_state&TS_CNTTB) == 0) 162135811Smarc tp->t_lflag &= ~FLUSHO; 162235811Smarc if ((tp->t_lflag&ECHO) == 0 && !(tp->t_lflag&ECHONL && c == '\n')) 16237502Sroot return; 162435811Smarc if (tp->t_lflag&ECHOCTL) { 162535811Smarc if ((c&TTY_CHARMASK)<=037 && c!='\t' && c!='\n' || c==0177) { 16267502Sroot (void) ttyoutput('^', tp); 162735811Smarc c &= TTY_CHARMASK; 16287502Sroot if (c == 0177) 16297502Sroot c = '?'; 16307502Sroot else 16317502Sroot c += 'A' - 1; 16327502Sroot } 16337502Sroot } 163435811Smarc (void) ttyoutput(c, tp); 16357502Sroot } 16367502Sroot 16377502Sroot /* 16387502Sroot * send string cp to tp 16397502Sroot */ 16407502Sroot ttyout(cp, tp) 16417625Ssam register char *cp; 16427625Ssam register struct tty *tp; 16437502Sroot { 16447502Sroot register char c; 16457502Sroot 16467502Sroot while (c = *cp++) 16477502Sroot (void) ttyoutput(c, tp); 16487502Sroot } 16497502Sroot 16507502Sroot ttwakeup(tp) 16517502Sroot struct tty *tp; 16527502Sroot { 16537502Sroot 16547502Sroot if (tp->t_rsel) { 16557502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16567502Sroot tp->t_state &= ~TS_RCOLL; 16577502Sroot tp->t_rsel = 0; 16587502Sroot } 165912752Ssam if (tp->t_state & TS_ASYNC) 166035811Smarc gsignal(tp->t_pgid, SIGIO); 16617502Sroot wakeup((caddr_t)&tp->t_rawq); 16627502Sroot } 166335811Smarc 166435811Smarc /* 166535811Smarc * set tty hi and low water marks 166635811Smarc * 166735811Smarc * Try to arrange the dynamics so there's about one second 166835811Smarc * from hi to low water. 166935811Smarc * 167035811Smarc */ 167135811Smarc ttsetwater(tp) 167235811Smarc struct tty *tp; 167335811Smarc { 167435811Smarc register cps = tp->t_ospeed / 10; 167535811Smarc register x; 167635811Smarc 167735811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 167835811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 167935811Smarc x += cps; 168035811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 168135811Smarc tp->t_hiwat = roundup(x, CBSIZE); 168235811Smarc #undef clamp 168335811Smarc } 168435811Smarc 168535811Smarc ttspeedtab(speed, table) 168635811Smarc struct speedtab table[]; 168735811Smarc { 168835811Smarc register int i; 168935811Smarc 169035811Smarc for (i = 0; table[i].sp_speed != -1; i++) 169135811Smarc if (table[i].sp_speed == speed) 169235811Smarc return(table[i].sp_code); 169335811Smarc return(-1); 169435811Smarc } 1695