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*37728Smckusick * @(#)tty.c 7.17 (Berkeley) 05/09/89 723387Smckusick */ 839Sbill 917095Sbloom #include "param.h" 1017095Sbloom #include "systm.h" 1117095Sbloom #include "user.h" 1217095Sbloom #include "ioctl.h" 1317095Sbloom #include "tty.h" 1435811Smarc #define TTYDEFCHARS 1535811Smarc #include "ttydefaults.h" 1635811Smarc #undef TTYDEFCHARS 1735811Smarc #include "termios.h" 1817095Sbloom #include "proc.h" 1917095Sbloom #include "file.h" 2017095Sbloom #include "conf.h" 2129946Skarels #include "dkstat.h" 2217095Sbloom #include "uio.h" 2317095Sbloom #include "kernel.h" 24*37728Smckusick #include "vnode.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) 9537584Smarc 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 { 10837584Smarc int s = spltty(); 10912752Ssam 11013809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 11137584Smarc (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 11237584Smarc 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 ; 13237584Smarc ttwakeup(tp); 133903Sbill } 134903Sbill if (rw & FWRITE) { 13537584Smarc 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) 18537584Smarc 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) 20137584Smarc 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 30737584Smarc case FIOASYNC: 30837584Smarc if (*(int *)data) 30937584Smarc tp->t_state |= TS_ASYNC; 31037584Smarc else 31137584Smarc tp->t_state &= ~TS_ASYNC; 31237584Smarc break; 31337584Smarc 31437584Smarc case FIONBIO: 31537584Smarc break; /* XXX remove */ 31637584Smarc 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: 37037584Smarc 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 */ 37937584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 38037584Smarc splx(s); 38135811Smarc return (error); 38237584Smarc } else { 38337584Smarc if (!(tp->t_state&TS_CARR_ON) && 38437584Smarc (tp->t_cflag&CLOCAL) && 38537584Smarc !(t->c_cflag&CLOCAL)) { 38637584Smarc tp->t_state &= ~TS_ISOPEN; 38737584Smarc tp->t_state |= TS_WOPEN; 38837584Smarc ttwakeup(tp); 38937584Smarc } 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); 54037584Smarc if (nread > 0 || 54137584Smarc (!(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 5737502Sroot tp->t_dev = dev; 57435811Smarc 5757502Sroot tp->t_state &= ~TS_WOPEN; 57617545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 57717545Skarels tp->t_state |= TS_ISOPEN; 57817598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 57917545Skarels } 5808556Sroot return (0); 5817502Sroot } 5827502Sroot 5837502Sroot /* 58425391Skarels * "close" a line discipline 58525391Skarels */ 58625391Skarels ttylclose(tp) 58725391Skarels register struct tty *tp; 58825391Skarels { 58925391Skarels 59025391Skarels ttywflush(tp); 59125391Skarels } 59225391Skarels 59325391Skarels /* 5947502Sroot * clean tp on last close 5957502Sroot */ 5967502Sroot ttyclose(tp) 5977625Ssam register struct tty *tp; 5987502Sroot { 59930534Skarels if (constty == tp) 60030534Skarels constty = NULL; 60125391Skarels ttyflush(tp, FREAD|FWRITE); 60235811Smarc tp->t_pgid = 0; 6037502Sroot tp->t_state = 0; 6047502Sroot } 6057502Sroot 6067502Sroot /* 60725391Skarels * Handle modem control transition on a tty. 60825391Skarels * Flag indicates new state of carrier. 60925391Skarels * Returns 0 if the line should be turned off, otherwise 1. 61025391Skarels */ 61125391Skarels ttymodem(tp, flag) 61225391Skarels register struct tty *tp; 61325391Skarels { 61425391Skarels 61535811Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag & MDMBUF)) { 61625391Skarels /* 61725391Skarels * MDMBUF: do flow control according to carrier flag 61825391Skarels */ 61925391Skarels if (flag) { 62025391Skarels tp->t_state &= ~TS_TTSTOP; 62125391Skarels ttstart(tp); 62225391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 62325391Skarels tp->t_state |= TS_TTSTOP; 62425391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 62525391Skarels } 62625391Skarels } else if (flag == 0) { 62725391Skarels /* 62825391Skarels * Lost carrier. 62925391Skarels */ 63025391Skarels tp->t_state &= ~TS_CARR_ON; 63125391Skarels if (tp->t_state & TS_ISOPEN) { 63235811Smarc if ((tp->t_lflag & NOHANG) == 0) { 63335811Smarc gsignal(tp->t_pgid, SIGHUP); 63435811Smarc gsignal(tp->t_pgid, SIGCONT); 63525391Skarels ttyflush(tp, FREAD|FWRITE); 63625391Skarels return (0); 63725391Skarels } 63825391Skarels } 63925391Skarels } else { 64025391Skarels /* 64125391Skarels * Carrier now on. 64225391Skarels */ 64325391Skarels tp->t_state |= TS_CARR_ON; 64437584Smarc ttwakeup(tp); 64525391Skarels } 64625391Skarels return (1); 64725391Skarels } 64825391Skarels 64925391Skarels /* 65025404Skarels * Default modem control routine (for other line disciplines). 65125404Skarels * Return argument flag, to turn off device on carrier drop. 65225404Skarels */ 65325415Skarels nullmodem(tp, flag) 65425415Skarels register struct tty *tp; 65525404Skarels int flag; 65625404Skarels { 65725404Skarels 65825404Skarels if (flag) 65925404Skarels tp->t_state |= TS_CARR_ON; 66025404Skarels else 66125404Skarels tp->t_state &= ~TS_CARR_ON; 66225404Skarels return (flag); 66325404Skarels } 66425404Skarels 66525404Skarels /* 6667502Sroot * reinput pending characters after state switch 66717545Skarels * call at spltty(). 6687502Sroot */ 6697502Sroot ttypend(tp) 6707625Ssam register struct tty *tp; 6717502Sroot { 6727502Sroot struct clist tq; 6737502Sroot register c; 6747502Sroot 67535811Smarc tp->t_lflag &= ~PENDIN; 6769578Ssam tp->t_state |= TS_TYPEN; 6777502Sroot tq = tp->t_rawq; 6787502Sroot tp->t_rawq.c_cc = 0; 6797502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6807502Sroot while ((c = getc(&tq)) >= 0) 6817502Sroot ttyinput(c, tp); 6829578Ssam tp->t_state &= ~TS_TYPEN; 6837502Sroot } 6847502Sroot 6857502Sroot /* 68635811Smarc * 6879578Ssam * Place a character on raw TTY input queue, 6889578Ssam * putting in delimiters and waking up top 6899578Ssam * half as needed. Also echo if required. 6909578Ssam * The arguments are the character and the 6919578Ssam * appropriate tty structure. 6927502Sroot */ 6937502Sroot ttyinput(c, tp) 6947625Ssam register c; 6957625Ssam register struct tty *tp; 6967502Sroot { 69735811Smarc register int iflag = tp->t_iflag; 69835811Smarc register int lflag = tp->t_lflag; 69935811Smarc register u_char *cc = tp->t_cc; 70035811Smarc int i, err; 7017502Sroot 7029578Ssam /* 7039578Ssam * If input is pending take it first. 7049578Ssam */ 70535811Smarc if (lflag&PENDIN) 7067502Sroot ttypend(tp); 70735811Smarc /* 70835811Smarc * Gather stats. 70935811Smarc */ 7107502Sroot tk_nin++; 71135811Smarc if (lflag&ICANON) { 71235811Smarc tk_cancc++; 71335811Smarc tp->t_cancc++; 71435811Smarc } else { 71535811Smarc tk_rawcc++; 71635811Smarc tp->t_rawcc++; 71735811Smarc } 7189578Ssam /* 71935811Smarc * Handle exceptional conditions (break, parity, framing). 7209578Ssam */ 72135811Smarc if (err = (c&TTY_ERRORMASK)) { 72235811Smarc c &= ~TTY_ERRORMASK; 72335811Smarc if (err&TTY_FE && !c) { /* break */ 72435811Smarc if (iflag&IGNBRK) 72535811Smarc goto endcase; 72635811Smarc else if (iflag&BRKINT && lflag&ISIG && 72735811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 72835811Smarc c = cc[VINTR]; 72935811Smarc else { 73035811Smarc c = 0; 73135811Smarc if (iflag&PARMRK) 73235811Smarc goto parmrk; 73335811Smarc } 73435811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 73535811Smarc if (iflag&IGNPAR) 73635811Smarc goto endcase; 73735811Smarc else if (iflag&PARMRK) { 73835811Smarc parmrk: 73935811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 74035811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 74135811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 74235811Smarc goto endcase; 74335811Smarc } else 74435811Smarc c = 0; 7457502Sroot } 7469578Ssam } 7479578Ssam /* 74835811Smarc * In tandem mode, check high water mark. 7499578Ssam */ 75035811Smarc if (iflag&IXOFF) 75135811Smarc ttyblock(tp); 75235811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 7539578Ssam c &= 0177; 7549578Ssam /* 7559578Ssam * Check for literal nexting very first 7569578Ssam */ 7579578Ssam if (tp->t_state&TS_LNCH) { 75835811Smarc c |= TTY_QUOTE; 7599578Ssam tp->t_state &= ~TS_LNCH; 7609578Ssam } 7619578Ssam /* 7629578Ssam * Scan for special characters. This code 7639578Ssam * is really just a big case statement with 7649578Ssam * non-constant cases. The bottom of the 7659578Ssam * case statement is labeled ``endcase'', so goto 7669578Ssam * it after a case match, or similar. 7679578Ssam */ 76835811Smarc /* 76935811Smarc * Control chars which aren't controlled 77035811Smarc * by ICANON, ISIG, or IXON. 77135811Smarc */ 77235811Smarc if (iflag&IEXTEN) { 77335811Smarc if (CCEQ(cc[VLNEXT],c)) { 77435811Smarc if (lflag&ECHO) { 77535811Smarc if (lflag&ECHOE) 77635811Smarc ttyout("^\b", tp); 77735811Smarc else 77835811Smarc ttyecho(c, tp); 77935811Smarc } 7809578Ssam tp->t_state |= TS_LNCH; 7819578Ssam goto endcase; 7829578Ssam } 78335811Smarc if (CCEQ(cc[VFLUSHO],c)) { 78435811Smarc if (lflag&FLUSHO) 78535811Smarc tp->t_lflag &= ~FLUSHO; 7867502Sroot else { 78712752Ssam ttyflush(tp, FWRITE); 7887502Sroot ttyecho(c, tp); 7899578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7907502Sroot ttyretype(tp); 79135811Smarc tp->t_lflag |= FLUSHO; 7927502Sroot } 7939578Ssam goto startoutput; 7949578Ssam } 79535811Smarc } 79635811Smarc /* 79735811Smarc * Signals. 79835811Smarc */ 79935811Smarc if (lflag&ISIG) { 80035811Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 80135811Smarc if ((lflag&NOFLSH) == 0) 80235811Smarc ttyflush(tp, FREAD|FWRITE); 80335811Smarc ttyecho(c, tp); 80435811Smarc gsignal(tp->t_pgid, CCEQ(cc[VINTR],c) ? 80535811Smarc SIGINT : SIGQUIT); 80635811Smarc goto endcase; 80735811Smarc } 80835811Smarc if (CCEQ(cc[VSUSP],c)) { 80935811Smarc if ((lflag&NOFLSH) == 0) 81012752Ssam ttyflush(tp, FREAD); 8119578Ssam ttyecho(c, tp); 81235811Smarc gsignal(tp->t_pgid, SIGTSTP); 8139578Ssam goto endcase; 8149578Ssam } 8159578Ssam } 8169578Ssam /* 8179578Ssam * Handle start/stop characters. 8189578Ssam */ 81935811Smarc if (iflag&IXON) { 82035811Smarc if (CCEQ(cc[VSTOP],c)) { 82135811Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 82235811Smarc tp->t_state |= TS_TTSTOP; 82335811Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 82435811Smarc return; 82535811Smarc } 82635811Smarc if (!CCEQ(cc[VSTART], c)) 82735811Smarc return; 82835811Smarc /* 82935811Smarc * if VSTART == VSTOP then toggle 83035811Smarc */ 83135811Smarc goto endcase; 8329578Ssam } 83335811Smarc if (CCEQ(cc[VSTART], c)) 83435811Smarc goto restartoutput; 8359578Ssam } 8369578Ssam /* 83735811Smarc * IGNCR, ICRNL, & INLCR 8389578Ssam */ 83935811Smarc if (c == '\r') { 84035811Smarc if (iflag&IGNCR) 84135811Smarc goto endcase; 84235811Smarc else if (iflag&ICRNL) 84335811Smarc c = '\n'; 8449578Ssam } 84535811Smarc else if (c == '\n' && iflag&INLCR) 84635811Smarc c = '\r'; 8479578Ssam /* 84835811Smarc * Non canonical mode; don't process line editing 8499578Ssam * characters; check high water mark for wakeup. 85035811Smarc * 8519578Ssam */ 85235811Smarc if (!(lflag&ICANON)) { 8539578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 85435811Smarc if (iflag&IMAXBEL) { 85535811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 85635811Smarc (void) ttyoutput(CTRL('g'), tp); 85735811Smarc } else 85835811Smarc ttyflush(tp, FREAD | FWRITE); 85935811Smarc } else { 86035811Smarc if (putc(c, &tp->t_rawq) >= 0) { 86135811Smarc ttwakeup(tp); 86235811Smarc ttyecho(c, tp); 86335811Smarc } 8647502Sroot } 8659578Ssam goto endcase; 8669578Ssam } 8679578Ssam /* 86835811Smarc * From here on down canonical mode character 8699578Ssam * processing takes place. 8709578Ssam */ 87135811Smarc /* 87235811Smarc * erase (^H / ^?) 87335811Smarc */ 87435811Smarc if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c)) { 8759578Ssam if (tp->t_rawq.c_cc) 8769578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8779578Ssam goto endcase; 8789578Ssam } 87935811Smarc /* 88035811Smarc * kill (^U) 88135811Smarc */ 88235811Smarc if (CCEQ(cc[VKILL], c)) { 88337584Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 88437584Smarc !(lflag&ECHOPRT)) { 8859578Ssam while (tp->t_rawq.c_cc) 8869578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8879578Ssam } else { 8889578Ssam ttyecho(c, tp); 88935811Smarc if (lflag&ECHOK || lflag&ECHOKE) 89035811Smarc ttyecho('\n', tp); 8919578Ssam while (getc(&tp->t_rawq) > 0) 8929578Ssam ; 8939578Ssam tp->t_rocount = 0; 8949578Ssam } 8959578Ssam tp->t_state &= ~TS_LOCAL; 8969578Ssam goto endcase; 8979578Ssam } 8989578Ssam /* 89935811Smarc * word erase (^W) 9009578Ssam */ 90135811Smarc if (CCEQ(cc[VWERASE], c)) { 90235811Smarc int ctype; 90335811Smarc 90435811Smarc #define CTYPE(c) ((lflag&ALTWERASE) ? (partab[(c)&TTY_CHARMASK]&0100) : 0) 90535811Smarc /* 90635811Smarc * erase whitespace 90735811Smarc */ 90835811Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 90935811Smarc ttyrub(c, tp); 91035811Smarc if (c == -1) 91134492Skarels goto endcase; 91235811Smarc /* 91335811Smarc * special case last char of token 91435811Smarc */ 91535811Smarc ttyrub(c, tp); 91635811Smarc c = unputc(&tp->t_rawq); 91735811Smarc if (c == -1 || c == ' ' || c == '\t') { 91835811Smarc if (c != -1) 91935811Smarc (void) putc(c, &tp->t_rawq); 92034492Skarels goto endcase; 92134492Skarels } 92235811Smarc /* 92335811Smarc * erase rest of token 92435811Smarc */ 92535811Smarc ctype = CTYPE(c); 92635811Smarc do { 92735811Smarc ttyrub(c, tp); 92835811Smarc c = unputc(&tp->t_rawq); 92935811Smarc if (c == -1) 93035811Smarc goto endcase; 93135811Smarc } while (c != ' ' && c != '\t' && CTYPE(c) == ctype); 93235811Smarc (void) putc(c, &tp->t_rawq); 93335811Smarc goto endcase; 93435811Smarc #undef CTYPE 9359578Ssam } 9369578Ssam /* 93735811Smarc * reprint line (^R) 93835811Smarc */ 93935811Smarc if (CCEQ(cc[VREPRINT], c)) { 94035811Smarc ttyretype(tp); 94135811Smarc goto endcase; 94235811Smarc } 94335811Smarc /* 9449578Ssam * Check for input buffer overflow 9459578Ssam */ 94610391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 94735811Smarc if (iflag&IMAXBEL) { 94835811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 94935811Smarc (void) ttyoutput(CTRL('g'), tp); 95035811Smarc } else 95135811Smarc ttyflush(tp, FREAD | FWRITE); 9529578Ssam goto endcase; 95310391Ssam } 9549578Ssam /* 9559578Ssam * Put data char in q for user and 9569578Ssam * wakeup on seeing a line delimiter. 9579578Ssam */ 9589578Ssam if (putc(c, &tp->t_rawq) >= 0) { 95935811Smarc if (ttbreakc(c)) { 9609578Ssam tp->t_rocount = 0; 9619578Ssam catq(&tp->t_rawq, &tp->t_canq); 9627502Sroot ttwakeup(tp); 9639578Ssam } else if (tp->t_rocount++ == 0) 9649578Ssam tp->t_rocol = tp->t_col; 9659578Ssam if (tp->t_state&TS_ERASE) { 96635811Smarc /* 96735811Smarc * end of prterase \.../ 96835811Smarc */ 9699578Ssam tp->t_state &= ~TS_ERASE; 9709578Ssam (void) ttyoutput('/', tp); 9719578Ssam } 9729578Ssam i = tp->t_col; 9737502Sroot ttyecho(c, tp); 97435811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 97535811Smarc /* 97635811Smarc * Place the cursor over the '^' of the ^D. 97735811Smarc */ 9789578Ssam i = MIN(2, tp->t_col - i); 9799578Ssam while (i > 0) { 9809578Ssam (void) ttyoutput('\b', tp); 9819578Ssam i--; 9829578Ssam } 9839578Ssam } 9847502Sroot } 9859578Ssam endcase: 9869578Ssam /* 98735811Smarc * IXANY means allow any character to restart output. 9889578Ssam */ 98935811Smarc if ((tp->t_state&TS_TTSTOP) && !(iflag&IXANY) 99035811Smarc && cc[VSTART] != cc[VSTOP]) 9917502Sroot return; 9929578Ssam restartoutput: 9937502Sroot tp->t_state &= ~TS_TTSTOP; 99435811Smarc tp->t_lflag &= ~FLUSHO; 9959578Ssam startoutput: 9967502Sroot ttstart(tp); 9977502Sroot } 9987502Sroot 9997502Sroot /* 10009578Ssam * Put character on TTY output queue, adding delays, 10017502Sroot * expanding tabs, and handling the CR/NL bit. 10029578Ssam * This is called both from the top half for output, 10039578Ssam * and from interrupt level for echoing. 10047502Sroot * The arguments are the character and the tty structure. 10057502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 10067502Sroot * Must be recursive. 10077502Sroot */ 10087502Sroot ttyoutput(c, tp) 10097502Sroot register c; 10107502Sroot register struct tty *tp; 10117502Sroot { 10127502Sroot register char *colp; 10137502Sroot register ctype; 101435811Smarc register long oflag = tp->t_oflag; 101535811Smarc 101635811Smarc if (!(oflag&OPOST)) { 101735811Smarc if (tp->t_lflag&FLUSHO) 10187502Sroot return (-1); 10197502Sroot if (putc(c, &tp->t_outq)) 10207625Ssam return (c); 10217502Sroot tk_nout++; 102235811Smarc tp->t_outcc++; 10237502Sroot return (-1); 10247502Sroot } 102535811Smarc c &= TTY_CHARMASK; 10267502Sroot /* 10277502Sroot * Turn tabs to spaces as required 10287502Sroot */ 102935811Smarc if (c == '\t' && oflag&OXTABS ) { 10307502Sroot register int s; 10317502Sroot 10327502Sroot c = 8 - (tp->t_col&7); 103335811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 103417545Skarels s = spltty(); /* don't interrupt tabs */ 10357502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10367502Sroot tk_nout += c; 103735811Smarc tp->t_outcc += c; 10387502Sroot splx(s); 10397502Sroot } 10407502Sroot tp->t_col += c; 10417502Sroot return (c ? -1 : '\t'); 10427502Sroot } 104335811Smarc if (c == CEOT && oflag&ONOEOT) 104435811Smarc return(-1); 10457502Sroot tk_nout++; 104635811Smarc tp->t_outcc++; 10477502Sroot /* 10487502Sroot * turn <nl> to <cr><lf> if desired. 10497502Sroot */ 105035811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 10517502Sroot return (c); 105235811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 105335811Smarc return (c); 10547502Sroot /* 10557502Sroot * Calculate delays. 10567502Sroot * The numbers here represent clock ticks 10577502Sroot * and are not necessarily optimal for all terminals. 10589578Ssam * 10599578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 106035811Smarc * 106135811Smarc * (actually, should THROW AWAY terminals which need delays) 10627502Sroot */ 10637502Sroot colp = &tp->t_col; 10647502Sroot ctype = partab[c]; 10657502Sroot c = 0; 10667502Sroot switch (ctype&077) { 10677502Sroot 10687502Sroot case ORDINARY: 10697502Sroot (*colp)++; 10707502Sroot 10717502Sroot case CONTROL: 10727502Sroot break; 10737502Sroot 10747502Sroot case BACKSPACE: 10757502Sroot if (*colp) 10767502Sroot (*colp)--; 10777502Sroot break; 10787502Sroot 107913821Ssam /* 108013821Ssam * This macro is close enough to the correct thing; 108113821Ssam * it should be replaced by real user settable delays 108213821Ssam * in any event... 108313821Ssam */ 108413821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10857502Sroot case NEWLINE: 10867502Sroot ctype = (tp->t_flags >> 8) & 03; 10877625Ssam if (ctype == 1) { /* tty 37 */ 108826357Skarels if (*colp > 0) { 108926357Skarels c = (((unsigned)*colp) >> 4) + 3; 109026357Skarels if ((unsigned)c > 6) 109126357Skarels c = 6; 109226357Skarels } 10939578Ssam } else if (ctype == 2) /* vt05 */ 109413821Ssam c = mstohz(100); 10957502Sroot *colp = 0; 10967502Sroot break; 10977502Sroot 10987502Sroot case TAB: 10997502Sroot ctype = (tp->t_flags >> 10) & 03; 11007625Ssam if (ctype == 1) { /* tty 37 */ 11017502Sroot c = 1 - (*colp | ~07); 11027625Ssam if (c < 5) 11037502Sroot c = 0; 11047502Sroot } 11057502Sroot *colp |= 07; 11067502Sroot (*colp)++; 11077502Sroot break; 11087502Sroot 11097502Sroot case VTAB: 11109578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 11117502Sroot c = 0177; 11127502Sroot break; 11137502Sroot 11147502Sroot case RETURN: 11157502Sroot ctype = (tp->t_flags >> 12) & 03; 11169578Ssam if (ctype == 1) /* tn 300 */ 111713821Ssam c = mstohz(83); 11189578Ssam else if (ctype == 2) /* ti 700 */ 111913821Ssam c = mstohz(166); 11209578Ssam else if (ctype == 3) { /* concept 100 */ 11217502Sroot int i; 11229578Ssam 11237502Sroot if ((i = *colp) >= 0) 11249578Ssam for (; i < 9; i++) 11257502Sroot (void) putc(0177, &tp->t_outq); 11267502Sroot } 11277502Sroot *colp = 0; 11287502Sroot } 112935811Smarc if (c && (tp->t_lflag&FLUSHO) == 0) 113035811Smarc (void) putc(c|TTY_QUOTE, &tp->t_outq); 11317502Sroot return (-1); 11327502Sroot } 113313821Ssam #undef mstohz 11347502Sroot 11357502Sroot /* 11367502Sroot * Called from device's read routine after it has 11377502Sroot * calculated the tty-structure given as argument. 11387502Sroot */ 113937584Smarc ttread(tp, uio, flag) 11407625Ssam register struct tty *tp; 11417722Swnj struct uio *uio; 11427502Sroot { 11437502Sroot register struct clist *qp; 114435811Smarc register int c; 114535811Smarc register long lflag = tp->t_lflag; 114635811Smarc register u_char *cc = tp->t_cc; 11479859Ssam int s, first, error = 0; 11487502Sroot 11497502Sroot loop: 115037584Smarc s = spltty(); 11519578Ssam /* 115237584Smarc * take pending input first 11539578Ssam */ 115435811Smarc if (lflag&PENDIN) 11557502Sroot ttypend(tp); 115637584Smarc /* 115737584Smarc * Handle carrier. 115837584Smarc */ 115937584Smarc if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) { 116037584Smarc if (tp->t_state&TS_ISOPEN) { 116137584Smarc splx(s); 116237584Smarc return (0); /* EOF */ 1163*37728Smckusick } else if (flag & IO_NDELAY) { 116437584Smarc splx(s); 116537584Smarc return (EWOULDBLOCK); 116637584Smarc } else { 116737584Smarc /* 116837584Smarc * sleep awaiting carrier 116937584Smarc */ 117037584Smarc sleep((caddr_t)&tp->t_rawq, TTIPRI); 117137584Smarc splx(s); 117237584Smarc goto loop; 117337584Smarc } 117437584Smarc } 11759859Ssam splx(s); 11769578Ssam /* 11779578Ssam * Hang process if it's in the background. 11789578Ssam */ 117935811Smarc if (u.u_ttyp == tp && u.u_procp->p_pgid != tp->t_pgid) { 118024392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 118124392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 118235811Smarc u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0) 11838520Sroot return (EIO); 118435811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTIN); 11857502Sroot sleep((caddr_t)&lbolt, TTIPRI); 118623165Sbloom goto loop; 11877502Sroot } 11889578Ssam /* 118935811Smarc * If canonical, use the canonical queue, 119035811Smarc * else use the raw queue. 119137584Smarc * 119237584Smarc * XXX - should get rid of canonical queue. 119337584Smarc * (actually, should get rid of clists...) 11949578Ssam */ 119535811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 11969578Ssam /* 11979578Ssam * No input, sleep on rawq awaiting hardware 11989578Ssam * receipt and notification. 11999578Ssam */ 120017545Skarels s = spltty(); 12019578Ssam if (qp->c_cc <= 0) { 120237584Smarc /** XXX ??? ask mike why TS_CARR_ON was (once) necessary here 12039578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 12049578Ssam (tp->t_state&TS_NBIO)) { 12059859Ssam splx(s); 12069578Ssam return (EWOULDBLOCK); 12077502Sroot } 120837584Smarc **/ 1209*37728Smckusick if (flag & IO_NDELAY) { 121037584Smarc splx(s); 121137584Smarc return (EWOULDBLOCK); 121237584Smarc } 12139578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 12149859Ssam splx(s); 12159578Ssam goto loop; 12169578Ssam } 12179859Ssam splx(s); 12189578Ssam /* 121935811Smarc * Input present, check for input mapping and processing. 12209578Ssam */ 12219578Ssam first = 1; 12229578Ssam while ((c = getc(qp)) >= 0) { 12239578Ssam /* 122435811Smarc * delayed suspend (^Y) 12259578Ssam */ 122635811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 122735811Smarc gsignal(tp->t_pgid, SIGTSTP); 12289578Ssam if (first) { 12299578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12309578Ssam goto loop; 12319578Ssam } 12329578Ssam break; 12337502Sroot } 12349578Ssam /* 123535811Smarc * Interpret EOF only in canonical mode. 12369578Ssam */ 123735811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12389578Ssam break; 12399578Ssam /* 12409578Ssam * Give user character. 12419578Ssam */ 124235811Smarc error = ureadc(c , uio); 12439578Ssam if (error) 12449578Ssam break; 124514938Smckusick if (uio->uio_resid == 0) 12469578Ssam break; 12479578Ssam /* 124835811Smarc * In canonical mode check for a "break character" 12499578Ssam * marking the end of a "line of input". 12509578Ssam */ 125135811Smarc if (lflag&ICANON && ttbreakc(c)) { 12529578Ssam break; 125335811Smarc } 12549578Ssam first = 0; 12557502Sroot } 12569578Ssam /* 12579578Ssam * Look to unblock output now that (presumably) 12589578Ssam * the input queue has gone down. 12599578Ssam */ 126035811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 126135811Smarc if (cc[VSTART] != _POSIX_VDISABLE 126235811Smarc && putc(cc[VSTART], &tp->t_outq) == 0) { 12637502Sroot tp->t_state &= ~TS_TBLOCK; 12647502Sroot ttstart(tp); 12657502Sroot } 126635811Smarc } 12678520Sroot return (error); 12687502Sroot } 12697502Sroot 12707502Sroot /* 127125391Skarels * Check the output queue on tp for space for a kernel message 127225391Skarels * (from uprintf/tprintf). Allow some space over the normal 127325391Skarels * hiwater mark so we don't lose messages due to normal flow 127425391Skarels * control, but don't let the tty run amok. 127530695Skarels * Sleeps here are not interruptible, but we return prematurely 127630695Skarels * if new signals come in. 127725391Skarels */ 127825391Skarels ttycheckoutq(tp, wait) 127925391Skarels register struct tty *tp; 128025391Skarels int wait; 128125391Skarels { 128230695Skarels int hiwat, s, oldsig; 128325391Skarels 128435811Smarc hiwat = tp->t_hiwat; 128525391Skarels s = spltty(); 128630695Skarels oldsig = u.u_procp->p_sig; 128725391Skarels if (tp->t_outq.c_cc > hiwat + 200) 128829946Skarels while (tp->t_outq.c_cc > hiwat) { 128929946Skarels ttstart(tp); 129030695Skarels if (wait == 0 || u.u_procp->p_sig != oldsig) { 129129946Skarels splx(s); 129229946Skarels return (0); 129329946Skarels } 129430695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 129529946Skarels tp->t_state |= TS_ASLEEP; 129630695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 129725391Skarels } 129825391Skarels splx(s); 129925391Skarels return (1); 130025391Skarels } 130125391Skarels 130225391Skarels /* 13037502Sroot * Called from the device's write routine after it has 13047502Sroot * calculated the tty-structure given as argument. 13057502Sroot */ 130637584Smarc ttwrite(tp, uio, flag) 13077625Ssam register struct tty *tp; 13089578Ssam register struct uio *uio; 13097502Sroot { 13107502Sroot register char *cp; 1311*37728Smckusick register int cc, ce; 13129578Ssam int i, hiwat, cnt, error, s; 13137502Sroot char obuf[OBUFSIZ]; 13147502Sroot 131535811Smarc hiwat = tp->t_hiwat; 13169578Ssam cnt = uio->uio_resid; 13179578Ssam error = 0; 13187502Sroot loop: 131937584Smarc s = spltty(); 132037584Smarc if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) { 132137584Smarc if (tp->t_state&TS_ISOPEN) { 132237584Smarc splx(s); 132337584Smarc return (EIO); 1324*37728Smckusick } else if (flag & IO_NDELAY) { 132537584Smarc splx(s); 132637584Smarc return (EWOULDBLOCK); 132737584Smarc } else { 132837584Smarc /* 132937584Smarc * sleep awaiting carrier 133037584Smarc */ 133137584Smarc sleep((caddr_t)&tp->t_rawq, TTIPRI); 133237584Smarc splx(s); 133337584Smarc goto loop; 133437584Smarc } 133537584Smarc } 133637584Smarc splx(s); 13379578Ssam /* 13389578Ssam * Hang the process if it's in the background. 13399578Ssam */ 134035811Smarc if (u.u_ttyp == tp && 134135811Smarc u.u_procp->p_pgid != tp->t_pgid && 134235811Smarc (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 134324392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 134435811Smarc !(u.u_procp->p_sigmask & sigmask(SIGTTOU)) && 134535811Smarc u.u_procp->p_pgrp->pg_jobc) { 134635811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU); 13477502Sroot sleep((caddr_t)&lbolt, TTIPRI); 134821776Sbloom goto loop; 13497502Sroot } 13509578Ssam /* 13519578Ssam * Process the user's data in at most OBUFSIZ 13529578Ssam * chunks. Perform lower case simulation and 13539578Ssam * similar hacks. Keep track of high water 13549578Ssam * mark, sleep on overflow awaiting device aid 13559578Ssam * in acquiring new space. 13569578Ssam */ 13577822Sroot while (uio->uio_resid > 0) { 135832067Skarels if (tp->t_outq.c_cc > hiwat) { 135932067Skarels cc = 0; 136032067Skarels goto ovhiwat; 136132067Skarels } 13629578Ssam /* 13639578Ssam * Grab a hunk of data from the user. 13649578Ssam */ 13657822Sroot cc = uio->uio_iov->iov_len; 13667822Sroot if (cc == 0) { 13677822Sroot uio->uio_iovcnt--; 13687822Sroot uio->uio_iov++; 136921776Sbloom if (uio->uio_iovcnt <= 0) 13707822Sroot panic("ttwrite"); 13717822Sroot continue; 13727822Sroot } 13737822Sroot if (cc > OBUFSIZ) 13747822Sroot cc = OBUFSIZ; 13757502Sroot cp = obuf; 1376*37728Smckusick error = uiomove(cp, cc, uio); 13778520Sroot if (error) 13787502Sroot break; 137935811Smarc if (tp->t_lflag&FLUSHO) 13807502Sroot continue; 13819578Ssam /* 13829578Ssam * If nothing fancy need be done, grab those characters we 13839578Ssam * can handle without any of ttyoutput's processing and 13849578Ssam * just transfer them to the output q. For those chars 13859578Ssam * which require special processing (as indicated by the 13869578Ssam * bits in partab), call ttyoutput. After processing 13879578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13889578Ssam * immediately. 13899578Ssam */ 13909578Ssam while (cc > 0) { 139135811Smarc if (!(tp->t_oflag&OPOST)) 13927502Sroot ce = cc; 13937502Sroot else { 139434492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 139534492Skarels (u_char *)partab, 077); 13969578Ssam /* 13979578Ssam * If ce is zero, then we're processing 13989578Ssam * a special character through ttyoutput. 13999578Ssam */ 14009578Ssam if (ce == 0) { 14017502Sroot tp->t_rocount = 0; 14027502Sroot if (ttyoutput(*cp, tp) >= 0) { 140321776Sbloom /* no c-lists, wait a bit */ 140421776Sbloom ttstart(tp); 140521776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 140621776Sbloom if (cc != 0) { 140721776Sbloom uio->uio_iov->iov_base -= cc; 140821776Sbloom uio->uio_iov->iov_len += cc; 140921776Sbloom uio->uio_resid += cc; 141021776Sbloom uio->uio_offset -= cc; 141121776Sbloom } 141221776Sbloom goto loop; 14137502Sroot } 14149578Ssam cp++, cc--; 141535811Smarc if ((tp->t_lflag&FLUSHO) || 14169578Ssam tp->t_outq.c_cc > hiwat) 14177502Sroot goto ovhiwat; 14189578Ssam continue; 14197502Sroot } 14207502Sroot } 14219578Ssam /* 14229578Ssam * A bunch of normal characters have been found, 14239578Ssam * transfer them en masse to the output queue and 14249578Ssam * continue processing at the top of the loop. 14259578Ssam * If there are any further characters in this 14269578Ssam * <= OBUFSIZ chunk, the first should be a character 14279578Ssam * requiring special handling by ttyoutput. 14289578Ssam */ 14297502Sroot tp->t_rocount = 0; 14309578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14319578Ssam ce -= i; 14329578Ssam tp->t_col += ce; 14339578Ssam cp += ce, cc -= ce, tk_nout += ce; 143435811Smarc tp->t_outcc += ce; 14359578Ssam if (i > 0) { 14369578Ssam /* out of c-lists, wait a bit */ 14377502Sroot ttstart(tp); 14387502Sroot sleep((caddr_t)&lbolt, TTOPRI); 143921776Sbloom uio->uio_iov->iov_base -= cc; 144021776Sbloom uio->uio_iov->iov_len += cc; 144121776Sbloom uio->uio_resid += cc; 144221776Sbloom uio->uio_offset -= cc; 144321776Sbloom goto loop; 14447502Sroot } 144535811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 14467502Sroot goto ovhiwat; 14477502Sroot } 144835811Smarc ttstart(tp); 14497502Sroot } 14508520Sroot return (error); 14517502Sroot ovhiwat: 14529578Ssam if (cc != 0) { 14539578Ssam uio->uio_iov->iov_base -= cc; 14549578Ssam uio->uio_iov->iov_len += cc; 14559578Ssam uio->uio_resid += cc; 14569578Ssam uio->uio_offset -= cc; 14579578Ssam } 145832067Skarels ttstart(tp); 145932067Skarels s = spltty(); 14609578Ssam /* 146135811Smarc * This can only occur if FLUSHO is set in t_lflag, 146232067Skarels * or if ttstart/oproc is synchronous (or very fast). 14639578Ssam */ 14647502Sroot if (tp->t_outq.c_cc <= hiwat) { 14659578Ssam splx(s); 14667502Sroot goto loop; 14677502Sroot } 1468*37728Smckusick if (flag & IO_NDELAY) { 146917545Skarels splx(s); 14707822Sroot if (uio->uio_resid == cnt) 14718520Sroot return (EWOULDBLOCK); 14728520Sroot return (0); 14737502Sroot } 14747502Sroot tp->t_state |= TS_ASLEEP; 14757502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14769578Ssam splx(s); 14777502Sroot goto loop; 14787502Sroot } 14797502Sroot 14807502Sroot /* 14817502Sroot * Rubout one character from the rawq of tp 14827502Sroot * as cleanly as possible. 14837502Sroot */ 14847502Sroot ttyrub(c, tp) 14857625Ssam register c; 14867625Ssam register struct tty *tp; 14877502Sroot { 14887502Sroot register char *cp; 14897502Sroot register int savecol; 14907502Sroot int s; 14917502Sroot char *nextc(); 14927502Sroot 149335811Smarc if ((tp->t_lflag&ECHO) == 0) 14947502Sroot return; 149535811Smarc tp->t_lflag &= ~FLUSHO; 149635811Smarc if (tp->t_lflag&ECHOE) { 14977502Sroot if (tp->t_rocount == 0) { 14987502Sroot /* 14997502Sroot * Screwed by ttwrite; retype 15007502Sroot */ 15017502Sroot ttyretype(tp); 15027502Sroot return; 15037502Sroot } 150435811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 15057502Sroot ttyrubo(tp, 2); 150635811Smarc else switch (partab[c&=0377]&077) { 15077502Sroot 15087502Sroot case ORDINARY: 150935811Smarc ttyrubo(tp, 1); 15107502Sroot break; 15117502Sroot 15127502Sroot case VTAB: 15137502Sroot case BACKSPACE: 15147502Sroot case CONTROL: 15157502Sroot case RETURN: 151635811Smarc if (tp->t_lflag&ECHOCTL) 15177502Sroot ttyrubo(tp, 2); 15187502Sroot break; 15197502Sroot 152035811Smarc case TAB: { 152135811Smarc int c; 152235811Smarc 15237502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15247502Sroot ttyretype(tp); 15257502Sroot return; 15267502Sroot } 152717545Skarels s = spltty(); 15287502Sroot savecol = tp->t_col; 15299578Ssam tp->t_state |= TS_CNTTB; 153035811Smarc tp->t_lflag |= FLUSHO; 15317502Sroot tp->t_col = tp->t_rocol; 15329578Ssam cp = tp->t_rawq.c_cf; 153335811Smarc c = *cp; /* XXX FIX NEXTC */ 153435811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 153535811Smarc ttyecho(c, tp); 153635811Smarc tp->t_lflag &= ~FLUSHO; 15379578Ssam tp->t_state &= ~TS_CNTTB; 15387502Sroot splx(s); 15397502Sroot /* 15407502Sroot * savecol will now be length of the tab 15417502Sroot */ 15427502Sroot savecol -= tp->t_col; 15437502Sroot tp->t_col += savecol; 15447502Sroot if (savecol > 8) 15457502Sroot savecol = 8; /* overflow screw */ 15467502Sroot while (--savecol >= 0) 15477502Sroot (void) ttyoutput('\b', tp); 15487502Sroot break; 154935811Smarc } 15507502Sroot 15517502Sroot default: 155237584Smarc /* XXX */ 155335811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 155435811Smarc c, partab[c&=0377]&077); 155535811Smarc /*panic("ttyrub");*/ 15567502Sroot } 155735811Smarc } else if (tp->t_lflag&ECHOPRT) { 15589578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15597502Sroot (void) ttyoutput('\\', tp); 15609578Ssam tp->t_state |= TS_ERASE; 15617502Sroot } 15627502Sroot ttyecho(c, tp); 15637502Sroot } else 156435811Smarc ttyecho(tp->t_cc[VERASE], tp); 15657502Sroot tp->t_rocount--; 15667502Sroot } 15677502Sroot 15687502Sroot /* 15697502Sroot * Crt back over cnt chars perhaps 15707502Sroot * erasing them. 15717502Sroot */ 15727502Sroot ttyrubo(tp, cnt) 15737625Ssam register struct tty *tp; 15747625Ssam int cnt; 15757502Sroot { 15767502Sroot 15777502Sroot while (--cnt >= 0) 157835811Smarc ttyout("\b \b", tp); 15797502Sroot } 15807502Sroot 15817502Sroot /* 15827502Sroot * Reprint the rawq line. 15837502Sroot * We assume c_cc has already been checked. 15847502Sroot */ 15857502Sroot ttyretype(tp) 15867625Ssam register struct tty *tp; 15877502Sroot { 15887502Sroot register char *cp; 15897502Sroot char *nextc(); 159035811Smarc int s, c; 15917502Sroot 159235811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 159335811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 15947502Sroot (void) ttyoutput('\n', tp); 159517545Skarels s = spltty(); 159635811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 159735811Smarc BIT OF FIRST CHAR ****/ 159835811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 159935811Smarc ttyecho(c, tp); 160035811Smarc } 160135811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 160235811Smarc ttyecho(c, tp); 160335811Smarc } 16049578Ssam tp->t_state &= ~TS_ERASE; 16057502Sroot splx(s); 16067502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16077502Sroot tp->t_rocol = 0; 16087502Sroot } 16097502Sroot 16107502Sroot /* 161135811Smarc * Echo a typed character to the terminal. 16127502Sroot */ 16137502Sroot ttyecho(c, tp) 16147625Ssam register c; 16157625Ssam register struct tty *tp; 16167502Sroot { 16179578Ssam if ((tp->t_state&TS_CNTTB) == 0) 161835811Smarc tp->t_lflag &= ~FLUSHO; 161935811Smarc if ((tp->t_lflag&ECHO) == 0 && !(tp->t_lflag&ECHONL && c == '\n')) 16207502Sroot return; 162135811Smarc if (tp->t_lflag&ECHOCTL) { 162235811Smarc if ((c&TTY_CHARMASK)<=037 && c!='\t' && c!='\n' || c==0177) { 16237502Sroot (void) ttyoutput('^', tp); 162435811Smarc c &= TTY_CHARMASK; 16257502Sroot if (c == 0177) 16267502Sroot c = '?'; 16277502Sroot else 16287502Sroot c += 'A' - 1; 16297502Sroot } 16307502Sroot } 163135811Smarc (void) ttyoutput(c, tp); 16327502Sroot } 16337502Sroot 16347502Sroot /* 16357502Sroot * send string cp to tp 16367502Sroot */ 16377502Sroot ttyout(cp, tp) 16387625Ssam register char *cp; 16397625Ssam register struct tty *tp; 16407502Sroot { 16417502Sroot register char c; 16427502Sroot 16437502Sroot while (c = *cp++) 16447502Sroot (void) ttyoutput(c, tp); 16457502Sroot } 16467502Sroot 16477502Sroot ttwakeup(tp) 16487502Sroot struct tty *tp; 16497502Sroot { 16507502Sroot 16517502Sroot if (tp->t_rsel) { 16527502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16537502Sroot tp->t_state &= ~TS_RCOLL; 16547502Sroot tp->t_rsel = 0; 16557502Sroot } 165612752Ssam if (tp->t_state & TS_ASYNC) 165735811Smarc gsignal(tp->t_pgid, SIGIO); 16587502Sroot wakeup((caddr_t)&tp->t_rawq); 16597502Sroot } 166035811Smarc 166135811Smarc /* 166235811Smarc * set tty hi and low water marks 166335811Smarc * 166435811Smarc * Try to arrange the dynamics so there's about one second 166535811Smarc * from hi to low water. 166635811Smarc * 166735811Smarc */ 166835811Smarc ttsetwater(tp) 166935811Smarc struct tty *tp; 167035811Smarc { 167135811Smarc register cps = tp->t_ospeed / 10; 167235811Smarc register x; 167335811Smarc 167435811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 167535811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 167635811Smarc x += cps; 167735811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 167835811Smarc tp->t_hiwat = roundup(x, CBSIZE); 167935811Smarc #undef clamp 168035811Smarc } 168135811Smarc 168235811Smarc ttspeedtab(speed, table) 168335811Smarc struct speedtab table[]; 168435811Smarc { 168535811Smarc register int i; 168635811Smarc 168735811Smarc for (i = 0; table[i].sp_speed != -1; i++) 168835811Smarc if (table[i].sp_speed == speed) 168935811Smarc return(table[i].sp_code); 169035811Smarc return(-1); 169135811Smarc } 1692