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*37554Smckusick * @(#)tty.c 7.15 (Berkeley) 04/26/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) 955408Swnj register 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 { 10817545Skarels register int s = spltty(); 10912752Ssam 11013809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 11132336Smckusick tp->t_state&TS_CARR_ON && tp->t_oproc) { 112903Sbill (*tp->t_oproc)(tp); 1135408Swnj tp->t_state |= TS_ASLEEP; 114903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 115903Sbill } 1169859Ssam splx(s); 11739Sbill } 11839Sbill 11939Sbill /* 1209578Ssam * Flush all TTY queues 12139Sbill */ 12212752Ssam ttyflush(tp, rw) 1237625Ssam register struct tty *tp; 12439Sbill { 125903Sbill register s; 126903Sbill 12717545Skarels s = spltty(); 128903Sbill if (rw & FREAD) { 129903Sbill while (getc(&tp->t_canq) >= 0) 130903Sbill ; 131903Sbill wakeup((caddr_t)&tp->t_rawq); 132903Sbill } 133903Sbill if (rw & FWRITE) { 134903Sbill wakeup((caddr_t)&tp->t_outq); 1355408Swnj tp->t_state &= ~TS_TTSTOP; 1365426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 137903Sbill while (getc(&tp->t_outq) >= 0) 138903Sbill ; 139903Sbill } 140903Sbill if (rw & FREAD) { 141903Sbill while (getc(&tp->t_rawq) >= 0) 142903Sbill ; 1439578Ssam tp->t_rocount = 0; 144903Sbill tp->t_rocol = 0; 1459578Ssam tp->t_state &= ~TS_LOCAL; 146903Sbill } 147903Sbill splx(s); 14839Sbill } 14939Sbill 150903Sbill /* 151903Sbill * Send stop character on input overflow. 152903Sbill */ 153903Sbill ttyblock(tp) 1547625Ssam register struct tty *tp; 15539Sbill { 156903Sbill register x; 1579578Ssam 158903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 159903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 16012752Ssam ttyflush(tp, FREAD|FWRITE); 1615408Swnj tp->t_state &= ~TS_TBLOCK; 162903Sbill } 16315118Skarels /* 16415118Skarels * Block further input iff: 16515118Skarels * Current input > threshold AND input is available to user program 16615118Skarels */ 16716055Skarels if (x >= TTYHOG/2 && 16835811Smarc (!(tp->t_lflag&ICANON)) || (tp->t_canq.c_cc > 0) && 16935811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 17035811Smarc if (putc(tp->t_cc[VSTOP], &tp->t_outq)==0) { 17115118Skarels tp->t_state |= TS_TBLOCK; 17215118Skarels ttstart(tp); 17315118Skarels } 174903Sbill } 17539Sbill } 17639Sbill 17739Sbill /* 178903Sbill * Restart typewriter output following a delay 179903Sbill * timeout. 180903Sbill * The name of the routine is passed to the timeout 181903Sbill * subroutine and it is called during a clock interrupt. 182121Sbill */ 183903Sbill ttrstrt(tp) 1847625Ssam register struct tty *tp; 185121Sbill { 186121Sbill 1879578Ssam if (tp == 0) 1889578Ssam panic("ttrstrt"); 1895408Swnj tp->t_state &= ~TS_TIMEOUT; 190903Sbill ttstart(tp); 191121Sbill } 192121Sbill 193121Sbill /* 194903Sbill * Start output on the typewriter. It is used from the top half 195903Sbill * after some characters have been put on the output queue, 196903Sbill * from the interrupt routine to transmit the next 197903Sbill * character, and after a timeout has finished. 19839Sbill */ 199903Sbill ttstart(tp) 2007625Ssam register struct tty *tp; 20139Sbill { 20239Sbill 20332067Skarels if (tp->t_oproc) /* kludge for pty */ 204903Sbill (*tp->t_oproc)(tp); 20539Sbill } 20639Sbill 20739Sbill /* 208903Sbill * Common code for tty ioctls. 20939Sbill */ 2101780Sbill /*ARGSUSED*/ 2117625Ssam ttioctl(tp, com, data, flag) 2127625Ssam register struct tty *tp; 2137625Ssam caddr_t data; 21439Sbill { 21539Sbill extern int nldisp; 21635811Smarc int softset = 0; 217*37554Smckusick int s, error; 21839Sbill 21930534Skarels 220903Sbill /* 221903Sbill * If the ioctl involves modification, 22217545Skarels * hang if in the background. 223903Sbill */ 2247625Ssam switch (com) { 22539Sbill 22635811Smarc case TIOCSETD: 227903Sbill case TIOCFLUSH: 22835811Smarc /*case TIOCSPGRP:*/ 2299325Ssam case TIOCSTI: 23017598Sbloom case TIOCSWINSZ: 23135811Smarc case TIOCSETA: 23235811Smarc case TIOCSETAW: 23335811Smarc case TIOCSETAF: 23435811Smarc case TIOCSETAS: 23535811Smarc case TIOCSETAWS: 23635811Smarc case TIOCSETAFS: 23735811Smarc while (u.u_procp->p_pgid != tp->t_pgid && 23835811Smarc tp == u.u_ttyp && 23935811Smarc u.u_procp->p_pgrp->pg_jobc && 240903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 24124392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 24224392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 24335811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU); 244903Sbill sleep((caddr_t)&lbolt, TTOPRI); 245903Sbill } 246903Sbill break; 247903Sbill } 248903Sbill 2499578Ssam /* 2509578Ssam * Process the ioctl. 2519578Ssam */ 2527625Ssam switch (com) { 253903Sbill 2548556Sroot /* get discipline number */ 25539Sbill case TIOCGETD: 2567625Ssam *(int *)data = tp->t_line; 25739Sbill break; 25839Sbill 2598556Sroot /* set line discipline */ 2607625Ssam case TIOCSETD: { 2617625Ssam register int t = *(int *)data; 26235811Smarc dev_t dev = tp->t_dev; 2639578Ssam int error = 0; 2647625Ssam 26535811Smarc if ((unsigned)t >= nldisp) 26610851Ssam return (ENXIO); 26725584Skarels if (t != tp->t_line) { 26825584Skarels s = spltty(); 26925584Skarels (*linesw[tp->t_line].l_close)(tp); 27025584Skarels error = (*linesw[t].l_open)(dev, tp); 27125584Skarels if (error) { 27235811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 27325584Skarels splx(s); 27425584Skarels return (error); 27525584Skarels } 27625584Skarels tp->t_line = t; 27710851Ssam splx(s); 27810851Ssam } 27939Sbill break; 2807625Ssam } 28139Sbill 2828556Sroot /* prevent more opens on channel */ 2835614Swnj case TIOCEXCL: 2845614Swnj tp->t_state |= TS_XCLUDE; 2855614Swnj break; 2865614Swnj 2875614Swnj case TIOCNXCL: 2885614Swnj tp->t_state &= ~TS_XCLUDE; 2895614Swnj break; 2905614Swnj 29139Sbill case TIOCHPCL: 29235811Smarc tp->t_cflag |= HUPCL; 29339Sbill break; 29439Sbill 2953942Sbugs case TIOCFLUSH: { 2967625Ssam register int flags = *(int *)data; 2977625Ssam 2987625Ssam if (flags == 0) 2993942Sbugs flags = FREAD|FWRITE; 3007625Ssam else 3017625Ssam flags &= FREAD|FWRITE; 30212752Ssam ttyflush(tp, flags); 30339Sbill break; 3043944Sbugs } 30539Sbill 3068556Sroot /* return number of characters immediately available */ 3077625Ssam case FIONREAD: 3087625Ssam *(off_t *)data = ttnread(tp); 309174Sbill break; 310174Sbill 31113077Ssam case TIOCOUTQ: 31213077Ssam *(int *)data = tp->t_outq.c_cc; 31313077Ssam break; 31413077Ssam 3158589Sroot case TIOCSTOP: 31617545Skarels s = spltty(); 3179578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3185573Swnj tp->t_state |= TS_TTSTOP; 3195573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3205573Swnj } 3217625Ssam splx(s); 3225573Swnj break; 3235573Swnj 3248589Sroot case TIOCSTART: 32517545Skarels s = spltty(); 32635811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 3275573Swnj tp->t_state &= ~TS_TTSTOP; 32835811Smarc tp->t_lflag &= ~FLUSHO; 3295573Swnj ttstart(tp); 3305573Swnj } 3317625Ssam splx(s); 3325573Swnj break; 3335573Swnj 3349325Ssam /* 3359325Ssam * Simulate typing of a character at the terminal. 3369325Ssam */ 3379325Ssam case TIOCSTI: 33817183Smckusick if (u.u_uid && (flag & FREAD) == 0) 33917183Smckusick return (EPERM); 3409325Ssam if (u.u_uid && u.u_ttyp != tp) 3419325Ssam return (EACCES); 3429578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3439325Ssam break; 3449325Ssam 34535811Smarc case TIOCGETA: { 34635811Smarc struct termios *t = (struct termios *)data; 34712752Ssam 34835811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 34935811Smarc break; 35035811Smarc } 35135811Smarc 35235811Smarc case TIOCSETAS: 35335811Smarc case TIOCSETAWS: 35435811Smarc case TIOCSETAFS: 35535811Smarc softset = 1; 35635811Smarc /*FALLTHROUGH*/ 35735811Smarc case TIOCSETA: 35835811Smarc case TIOCSETAW: 35935811Smarc case TIOCSETAF: 36035811Smarc { 36135811Smarc register struct termios *t = (struct termios *)data; 36235811Smarc int error; 36335811Smarc 36417545Skarels s = spltty(); 36535811Smarc if (!softset) { 36635811Smarc /* 36735811Smarc * set device hardware 36835811Smarc */ 36935811Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) 37035811Smarc return (error); 37135811Smarc else { 37235811Smarc tp->t_cflag = t->c_cflag; 37335811Smarc tp->t_ispeed = t->c_ispeed; 37435811Smarc tp->t_ospeed = t->c_ospeed; 37534492Skarels } 37635811Smarc ttsetwater(tp); 37712752Ssam } 37835811Smarc if (com == TIOCSETAF || com == TIOCSETAFS) 37935811Smarc ttywflush(tp); 38035811Smarc else { 38135811Smarc if (com == TIOCSETAW || com == TIOCSETAWS) 38235811Smarc ttywait(tp); 38335811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 38435811Smarc if (t->c_lflag&ICANON) { 38535811Smarc tp->t_lflag |= PENDIN; 38635811Smarc ttwakeup(tp); 38735811Smarc } 38835811Smarc else { 38935811Smarc struct clist tq; 39035811Smarc 39135811Smarc catq(&tp->t_rawq, &tp->t_canq); 39235811Smarc tq = tp->t_rawq; 39335811Smarc tp->t_rawq = tp->t_canq; 39435811Smarc tp->t_canq = tq; 39535811Smarc } 39612752Ssam } 39735811Smarc tp->t_iflag = t->c_iflag; 39835811Smarc tp->t_oflag = t->c_oflag; 39935811Smarc tp->t_lflag = t->c_lflag; 40035811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 40112752Ssam splx(s); 40212752Ssam break; 40312752Ssam } 40412752Ssam 40512752Ssam case FIONBIO: 40612752Ssam if (*(int *)data) 40712752Ssam tp->t_state |= TS_NBIO; 40812752Ssam else 40912752Ssam tp->t_state &= ~TS_NBIO; 41012752Ssam break; 41112752Ssam 41212752Ssam case FIOASYNC: 41312752Ssam if (*(int *)data) 41412752Ssam tp->t_state |= TS_ASYNC; 41512752Ssam else 41612752Ssam tp->t_state &= ~TS_ASYNC; 41712752Ssam break; 41812752Ssam 41912752Ssam /* 42035811Smarc * Acquire controlling terminal. 42134492Skarels */ 42235811Smarc case TIOCSCTTY: { 42335811Smarc register struct proc *p = u.u_procp; 42434492Skarels 42535811Smarc /* RETHINK - whether non-session leader 42635811Smarc * can allocate a new ctty for a session. 42735811Smarc */ 42835811Smarc if (u.u_ttyp || 42935811Smarc (tp->t_session && tp->t_session != p->p_session) || 43035811Smarc (!tp->t_session && !SESS_LEADER(p))) 43135811Smarc return(EPERM); 43235811Smarc u.u_ttyp = tp; 43335811Smarc u.u_ttyd = tp->t_dev; 43435811Smarc if (tp->t_pgid == 0) 43535811Smarc tp->t_pgid = p->p_pgrp->pg_id; 43635811Smarc tp->t_session = p->p_session; 43734492Skarels break; 43835811Smarc } 43934492Skarels 44034492Skarels /* 44135811Smarc * Set terminal process group. 44217545Skarels */ 44318650Sbloom case TIOCSPGRP: { 44435811Smarc register struct proc *p = u.u_procp; 44535811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 44617545Skarels 44735811Smarc if (u.u_uid && 44835811Smarc (tp != u.u_ttyp || 44935811Smarc (pgrp && pgrp->pg_session != p->p_session))) { 45035811Smarc if (u.u_ttyp == NULL) 45135811Smarc return (ENOTTY); 45235811Smarc else 45335811Smarc return (EPERM); 45435811Smarc } 45535811Smarc tp->t_pgid = *(int *)data; 45612752Ssam break; 45718650Sbloom } 45812752Ssam 45912752Ssam case TIOCGPGRP: 46035811Smarc *(int *)data = tp->t_pgid; 46112752Ssam break; 46212752Ssam 46317598Sbloom case TIOCSWINSZ: 46418650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 46518650Sbloom sizeof (struct winsize))) { 46617598Sbloom tp->t_winsize = *(struct winsize *)data; 46735811Smarc gsignal(tp->t_pgid, SIGWINCH); 46817598Sbloom } 46917598Sbloom break; 47017598Sbloom 47117598Sbloom case TIOCGWINSZ: 47217598Sbloom *(struct winsize *)data = tp->t_winsize; 47317598Sbloom break; 47417598Sbloom 47530534Skarels case TIOCCONS: 47630534Skarels if (*(int *)data) { 47730534Skarels if (constty != NULL) 47830534Skarels return (EBUSY); 47930534Skarels #ifndef UCONSOLE 480*37554Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 481*37554Smckusick return (error); 48230534Skarels #endif 48330534Skarels constty = tp; 48430534Skarels } else if (tp == constty) 48533404Skarels constty = NULL; 48630534Skarels break; 48730534Skarels 48835811Smarc #ifdef COMPAT_43 48935811Smarc case TIOCGETP: 49035811Smarc case TIOCSETP: 49135811Smarc case TIOCSETN: 49235811Smarc case TIOCGETC: 49335811Smarc case TIOCSETC: 49435811Smarc case TIOCSLTC: 49535811Smarc case TIOCGLTC: 49635811Smarc case TIOCLBIS: 49735811Smarc case TIOCLBIC: 49835811Smarc case TIOCLSET: 49935811Smarc case TIOCLGET: 50035811Smarc case TIOCGETDCOMPAT: 50135811Smarc case TIOCSETDCOMPAT: 50235811Smarc return(ttcompat(tp, com, data, flag)); 50335811Smarc #endif 50435811Smarc 50539Sbill default: 5068556Sroot return (-1); 50739Sbill } 5088556Sroot return (0); 50939Sbill } 5104484Swnj 5114484Swnj ttnread(tp) 5124484Swnj struct tty *tp; 5134484Swnj { 5144484Swnj int nread = 0; 5154484Swnj 51635811Smarc if (tp->t_lflag & PENDIN) 5174484Swnj ttypend(tp); 5184484Swnj nread = tp->t_canq.c_cc; 51935811Smarc if ((tp->t_lflag & ICANON) == 0) 5204484Swnj nread += tp->t_rawq.c_cc; 5214484Swnj return (nread); 5224484Swnj } 5234484Swnj 5245408Swnj ttselect(dev, rw) 5254484Swnj dev_t dev; 5265408Swnj int rw; 5274484Swnj { 5284484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5294484Swnj int nread; 53017545Skarels int s = spltty(); 5314484Swnj 5325408Swnj switch (rw) { 5334484Swnj 5344484Swnj case FREAD: 5354484Swnj nread = ttnread(tp); 53629946Skarels if (nread > 0 || (tp->t_state & TS_CARR_ON) == 0) 5375408Swnj goto win; 5384938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5395408Swnj tp->t_state |= TS_RCOLL; 5404484Swnj else 5414484Swnj tp->t_rsel = u.u_procp; 5425408Swnj break; 5434484Swnj 5445408Swnj case FWRITE: 54535811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 5465408Swnj goto win; 5475408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5485408Swnj tp->t_state |= TS_WCOLL; 5495408Swnj else 5505408Swnj tp->t_wsel = u.u_procp; 5515408Swnj break; 5524484Swnj } 5535408Swnj splx(s); 5545408Swnj return (0); 5555408Swnj win: 5565408Swnj splx(s); 5575408Swnj return (1); 5584484Swnj } 5597436Skre 5607502Sroot /* 56125391Skarels * Initial open of tty, or (re)entry to line discipline. 5627502Sroot */ 5637502Sroot ttyopen(dev, tp) 5647625Ssam dev_t dev; 5657625Ssam register struct tty *tp; 5667502Sroot { 5677502Sroot register struct proc *pp; 5687502Sroot 5697502Sroot tp->t_dev = dev; 57035811Smarc 5717502Sroot tp->t_state &= ~TS_WOPEN; 57217545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 57317545Skarels tp->t_state |= TS_ISOPEN; 57417598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 57517545Skarels } 5768556Sroot return (0); 5777502Sroot } 5787502Sroot 5797502Sroot /* 58025391Skarels * "close" a line discipline 58125391Skarels */ 58225391Skarels ttylclose(tp) 58325391Skarels register struct tty *tp; 58425391Skarels { 58525391Skarels 58625391Skarels ttywflush(tp); 58725391Skarels } 58825391Skarels 58925391Skarels /* 5907502Sroot * clean tp on last close 5917502Sroot */ 5927502Sroot ttyclose(tp) 5937625Ssam register struct tty *tp; 5947502Sroot { 59530534Skarels if (constty == tp) 59630534Skarels constty = NULL; 59725391Skarels ttyflush(tp, FREAD|FWRITE); 59835811Smarc tp->t_pgid = 0; 5997502Sroot tp->t_state = 0; 6007502Sroot } 6017502Sroot 6027502Sroot /* 60325391Skarels * Handle modem control transition on a tty. 60425391Skarels * Flag indicates new state of carrier. 60525391Skarels * Returns 0 if the line should be turned off, otherwise 1. 60625391Skarels */ 60725391Skarels ttymodem(tp, flag) 60825391Skarels register struct tty *tp; 60925391Skarels { 61025391Skarels 61135811Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag & MDMBUF)) { 61225391Skarels /* 61325391Skarels * MDMBUF: do flow control according to carrier flag 61425391Skarels */ 61525391Skarels if (flag) { 61625391Skarels tp->t_state &= ~TS_TTSTOP; 61725391Skarels ttstart(tp); 61825391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 61925391Skarels tp->t_state |= TS_TTSTOP; 62025391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 62125391Skarels } 62225391Skarels } else if (flag == 0) { 62325391Skarels /* 62425391Skarels * Lost carrier. 62525391Skarels */ 62625391Skarels tp->t_state &= ~TS_CARR_ON; 62725391Skarels if (tp->t_state & TS_ISOPEN) { 62835811Smarc if ((tp->t_lflag & NOHANG) == 0) { 62935811Smarc gsignal(tp->t_pgid, SIGHUP); 63035811Smarc gsignal(tp->t_pgid, SIGCONT); 63125391Skarels ttyflush(tp, FREAD|FWRITE); 63225391Skarels return (0); 63325391Skarels } 63425391Skarels } 63525391Skarels } else { 63625391Skarels /* 63725391Skarels * Carrier now on. 63825391Skarels */ 63925391Skarels tp->t_state |= TS_CARR_ON; 64025391Skarels wakeup((caddr_t)&tp->t_rawq); 64125391Skarels } 64225391Skarels return (1); 64325391Skarels } 64425391Skarels 64525391Skarels /* 64625404Skarels * Default modem control routine (for other line disciplines). 64725404Skarels * Return argument flag, to turn off device on carrier drop. 64825404Skarels */ 64925415Skarels nullmodem(tp, flag) 65025415Skarels register struct tty *tp; 65125404Skarels int flag; 65225404Skarels { 65325404Skarels 65425404Skarels if (flag) 65525404Skarels tp->t_state |= TS_CARR_ON; 65625404Skarels else 65725404Skarels tp->t_state &= ~TS_CARR_ON; 65825404Skarels return (flag); 65925404Skarels } 66025404Skarels 66125404Skarels /* 6627502Sroot * reinput pending characters after state switch 66317545Skarels * call at spltty(). 6647502Sroot */ 6657502Sroot ttypend(tp) 6667625Ssam register struct tty *tp; 6677502Sroot { 6687502Sroot struct clist tq; 6697502Sroot register c; 6707502Sroot 67135811Smarc tp->t_lflag &= ~PENDIN; 6729578Ssam tp->t_state |= TS_TYPEN; 6737502Sroot tq = tp->t_rawq; 6747502Sroot tp->t_rawq.c_cc = 0; 6757502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6767502Sroot while ((c = getc(&tq)) >= 0) 6777502Sroot ttyinput(c, tp); 6789578Ssam tp->t_state &= ~TS_TYPEN; 6797502Sroot } 6807502Sroot 6817502Sroot /* 68235811Smarc * 6839578Ssam * Place a character on raw TTY input queue, 6849578Ssam * putting in delimiters and waking up top 6859578Ssam * half as needed. Also echo if required. 6869578Ssam * The arguments are the character and the 6879578Ssam * appropriate tty structure. 6887502Sroot */ 6897502Sroot ttyinput(c, tp) 6907625Ssam register c; 6917625Ssam register struct tty *tp; 6927502Sroot { 69335811Smarc register int iflag = tp->t_iflag; 69435811Smarc register int lflag = tp->t_lflag; 69535811Smarc register u_char *cc = tp->t_cc; 69635811Smarc int i, err; 6977502Sroot 6989578Ssam /* 6999578Ssam * If input is pending take it first. 7009578Ssam */ 70135811Smarc if (lflag&PENDIN) 7027502Sroot ttypend(tp); 70335811Smarc /* 70435811Smarc * Gather stats. 70535811Smarc */ 7067502Sroot tk_nin++; 70735811Smarc if (lflag&ICANON) { 70835811Smarc tk_cancc++; 70935811Smarc tp->t_cancc++; 71035811Smarc } else { 71135811Smarc tk_rawcc++; 71235811Smarc tp->t_rawcc++; 71335811Smarc } 7149578Ssam /* 71535811Smarc * Handle exceptional conditions (break, parity, framing). 7169578Ssam */ 71735811Smarc if (err = (c&TTY_ERRORMASK)) { 71835811Smarc c &= ~TTY_ERRORMASK; 71935811Smarc if (err&TTY_FE && !c) { /* break */ 72035811Smarc if (iflag&IGNBRK) 72135811Smarc goto endcase; 72235811Smarc else if (iflag&BRKINT && lflag&ISIG && 72335811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 72435811Smarc c = cc[VINTR]; 72535811Smarc else { 72635811Smarc c = 0; 72735811Smarc if (iflag&PARMRK) 72835811Smarc goto parmrk; 72935811Smarc } 73035811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 73135811Smarc if (iflag&IGNPAR) 73235811Smarc goto endcase; 73335811Smarc else if (iflag&PARMRK) { 73435811Smarc parmrk: 73535811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 73635811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 73735811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 73835811Smarc goto endcase; 73935811Smarc } else 74035811Smarc c = 0; 7417502Sroot } 7429578Ssam } 7439578Ssam /* 74435811Smarc * In tandem mode, check high water mark. 7459578Ssam */ 74635811Smarc if (iflag&IXOFF) 74735811Smarc ttyblock(tp); 74835811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 7499578Ssam c &= 0177; 7509578Ssam /* 7519578Ssam * Check for literal nexting very first 7529578Ssam */ 7539578Ssam if (tp->t_state&TS_LNCH) { 75435811Smarc c |= TTY_QUOTE; 7559578Ssam tp->t_state &= ~TS_LNCH; 7569578Ssam } 7579578Ssam /* 7589578Ssam * Scan for special characters. This code 7599578Ssam * is really just a big case statement with 7609578Ssam * non-constant cases. The bottom of the 7619578Ssam * case statement is labeled ``endcase'', so goto 7629578Ssam * it after a case match, or similar. 7639578Ssam */ 76435811Smarc /* 76535811Smarc * Control chars which aren't controlled 76635811Smarc * by ICANON, ISIG, or IXON. 76735811Smarc */ 76835811Smarc if (iflag&IEXTEN) { 76935811Smarc if (CCEQ(cc[VLNEXT],c)) { 77035811Smarc if (lflag&ECHO) { 77135811Smarc if (lflag&ECHOE) 77235811Smarc ttyout("^\b", tp); 77335811Smarc else 77435811Smarc ttyecho(c, tp); 77535811Smarc } 7769578Ssam tp->t_state |= TS_LNCH; 7779578Ssam goto endcase; 7789578Ssam } 77935811Smarc if (CCEQ(cc[VFLUSHO],c)) { 78035811Smarc if (lflag&FLUSHO) 78135811Smarc tp->t_lflag &= ~FLUSHO; 7827502Sroot else { 78312752Ssam ttyflush(tp, FWRITE); 7847502Sroot ttyecho(c, tp); 7859578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7867502Sroot ttyretype(tp); 78735811Smarc tp->t_lflag |= FLUSHO; 7887502Sroot } 7899578Ssam goto startoutput; 7909578Ssam } 79135811Smarc } 79235811Smarc /* 79335811Smarc * Signals. 79435811Smarc */ 79535811Smarc if (lflag&ISIG) { 79635811Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 79735811Smarc if ((lflag&NOFLSH) == 0) 79835811Smarc ttyflush(tp, FREAD|FWRITE); 79935811Smarc ttyecho(c, tp); 80035811Smarc gsignal(tp->t_pgid, CCEQ(cc[VINTR],c) ? 80135811Smarc SIGINT : SIGQUIT); 80235811Smarc goto endcase; 80335811Smarc } 80435811Smarc if (CCEQ(cc[VSUSP],c)) { 80535811Smarc if ((lflag&NOFLSH) == 0) 80612752Ssam ttyflush(tp, FREAD); 8079578Ssam ttyecho(c, tp); 80835811Smarc gsignal(tp->t_pgid, SIGTSTP); 8099578Ssam goto endcase; 8109578Ssam } 8119578Ssam } 8129578Ssam /* 8139578Ssam * Handle start/stop characters. 8149578Ssam */ 81535811Smarc if (iflag&IXON) { 81635811Smarc if (CCEQ(cc[VSTOP],c)) { 81735811Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 81835811Smarc tp->t_state |= TS_TTSTOP; 81935811Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 82035811Smarc return; 82135811Smarc } 82235811Smarc if (!CCEQ(cc[VSTART], c)) 82335811Smarc return; 82435811Smarc /* 82535811Smarc * if VSTART == VSTOP then toggle 82635811Smarc */ 82735811Smarc goto endcase; 8289578Ssam } 82935811Smarc if (CCEQ(cc[VSTART], c)) 83035811Smarc goto restartoutput; 8319578Ssam } 8329578Ssam /* 83335811Smarc * IGNCR, ICRNL, & INLCR 8349578Ssam */ 83535811Smarc if (c == '\r') { 83635811Smarc if (iflag&IGNCR) 83735811Smarc goto endcase; 83835811Smarc else if (iflag&ICRNL) 83935811Smarc c = '\n'; 8409578Ssam } 84135811Smarc else if (c == '\n' && iflag&INLCR) 84235811Smarc c = '\r'; 8439578Ssam /* 84435811Smarc * Non canonical mode; don't process line editing 8459578Ssam * characters; check high water mark for wakeup. 84635811Smarc * 8479578Ssam */ 84835811Smarc if (!(lflag&ICANON)) { 8499578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 85035811Smarc if (iflag&IMAXBEL) { 85135811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 85235811Smarc (void) ttyoutput(CTRL('g'), tp); 85335811Smarc } else 85435811Smarc ttyflush(tp, FREAD | FWRITE); 85535811Smarc } else { 85635811Smarc if (putc(c, &tp->t_rawq) >= 0) { 85735811Smarc ttwakeup(tp); 85835811Smarc ttyecho(c, tp); 85935811Smarc } 8607502Sroot } 8619578Ssam goto endcase; 8629578Ssam } 8639578Ssam /* 86435811Smarc * From here on down canonical mode character 8659578Ssam * processing takes place. 8669578Ssam */ 86735811Smarc /* 86835811Smarc * erase (^H / ^?) 86935811Smarc */ 87035811Smarc if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c)) { 8719578Ssam if (tp->t_rawq.c_cc) 8729578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8739578Ssam goto endcase; 8749578Ssam } 87535811Smarc /* 87635811Smarc * kill (^U) 87735811Smarc */ 87835811Smarc if (CCEQ(cc[VKILL], c)) { 87935811Smarc if (lflag&ECHOKE && 8809578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 8819578Ssam while (tp->t_rawq.c_cc) 8829578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8839578Ssam } else { 8849578Ssam ttyecho(c, tp); 88535811Smarc if (lflag&ECHOK || lflag&ECHOKE) 88635811Smarc ttyecho('\n', tp); 8879578Ssam while (getc(&tp->t_rawq) > 0) 8889578Ssam ; 8899578Ssam tp->t_rocount = 0; 8909578Ssam } 8919578Ssam tp->t_state &= ~TS_LOCAL; 8929578Ssam goto endcase; 8939578Ssam } 8949578Ssam /* 89535811Smarc * word erase (^W) 8969578Ssam */ 89735811Smarc if (CCEQ(cc[VWERASE], c)) { 89835811Smarc int ctype; 89935811Smarc 90035811Smarc #define CTYPE(c) ((lflag&ALTWERASE) ? (partab[(c)&TTY_CHARMASK]&0100) : 0) 90135811Smarc /* 90235811Smarc * erase whitespace 90335811Smarc */ 90435811Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 90535811Smarc ttyrub(c, tp); 90635811Smarc if (c == -1) 90734492Skarels goto endcase; 90835811Smarc /* 90935811Smarc * special case last char of token 91035811Smarc */ 91135811Smarc ttyrub(c, tp); 91235811Smarc c = unputc(&tp->t_rawq); 91335811Smarc if (c == -1 || c == ' ' || c == '\t') { 91435811Smarc if (c != -1) 91535811Smarc (void) putc(c, &tp->t_rawq); 91634492Skarels goto endcase; 91734492Skarels } 91835811Smarc /* 91935811Smarc * erase rest of token 92035811Smarc */ 92135811Smarc ctype = CTYPE(c); 92235811Smarc do { 92335811Smarc ttyrub(c, tp); 92435811Smarc c = unputc(&tp->t_rawq); 92535811Smarc if (c == -1) 92635811Smarc goto endcase; 92735811Smarc } while (c != ' ' && c != '\t' && CTYPE(c) == ctype); 92835811Smarc (void) putc(c, &tp->t_rawq); 92935811Smarc goto endcase; 93035811Smarc #undef CTYPE 9319578Ssam } 9329578Ssam /* 93335811Smarc * reprint line (^R) 93435811Smarc */ 93535811Smarc if (CCEQ(cc[VREPRINT], c)) { 93635811Smarc ttyretype(tp); 93735811Smarc goto endcase; 93835811Smarc } 93935811Smarc /* 9409578Ssam * Check for input buffer overflow 9419578Ssam */ 94210391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 94335811Smarc if (iflag&IMAXBEL) { 94435811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 94535811Smarc (void) ttyoutput(CTRL('g'), tp); 94635811Smarc } else 94735811Smarc ttyflush(tp, FREAD | FWRITE); 9489578Ssam goto endcase; 94910391Ssam } 9509578Ssam /* 9519578Ssam * Put data char in q for user and 9529578Ssam * wakeup on seeing a line delimiter. 9539578Ssam */ 9549578Ssam if (putc(c, &tp->t_rawq) >= 0) { 95535811Smarc if (ttbreakc(c)) { 9569578Ssam tp->t_rocount = 0; 9579578Ssam catq(&tp->t_rawq, &tp->t_canq); 9587502Sroot ttwakeup(tp); 9599578Ssam } else if (tp->t_rocount++ == 0) 9609578Ssam tp->t_rocol = tp->t_col; 9619578Ssam if (tp->t_state&TS_ERASE) { 96235811Smarc /* 96335811Smarc * end of prterase \.../ 96435811Smarc */ 9659578Ssam tp->t_state &= ~TS_ERASE; 9669578Ssam (void) ttyoutput('/', tp); 9679578Ssam } 9689578Ssam i = tp->t_col; 9697502Sroot ttyecho(c, tp); 97035811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 97135811Smarc /* 97235811Smarc * Place the cursor over the '^' of the ^D. 97335811Smarc */ 9749578Ssam i = MIN(2, tp->t_col - i); 9759578Ssam while (i > 0) { 9769578Ssam (void) ttyoutput('\b', tp); 9779578Ssam i--; 9789578Ssam } 9799578Ssam } 9807502Sroot } 9819578Ssam endcase: 9829578Ssam /* 98335811Smarc * IXANY means allow any character to restart output. 9849578Ssam */ 98535811Smarc if ((tp->t_state&TS_TTSTOP) && !(iflag&IXANY) 98635811Smarc && cc[VSTART] != cc[VSTOP]) 9877502Sroot return; 9889578Ssam restartoutput: 9897502Sroot tp->t_state &= ~TS_TTSTOP; 99035811Smarc tp->t_lflag &= ~FLUSHO; 9919578Ssam startoutput: 9927502Sroot ttstart(tp); 9937502Sroot } 9947502Sroot 9957502Sroot /* 9969578Ssam * Put character on TTY output queue, adding delays, 9977502Sroot * expanding tabs, and handling the CR/NL bit. 9989578Ssam * This is called both from the top half for output, 9999578Ssam * and from interrupt level for echoing. 10007502Sroot * The arguments are the character and the tty structure. 10017502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 10027502Sroot * Must be recursive. 10037502Sroot */ 10047502Sroot ttyoutput(c, tp) 10057502Sroot register c; 10067502Sroot register struct tty *tp; 10077502Sroot { 10087502Sroot register char *colp; 10097502Sroot register ctype; 101035811Smarc register long oflag = tp->t_oflag; 101135811Smarc 101235811Smarc if (!(oflag&OPOST)) { 101335811Smarc if (tp->t_lflag&FLUSHO) 10147502Sroot return (-1); 10157502Sroot if (putc(c, &tp->t_outq)) 10167625Ssam return (c); 10177502Sroot tk_nout++; 101835811Smarc tp->t_outcc++; 10197502Sroot return (-1); 10207502Sroot } 102135811Smarc c &= TTY_CHARMASK; 10227502Sroot /* 10237502Sroot * Turn tabs to spaces as required 10247502Sroot */ 102535811Smarc if (c == '\t' && oflag&OXTABS ) { 10267502Sroot register int s; 10277502Sroot 10287502Sroot c = 8 - (tp->t_col&7); 102935811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 103017545Skarels s = spltty(); /* don't interrupt tabs */ 10317502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10327502Sroot tk_nout += c; 103335811Smarc tp->t_outcc += c; 10347502Sroot splx(s); 10357502Sroot } 10367502Sroot tp->t_col += c; 10377502Sroot return (c ? -1 : '\t'); 10387502Sroot } 103935811Smarc if (c == CEOT && oflag&ONOEOT) 104035811Smarc return(-1); 10417502Sroot tk_nout++; 104235811Smarc tp->t_outcc++; 10437502Sroot /* 10447502Sroot * turn <nl> to <cr><lf> if desired. 10457502Sroot */ 104635811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 10477502Sroot return (c); 104835811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 104935811Smarc return (c); 10507502Sroot /* 10517502Sroot * Calculate delays. 10527502Sroot * The numbers here represent clock ticks 10537502Sroot * and are not necessarily optimal for all terminals. 10549578Ssam * 10559578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 105635811Smarc * 105735811Smarc * (actually, should THROW AWAY terminals which need delays) 10587502Sroot */ 10597502Sroot colp = &tp->t_col; 10607502Sroot ctype = partab[c]; 10617502Sroot c = 0; 10627502Sroot switch (ctype&077) { 10637502Sroot 10647502Sroot case ORDINARY: 10657502Sroot (*colp)++; 10667502Sroot 10677502Sroot case CONTROL: 10687502Sroot break; 10697502Sroot 10707502Sroot case BACKSPACE: 10717502Sroot if (*colp) 10727502Sroot (*colp)--; 10737502Sroot break; 10747502Sroot 107513821Ssam /* 107613821Ssam * This macro is close enough to the correct thing; 107713821Ssam * it should be replaced by real user settable delays 107813821Ssam * in any event... 107913821Ssam */ 108013821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10817502Sroot case NEWLINE: 10827502Sroot ctype = (tp->t_flags >> 8) & 03; 10837625Ssam if (ctype == 1) { /* tty 37 */ 108426357Skarels if (*colp > 0) { 108526357Skarels c = (((unsigned)*colp) >> 4) + 3; 108626357Skarels if ((unsigned)c > 6) 108726357Skarels c = 6; 108826357Skarels } 10899578Ssam } else if (ctype == 2) /* vt05 */ 109013821Ssam c = mstohz(100); 10917502Sroot *colp = 0; 10927502Sroot break; 10937502Sroot 10947502Sroot case TAB: 10957502Sroot ctype = (tp->t_flags >> 10) & 03; 10967625Ssam if (ctype == 1) { /* tty 37 */ 10977502Sroot c = 1 - (*colp | ~07); 10987625Ssam if (c < 5) 10997502Sroot c = 0; 11007502Sroot } 11017502Sroot *colp |= 07; 11027502Sroot (*colp)++; 11037502Sroot break; 11047502Sroot 11057502Sroot case VTAB: 11069578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 11077502Sroot c = 0177; 11087502Sroot break; 11097502Sroot 11107502Sroot case RETURN: 11117502Sroot ctype = (tp->t_flags >> 12) & 03; 11129578Ssam if (ctype == 1) /* tn 300 */ 111313821Ssam c = mstohz(83); 11149578Ssam else if (ctype == 2) /* ti 700 */ 111513821Ssam c = mstohz(166); 11169578Ssam else if (ctype == 3) { /* concept 100 */ 11177502Sroot int i; 11189578Ssam 11197502Sroot if ((i = *colp) >= 0) 11209578Ssam for (; i < 9; i++) 11217502Sroot (void) putc(0177, &tp->t_outq); 11227502Sroot } 11237502Sroot *colp = 0; 11247502Sroot } 112535811Smarc if (c && (tp->t_lflag&FLUSHO) == 0) 112635811Smarc (void) putc(c|TTY_QUOTE, &tp->t_outq); 11277502Sroot return (-1); 11287502Sroot } 112913821Ssam #undef mstohz 11307502Sroot 11317502Sroot /* 11327502Sroot * Called from device's read routine after it has 11337502Sroot * calculated the tty-structure given as argument. 11347502Sroot */ 11357722Swnj ttread(tp, uio) 11367625Ssam register struct tty *tp; 11377722Swnj struct uio *uio; 11387502Sroot { 11397502Sroot register struct clist *qp; 114035811Smarc register int c; 114135811Smarc register long lflag = tp->t_lflag; 114235811Smarc register long iflag = tp->t_iflag; 114335811Smarc register u_char *cc = tp->t_cc; 11449859Ssam int s, first, error = 0; 11457502Sroot 11467502Sroot loop: 11479578Ssam /* 11489578Ssam * Take any pending input first. 11499578Ssam */ 115017545Skarels s = spltty(); 115135811Smarc if (lflag&PENDIN) 11527502Sroot ttypend(tp); 11539859Ssam splx(s); 115423165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 115523165Sbloom return (EIO); 11569578Ssam /* 11579578Ssam * Hang process if it's in the background. 11589578Ssam */ 115935811Smarc if (u.u_ttyp == tp && u.u_procp->p_pgid != tp->t_pgid) { 116024392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 116124392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 116235811Smarc u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0) 11638520Sroot return (EIO); 116435811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTIN); 11657502Sroot sleep((caddr_t)&lbolt, TTIPRI); 116623165Sbloom goto loop; 11677502Sroot } 11689578Ssam /* 116935811Smarc * If canonical, use the canonical queue, 117035811Smarc * else use the raw queue. 11719578Ssam */ 117235811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 11739578Ssam /* 11749578Ssam * No input, sleep on rawq awaiting hardware 11759578Ssam * receipt and notification. 11769578Ssam */ 117717545Skarels s = spltty(); 11789578Ssam if (qp->c_cc <= 0) { 11799578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11809578Ssam (tp->t_state&TS_NBIO)) { 11819859Ssam splx(s); 11829578Ssam return (EWOULDBLOCK); 11837502Sroot } 11849578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11859859Ssam splx(s); 11869578Ssam goto loop; 11879578Ssam } 11889859Ssam splx(s); 11899578Ssam /* 119035811Smarc * Input present, check for input mapping and processing. 11919578Ssam */ 11929578Ssam first = 1; 11939578Ssam while ((c = getc(qp)) >= 0) { 11949578Ssam /* 119535811Smarc * delayed suspend (^Y) 11969578Ssam */ 119735811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 119835811Smarc gsignal(tp->t_pgid, SIGTSTP); 11999578Ssam if (first) { 12009578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12019578Ssam goto loop; 12029578Ssam } 12039578Ssam break; 12047502Sroot } 12059578Ssam /* 120635811Smarc * Interpret EOF only in canonical mode. 12079578Ssam */ 120835811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12099578Ssam break; 12109578Ssam /* 12119578Ssam * Give user character. 12129578Ssam */ 121335811Smarc error = ureadc(c , uio); 12149578Ssam if (error) 12159578Ssam break; 121614938Smckusick if (uio->uio_resid == 0) 12179578Ssam break; 12189578Ssam /* 121935811Smarc * In canonical mode check for a "break character" 12209578Ssam * marking the end of a "line of input". 12219578Ssam */ 122235811Smarc if (lflag&ICANON && ttbreakc(c)) { 12239578Ssam break; 122435811Smarc } 12259578Ssam first = 0; 12267502Sroot } 12279859Ssam checktandem: 12289578Ssam /* 12299578Ssam * Look to unblock output now that (presumably) 12309578Ssam * the input queue has gone down. 12319578Ssam */ 123235811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 123335811Smarc if (cc[VSTART] != _POSIX_VDISABLE 123435811Smarc && putc(cc[VSTART], &tp->t_outq) == 0) { 12357502Sroot tp->t_state &= ~TS_TBLOCK; 12367502Sroot ttstart(tp); 12377502Sroot } 123835811Smarc } 12398520Sroot return (error); 12407502Sroot } 12417502Sroot 12427502Sroot /* 124325391Skarels * Check the output queue on tp for space for a kernel message 124425391Skarels * (from uprintf/tprintf). Allow some space over the normal 124525391Skarels * hiwater mark so we don't lose messages due to normal flow 124625391Skarels * control, but don't let the tty run amok. 124730695Skarels * Sleeps here are not interruptible, but we return prematurely 124830695Skarels * if new signals come in. 124925391Skarels */ 125025391Skarels ttycheckoutq(tp, wait) 125125391Skarels register struct tty *tp; 125225391Skarels int wait; 125325391Skarels { 125430695Skarels int hiwat, s, oldsig; 125525391Skarels 125635811Smarc hiwat = tp->t_hiwat; 125725391Skarels s = spltty(); 125830695Skarels oldsig = u.u_procp->p_sig; 125925391Skarels if (tp->t_outq.c_cc > hiwat + 200) 126029946Skarels while (tp->t_outq.c_cc > hiwat) { 126129946Skarels ttstart(tp); 126230695Skarels if (wait == 0 || u.u_procp->p_sig != oldsig) { 126329946Skarels splx(s); 126429946Skarels return (0); 126529946Skarels } 126630695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 126729946Skarels tp->t_state |= TS_ASLEEP; 126830695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 126925391Skarels } 127025391Skarels splx(s); 127125391Skarels return (1); 127225391Skarels } 127325391Skarels 127425391Skarels /* 12757502Sroot * Called from the device's write routine after it has 12767502Sroot * calculated the tty-structure given as argument. 12777502Sroot */ 12787822Sroot ttwrite(tp, uio) 12797625Ssam register struct tty *tp; 12809578Ssam register struct uio *uio; 12817502Sroot { 12827502Sroot register char *cp; 12839578Ssam register int cc, ce, c; 12849578Ssam int i, hiwat, cnt, error, s; 12857502Sroot char obuf[OBUFSIZ]; 12867502Sroot 128735811Smarc hiwat = tp->t_hiwat; 12889578Ssam cnt = uio->uio_resid; 12899578Ssam error = 0; 12907502Sroot loop: 129121776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 129221776Sbloom return (EIO); 12939578Ssam /* 12949578Ssam * Hang the process if it's in the background. 12959578Ssam */ 129635811Smarc if (u.u_ttyp == tp && 129735811Smarc u.u_procp->p_pgid != tp->t_pgid && 129835811Smarc (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 129924392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 130035811Smarc !(u.u_procp->p_sigmask & sigmask(SIGTTOU)) && 130135811Smarc u.u_procp->p_pgrp->pg_jobc) { 130235811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU); 13037502Sroot sleep((caddr_t)&lbolt, TTIPRI); 130421776Sbloom goto loop; 13057502Sroot } 13069578Ssam /* 13079578Ssam * Process the user's data in at most OBUFSIZ 13089578Ssam * chunks. Perform lower case simulation and 13099578Ssam * similar hacks. Keep track of high water 13109578Ssam * mark, sleep on overflow awaiting device aid 13119578Ssam * in acquiring new space. 13129578Ssam */ 13137822Sroot while (uio->uio_resid > 0) { 131432067Skarels if (tp->t_outq.c_cc > hiwat) { 131532067Skarels cc = 0; 131632067Skarels goto ovhiwat; 131732067Skarels } 13189578Ssam /* 13199578Ssam * Grab a hunk of data from the user. 13209578Ssam */ 13217822Sroot cc = uio->uio_iov->iov_len; 13227822Sroot if (cc == 0) { 13237822Sroot uio->uio_iovcnt--; 13247822Sroot uio->uio_iov++; 132521776Sbloom if (uio->uio_iovcnt <= 0) 13267822Sroot panic("ttwrite"); 13277822Sroot continue; 13287822Sroot } 13297822Sroot if (cc > OBUFSIZ) 13307822Sroot cc = OBUFSIZ; 13317502Sroot cp = obuf; 133212752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13338520Sroot if (error) 13347502Sroot break; 133535811Smarc if (tp->t_lflag&FLUSHO) 13367502Sroot continue; 13379578Ssam /* 13389578Ssam * If nothing fancy need be done, grab those characters we 13399578Ssam * can handle without any of ttyoutput's processing and 13409578Ssam * just transfer them to the output q. For those chars 13419578Ssam * which require special processing (as indicated by the 13429578Ssam * bits in partab), call ttyoutput. After processing 13439578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13449578Ssam * immediately. 13459578Ssam */ 13469578Ssam while (cc > 0) { 134735811Smarc if (!(tp->t_oflag&OPOST)) 13487502Sroot ce = cc; 13497502Sroot else { 135034492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 135134492Skarels (u_char *)partab, 077); 13529578Ssam /* 13539578Ssam * If ce is zero, then we're processing 13549578Ssam * a special character through ttyoutput. 13559578Ssam */ 13569578Ssam if (ce == 0) { 13577502Sroot tp->t_rocount = 0; 13587502Sroot if (ttyoutput(*cp, tp) >= 0) { 135921776Sbloom /* no c-lists, wait a bit */ 136021776Sbloom ttstart(tp); 136121776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 136221776Sbloom if (cc != 0) { 136321776Sbloom uio->uio_iov->iov_base -= cc; 136421776Sbloom uio->uio_iov->iov_len += cc; 136521776Sbloom uio->uio_resid += cc; 136621776Sbloom uio->uio_offset -= cc; 136721776Sbloom } 136821776Sbloom goto loop; 13697502Sroot } 13709578Ssam cp++, cc--; 137135811Smarc if ((tp->t_lflag&FLUSHO) || 13729578Ssam tp->t_outq.c_cc > hiwat) 13737502Sroot goto ovhiwat; 13749578Ssam continue; 13757502Sroot } 13767502Sroot } 13779578Ssam /* 13789578Ssam * A bunch of normal characters have been found, 13799578Ssam * transfer them en masse to the output queue and 13809578Ssam * continue processing at the top of the loop. 13819578Ssam * If there are any further characters in this 13829578Ssam * <= OBUFSIZ chunk, the first should be a character 13839578Ssam * requiring special handling by ttyoutput. 13849578Ssam */ 13857502Sroot tp->t_rocount = 0; 13869578Ssam i = b_to_q(cp, ce, &tp->t_outq); 13879578Ssam ce -= i; 13889578Ssam tp->t_col += ce; 13899578Ssam cp += ce, cc -= ce, tk_nout += ce; 139035811Smarc tp->t_outcc += ce; 13919578Ssam if (i > 0) { 13929578Ssam /* out of c-lists, wait a bit */ 13937502Sroot ttstart(tp); 13947502Sroot sleep((caddr_t)&lbolt, TTOPRI); 139521776Sbloom uio->uio_iov->iov_base -= cc; 139621776Sbloom uio->uio_iov->iov_len += cc; 139721776Sbloom uio->uio_resid += cc; 139821776Sbloom uio->uio_offset -= cc; 139921776Sbloom goto loop; 14007502Sroot } 140135811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 14027502Sroot goto ovhiwat; 14037502Sroot } 140435811Smarc ttstart(tp); 14057502Sroot } 14068520Sroot return (error); 14077502Sroot ovhiwat: 14089578Ssam if (cc != 0) { 14099578Ssam uio->uio_iov->iov_base -= cc; 14109578Ssam uio->uio_iov->iov_len += cc; 14119578Ssam uio->uio_resid += cc; 14129578Ssam uio->uio_offset -= cc; 14139578Ssam } 141432067Skarels ttstart(tp); 141532067Skarels s = spltty(); 14169578Ssam /* 141735811Smarc * This can only occur if FLUSHO is set in t_lflag, 141832067Skarels * or if ttstart/oproc is synchronous (or very fast). 14199578Ssam */ 14207502Sroot if (tp->t_outq.c_cc <= hiwat) { 14219578Ssam splx(s); 14227502Sroot goto loop; 14237502Sroot } 14249578Ssam if (tp->t_state&TS_NBIO) { 142517545Skarels splx(s); 14267822Sroot if (uio->uio_resid == cnt) 14278520Sroot return (EWOULDBLOCK); 14288520Sroot return (0); 14297502Sroot } 14307502Sroot tp->t_state |= TS_ASLEEP; 14317502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14329578Ssam splx(s); 14337502Sroot goto loop; 14347502Sroot } 14357502Sroot 14367502Sroot /* 14377502Sroot * Rubout one character from the rawq of tp 14387502Sroot * as cleanly as possible. 14397502Sroot */ 14407502Sroot ttyrub(c, tp) 14417625Ssam register c; 14427625Ssam register struct tty *tp; 14437502Sroot { 14447502Sroot register char *cp; 14457502Sroot register int savecol; 14467502Sroot int s; 14477502Sroot char *nextc(); 14487502Sroot 144935811Smarc if ((tp->t_lflag&ECHO) == 0) 14507502Sroot return; 145135811Smarc tp->t_lflag &= ~FLUSHO; 145235811Smarc if (tp->t_lflag&ECHOE) { 14537502Sroot if (tp->t_rocount == 0) { 14547502Sroot /* 14557502Sroot * Screwed by ttwrite; retype 14567502Sroot */ 14577502Sroot ttyretype(tp); 14587502Sroot return; 14597502Sroot } 146035811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 14617502Sroot ttyrubo(tp, 2); 146235811Smarc else switch (partab[c&=0377]&077) { 14637502Sroot 14647502Sroot case ORDINARY: 146535811Smarc ttyrubo(tp, 1); 14667502Sroot break; 14677502Sroot 14687502Sroot case VTAB: 14697502Sroot case BACKSPACE: 14707502Sroot case CONTROL: 14717502Sroot case RETURN: 147235811Smarc if (tp->t_lflag&ECHOCTL) 14737502Sroot ttyrubo(tp, 2); 14747502Sroot break; 14757502Sroot 147635811Smarc case TAB: { 147735811Smarc int c; 147835811Smarc 14797502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 14807502Sroot ttyretype(tp); 14817502Sroot return; 14827502Sroot } 148317545Skarels s = spltty(); 14847502Sroot savecol = tp->t_col; 14859578Ssam tp->t_state |= TS_CNTTB; 148635811Smarc tp->t_lflag |= FLUSHO; 14877502Sroot tp->t_col = tp->t_rocol; 14889578Ssam cp = tp->t_rawq.c_cf; 148935811Smarc c = *cp; /* XXX FIX NEXTC */ 149035811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 149135811Smarc ttyecho(c, tp); 149235811Smarc tp->t_lflag &= ~FLUSHO; 14939578Ssam tp->t_state &= ~TS_CNTTB; 14947502Sroot splx(s); 14957502Sroot /* 14967502Sroot * savecol will now be length of the tab 14977502Sroot */ 14987502Sroot savecol -= tp->t_col; 14997502Sroot tp->t_col += savecol; 15007502Sroot if (savecol > 8) 15017502Sroot savecol = 8; /* overflow screw */ 15027502Sroot while (--savecol >= 0) 15037502Sroot (void) ttyoutput('\b', tp); 15047502Sroot break; 150535811Smarc } 15067502Sroot 15077502Sroot default: 150835811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 150935811Smarc c, partab[c&=0377]&077); 151035811Smarc /*panic("ttyrub");*/ 15117502Sroot } 151235811Smarc } else if (tp->t_lflag&ECHOPRT) { 15139578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15147502Sroot (void) ttyoutput('\\', tp); 15159578Ssam tp->t_state |= TS_ERASE; 15167502Sroot } 15177502Sroot ttyecho(c, tp); 15187502Sroot } else 151935811Smarc ttyecho(tp->t_cc[VERASE], tp); 15207502Sroot tp->t_rocount--; 15217502Sroot } 15227502Sroot 15237502Sroot /* 15247502Sroot * Crt back over cnt chars perhaps 15257502Sroot * erasing them. 15267502Sroot */ 15277502Sroot ttyrubo(tp, cnt) 15287625Ssam register struct tty *tp; 15297625Ssam int cnt; 15307502Sroot { 15317502Sroot 15327502Sroot while (--cnt >= 0) 153335811Smarc ttyout("\b \b", tp); 15347502Sroot } 15357502Sroot 15367502Sroot /* 15377502Sroot * Reprint the rawq line. 15387502Sroot * We assume c_cc has already been checked. 15397502Sroot */ 15407502Sroot ttyretype(tp) 15417625Ssam register struct tty *tp; 15427502Sroot { 15437502Sroot register char *cp; 15447502Sroot char *nextc(); 154535811Smarc int s, c; 15467502Sroot 154735811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 154835811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 15497502Sroot (void) ttyoutput('\n', tp); 155017545Skarels s = spltty(); 155135811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 155235811Smarc BIT OF FIRST CHAR ****/ 155335811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 155435811Smarc ttyecho(c, tp); 155535811Smarc } 155635811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 155735811Smarc ttyecho(c, tp); 155835811Smarc } 15599578Ssam tp->t_state &= ~TS_ERASE; 15607502Sroot splx(s); 15617502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15627502Sroot tp->t_rocol = 0; 15637502Sroot } 15647502Sroot 15657502Sroot /* 156635811Smarc * Echo a typed character to the terminal. 15677502Sroot */ 15687502Sroot ttyecho(c, tp) 15697625Ssam register c; 15707625Ssam register struct tty *tp; 15717502Sroot { 15729578Ssam if ((tp->t_state&TS_CNTTB) == 0) 157335811Smarc tp->t_lflag &= ~FLUSHO; 157435811Smarc if ((tp->t_lflag&ECHO) == 0 && !(tp->t_lflag&ECHONL && c == '\n')) 15757502Sroot return; 157635811Smarc if (tp->t_lflag&ECHOCTL) { 157735811Smarc if ((c&TTY_CHARMASK)<=037 && c!='\t' && c!='\n' || c==0177) { 15787502Sroot (void) ttyoutput('^', tp); 157935811Smarc c &= TTY_CHARMASK; 15807502Sroot if (c == 0177) 15817502Sroot c = '?'; 15827502Sroot else 15837502Sroot c += 'A' - 1; 15847502Sroot } 15857502Sroot } 158635811Smarc (void) ttyoutput(c, tp); 15877502Sroot } 15887502Sroot 15897502Sroot /* 15907502Sroot * send string cp to tp 15917502Sroot */ 15927502Sroot ttyout(cp, tp) 15937625Ssam register char *cp; 15947625Ssam register struct tty *tp; 15957502Sroot { 15967502Sroot register char c; 15977502Sroot 15987502Sroot while (c = *cp++) 15997502Sroot (void) ttyoutput(c, tp); 16007502Sroot } 16017502Sroot 16027502Sroot ttwakeup(tp) 16037502Sroot struct tty *tp; 16047502Sroot { 16057502Sroot 16067502Sroot if (tp->t_rsel) { 16077502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16087502Sroot tp->t_state &= ~TS_RCOLL; 16097502Sroot tp->t_rsel = 0; 16107502Sroot } 161112752Ssam if (tp->t_state & TS_ASYNC) 161235811Smarc gsignal(tp->t_pgid, SIGIO); 16137502Sroot wakeup((caddr_t)&tp->t_rawq); 16147502Sroot } 161535811Smarc 161635811Smarc /* 161735811Smarc * set tty hi and low water marks 161835811Smarc * 161935811Smarc * Try to arrange the dynamics so there's about one second 162035811Smarc * from hi to low water. 162135811Smarc * 162235811Smarc */ 162335811Smarc ttsetwater(tp) 162435811Smarc struct tty *tp; 162535811Smarc { 162635811Smarc register cps = tp->t_ospeed / 10; 162735811Smarc register x; 162835811Smarc 162935811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 163035811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 163135811Smarc x += cps; 163235811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 163335811Smarc tp->t_hiwat = roundup(x, CBSIZE); 163435811Smarc #undef clamp 163535811Smarc } 163635811Smarc 163735811Smarc ttspeedtab(speed, table) 163835811Smarc struct speedtab table[]; 163935811Smarc { 164035811Smarc register int i; 164135811Smarc 164235811Smarc for (i = 0; table[i].sp_speed != -1; i++) 164335811Smarc if (table[i].sp_speed == speed) 164435811Smarc return(table[i].sp_code); 164535811Smarc return(-1); 164635811Smarc } 1647