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*40030Smarc * @(#)tty.c 7.20 (Berkeley) 02/07/90 723387Smckusick */ 839Sbill 917095Sbloom #include "param.h" 1017095Sbloom #include "systm.h" 1117095Sbloom #include "user.h" 1217095Sbloom #include "ioctl.h" 1339407Smarc #define TTYDEFCHARS 1417095Sbloom #include "tty.h" 1535811Smarc #undef TTYDEFCHARS 1617095Sbloom #include "proc.h" 1717095Sbloom #include "file.h" 1817095Sbloom #include "conf.h" 1929946Skarels #include "dkstat.h" 2017095Sbloom #include "uio.h" 2117095Sbloom #include "kernel.h" 2237728Smckusick #include "vnode.h" 2335811Smarc #include "syslog.h" 2439Sbill 2537525Smckusick #include "machine/reg.h" 2637525Smckusick 277436Skre /* 287436Skre * Table giving parity for characters and indicating 2935811Smarc * character classes to tty driver. The 8th bit 3035811Smarc * indicates parity, the 7th bit indicates the character 3135811Smarc * is an alphameric or underscore (for ALTWERASE), and the 3235811Smarc * low 6 bits indicate delay type. If the low 6 bits are 0 3335811Smarc * then the character needs no special processing on output. 347436Skre */ 3539Sbill 367436Skre char partab[] = { 3735811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* nul - bel */ 3835811Smarc 0202,0004,0003,0201,0005,0206,0201,0001, /* bs - si */ 3935811Smarc 0201,0001,0001,0201,0001,0201,0201,0001, /* dle - etb */ 4035811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* can - us */ 4135811Smarc 0200,0000,0000,0200,0000,0200,0200,0000, /* sp - ' */ 4235811Smarc 0000,0200,0200,0000,0200,0000,0000,0200, /* ( - / */ 4335811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* 0 - 7 */ 4435811Smarc 0300,0100,0000,0200,0000,0200,0200,0000, /* 8 - ? */ 4535811Smarc 0200,0100,0100,0300,0100,0300,0300,0100, /* @ - G */ 4635811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* H - O */ 4735811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* P - W */ 4835811Smarc 0300,0100,0100,0200,0000,0200,0200,0300, /* X - _ */ 4935811Smarc 0000,0300,0300,0100,0300,0100,0100,0300, /* ` - g */ 5035811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* h - o */ 5135811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* p - w */ 5235811Smarc 0100,0300,0300,0000,0200,0000,0000,0201, /* x - del */ 537436Skre /* 5435811Smarc * meta chars 557436Skre */ 5635811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* nul - bel */ 5735811Smarc 0202,0004,0003,0201,0005,0206,0201,0001, /* bs - si */ 5835811Smarc 0201,0001,0001,0201,0001,0201,0201,0001, /* dle - etb */ 5935811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* can - us */ 6035811Smarc 0200,0000,0000,0200,0000,0200,0200,0000, /* sp - ' */ 6135811Smarc 0000,0200,0200,0000,0200,0000,0000,0200, /* ( - / */ 6235811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* 0 - 7 */ 6335811Smarc 0300,0100,0000,0200,0000,0200,0200,0000, /* 8 - ? */ 6435811Smarc 0200,0100,0100,0300,0100,0300,0300,0100, /* @ - G */ 6535811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* H - O */ 6635811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* P - W */ 6735811Smarc 0300,0100,0100,0200,0000,0200,0200,0300, /* X - _ */ 6835811Smarc 0000,0300,0300,0100,0300,0100,0100,0300, /* ` - g */ 6935811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* h - o */ 7035811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* p - w */ 7135811Smarc 0100,0300,0300,0000,0200,0000,0000,0201, /* x - del */ 727436Skre }; 737436Skre 7435811Smarc extern struct tty *constty; /* temporary virtual console */ 7535811Smarc extern char partab[], maptab[]; 7635811Smarc 77146Sbill /* 7835811Smarc * Is 'c' a line delimiter ("break" character)? 7939Sbill */ 8035811Smarc #define ttbreakc(c) (c == '\n' || CCEQ(cc[VEOF], c) || \ 8135811Smarc CCEQ(cc[VEOL], c) || CCEQ(cc[VEOL2], c)) 8239Sbill 8339Sbill ttychars(tp) 849578Ssam struct tty *tp; 8539Sbill { 8635811Smarc bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 8739Sbill } 8839Sbill 8939Sbill /* 90903Sbill * Wait for output to drain, then flush input waiting. 9139Sbill */ 9212752Ssam ttywflush(tp) 9337584Smarc struct tty *tp; 9439Sbill { 9539Sbill 9612752Ssam ttywait(tp); 9712752Ssam ttyflush(tp, FREAD); 9812752Ssam } 9912752Ssam 10035811Smarc /* 10135811Smarc * Wait for output to drain. 10235811Smarc */ 10312752Ssam ttywait(tp) 10412752Ssam register struct tty *tp; 10512752Ssam { 10637584Smarc int s = spltty(); 10712752Ssam 10813809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 10937584Smarc (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 11037584Smarc tp->t_oproc) { 111903Sbill (*tp->t_oproc)(tp); 1125408Swnj tp->t_state |= TS_ASLEEP; 113903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 114903Sbill } 1159859Ssam splx(s); 11639Sbill } 11739Sbill 11839Sbill /* 1199578Ssam * Flush all TTY queues 12039Sbill */ 12112752Ssam ttyflush(tp, rw) 1227625Ssam register struct tty *tp; 12339Sbill { 124903Sbill register s; 125903Sbill 12617545Skarels s = spltty(); 127903Sbill if (rw & FREAD) { 128903Sbill while (getc(&tp->t_canq) >= 0) 129903Sbill ; 13037584Smarc ttwakeup(tp); 131903Sbill } 132903Sbill if (rw & FWRITE) { 13337584Smarc wakeup((caddr_t)&tp->t_outq); /* XXX? what about selwakeup? */ 1345408Swnj tp->t_state &= ~TS_TTSTOP; 1355426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 136903Sbill while (getc(&tp->t_outq) >= 0) 137903Sbill ; 138903Sbill } 139903Sbill if (rw & FREAD) { 140903Sbill while (getc(&tp->t_rawq) >= 0) 141903Sbill ; 1429578Ssam tp->t_rocount = 0; 143903Sbill tp->t_rocol = 0; 1449578Ssam tp->t_state &= ~TS_LOCAL; 145903Sbill } 146903Sbill splx(s); 14739Sbill } 14839Sbill 149903Sbill /* 150903Sbill * Send stop character on input overflow. 151903Sbill */ 152903Sbill ttyblock(tp) 1537625Ssam register struct tty *tp; 15439Sbill { 155903Sbill register x; 1569578Ssam 157903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 158903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 15912752Ssam ttyflush(tp, FREAD|FWRITE); 1605408Swnj tp->t_state &= ~TS_TBLOCK; 161903Sbill } 16215118Skarels /* 16315118Skarels * Block further input iff: 16415118Skarels * Current input > threshold AND input is available to user program 16515118Skarels */ 16616055Skarels if (x >= TTYHOG/2 && 16735811Smarc (!(tp->t_lflag&ICANON)) || (tp->t_canq.c_cc > 0) && 16835811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 16935811Smarc if (putc(tp->t_cc[VSTOP], &tp->t_outq)==0) { 17015118Skarels tp->t_state |= TS_TBLOCK; 17115118Skarels ttstart(tp); 17215118Skarels } 173903Sbill } 17439Sbill } 17539Sbill 17639Sbill /* 177903Sbill * Restart typewriter output following a delay 178903Sbill * timeout. 179903Sbill * The name of the routine is passed to the timeout 180903Sbill * subroutine and it is called during a clock interrupt. 181121Sbill */ 182903Sbill ttrstrt(tp) 18337584Smarc struct tty *tp; 184121Sbill { 185121Sbill 1869578Ssam if (tp == 0) 1879578Ssam panic("ttrstrt"); 1885408Swnj tp->t_state &= ~TS_TIMEOUT; 189903Sbill ttstart(tp); 190121Sbill } 191121Sbill 192121Sbill /* 193903Sbill * Start output on the typewriter. It is used from the top half 194903Sbill * after some characters have been put on the output queue, 195903Sbill * from the interrupt routine to transmit the next 196903Sbill * character, and after a timeout has finished. 19739Sbill */ 198903Sbill ttstart(tp) 19937584Smarc struct tty *tp; 20039Sbill { 20139Sbill 20232067Skarels if (tp->t_oproc) /* kludge for pty */ 203903Sbill (*tp->t_oproc)(tp); 20439Sbill } 20539Sbill 20639Sbill /* 207903Sbill * Common code for tty ioctls. 20839Sbill */ 2091780Sbill /*ARGSUSED*/ 2107625Ssam ttioctl(tp, com, data, flag) 2117625Ssam register struct tty *tp; 2127625Ssam caddr_t data; 21339Sbill { 21439Sbill extern int nldisp; 21537554Smckusick int s, error; 21639Sbill 217903Sbill /* 218903Sbill * If the ioctl involves modification, 21917545Skarels * hang if in the background. 220903Sbill */ 2217625Ssam switch (com) { 22239Sbill 22335811Smarc case TIOCSETD: 224903Sbill case TIOCFLUSH: 22535811Smarc /*case TIOCSPGRP:*/ 2269325Ssam case TIOCSTI: 22717598Sbloom case TIOCSWINSZ: 22835811Smarc case TIOCSETA: 22935811Smarc case TIOCSETAW: 23035811Smarc case TIOCSETAF: 23139407Smarc /**** these get removed **** 23235811Smarc case TIOCSETAS: 23335811Smarc case TIOCSETAWS: 23435811Smarc case TIOCSETAFS: 23539407Smarc /***************************/ 236*40030Smarc #ifdef COMPAT_43 237*40030Smarc case TIOCSETP: 238*40030Smarc case TIOCSETN: 239*40030Smarc case TIOCSETC: 240*40030Smarc case TIOCSLTC: 241*40030Smarc case TIOCLBIS: 242*40030Smarc case TIOCLBIC: 243*40030Smarc case TIOCLSET: 244*40030Smarc case OTIOCSETD: 245*40030Smarc #endif 24639555Smarc while (isbackground(u.u_procp, tp) && 24735811Smarc u.u_procp->p_pgrp->pg_jobc && 248903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 24924392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 25024392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 25135811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU); 252903Sbill sleep((caddr_t)&lbolt, TTOPRI); 253903Sbill } 254903Sbill break; 255903Sbill } 256903Sbill 2579578Ssam /* 2589578Ssam * Process the ioctl. 2599578Ssam */ 2607625Ssam switch (com) { 261903Sbill 2628556Sroot /* get discipline number */ 26339Sbill case TIOCGETD: 2647625Ssam *(int *)data = tp->t_line; 26539Sbill break; 26639Sbill 2678556Sroot /* set line discipline */ 2687625Ssam case TIOCSETD: { 2697625Ssam register int t = *(int *)data; 27035811Smarc dev_t dev = tp->t_dev; 2719578Ssam int error = 0; 2727625Ssam 27335811Smarc if ((unsigned)t >= nldisp) 27410851Ssam return (ENXIO); 27525584Skarels if (t != tp->t_line) { 27625584Skarels s = spltty(); 27725584Skarels (*linesw[tp->t_line].l_close)(tp); 27825584Skarels error = (*linesw[t].l_open)(dev, tp); 27925584Skarels if (error) { 28035811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 28125584Skarels splx(s); 28225584Skarels return (error); 28325584Skarels } 28425584Skarels tp->t_line = t; 28510851Ssam splx(s); 28610851Ssam } 28739Sbill break; 2887625Ssam } 28939Sbill 2908556Sroot /* prevent more opens on channel */ 2915614Swnj case TIOCEXCL: 2925614Swnj tp->t_state |= TS_XCLUDE; 2935614Swnj break; 2945614Swnj 2955614Swnj case TIOCNXCL: 2965614Swnj tp->t_state &= ~TS_XCLUDE; 2975614Swnj break; 2985614Swnj 29939Sbill case TIOCHPCL: 30035811Smarc tp->t_cflag |= HUPCL; 30139Sbill break; 30239Sbill 3033942Sbugs case TIOCFLUSH: { 3047625Ssam register int flags = *(int *)data; 3057625Ssam 3067625Ssam if (flags == 0) 3073942Sbugs flags = FREAD|FWRITE; 3087625Ssam else 3097625Ssam flags &= FREAD|FWRITE; 31012752Ssam ttyflush(tp, flags); 31139Sbill break; 3123944Sbugs } 31339Sbill 31437584Smarc case FIOASYNC: 31537584Smarc if (*(int *)data) 31637584Smarc tp->t_state |= TS_ASYNC; 31737584Smarc else 31837584Smarc tp->t_state &= ~TS_ASYNC; 31937584Smarc break; 32037584Smarc 32137584Smarc case FIONBIO: 32237584Smarc break; /* XXX remove */ 32337584Smarc 3248556Sroot /* return number of characters immediately available */ 3257625Ssam case FIONREAD: 3267625Ssam *(off_t *)data = ttnread(tp); 327174Sbill break; 328174Sbill 32913077Ssam case TIOCOUTQ: 33013077Ssam *(int *)data = tp->t_outq.c_cc; 33113077Ssam break; 33213077Ssam 3338589Sroot case TIOCSTOP: 33417545Skarels s = spltty(); 3359578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3365573Swnj tp->t_state |= TS_TTSTOP; 3375573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3385573Swnj } 3397625Ssam splx(s); 3405573Swnj break; 3415573Swnj 3428589Sroot case TIOCSTART: 34317545Skarels s = spltty(); 34435811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 3455573Swnj tp->t_state &= ~TS_TTSTOP; 34635811Smarc tp->t_lflag &= ~FLUSHO; 3475573Swnj ttstart(tp); 3485573Swnj } 3497625Ssam splx(s); 3505573Swnj break; 3515573Swnj 3529325Ssam /* 3539325Ssam * Simulate typing of a character at the terminal. 3549325Ssam */ 3559325Ssam case TIOCSTI: 35617183Smckusick if (u.u_uid && (flag & FREAD) == 0) 35717183Smckusick return (EPERM); 35839555Smarc if (u.u_uid && !isctty(u.u_procp, tp)) 3599325Ssam return (EACCES); 3609578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3619325Ssam break; 3629325Ssam 36335811Smarc case TIOCGETA: { 36435811Smarc struct termios *t = (struct termios *)data; 36512752Ssam 36635811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 36735811Smarc break; 36835811Smarc } 36935811Smarc 37039407Smarc /*** THIS ALL GETS REMOVED ***/ 37139407Smarc case JUNK_TIOCSETAS: 37239407Smarc case JUNK_TIOCSETAWS: 37339407Smarc case JUNK_TIOCSETAFS: 37439407Smarc ((struct termios *)data)->c_cflag |= CIGNORE; 37539407Smarc switch(com) { 37639407Smarc case JUNK_TIOCSETAS: 37739407Smarc com = TIOCSETA; 37839407Smarc break; 37939407Smarc case JUNK_TIOCSETAWS: 38039407Smarc com = TIOCSETAW; 38139407Smarc break; 38239407Smarc case JUNK_TIOCSETAFS: 38339407Smarc com = TIOCSETAF; 38439407Smarc break; 38539407Smarc } 38639407Smarc /*******************************/ 38739407Smarc /*FALLTHROGH*/ 38835811Smarc case TIOCSETA: 38935811Smarc case TIOCSETAW: 39037584Smarc case TIOCSETAF: { 39135811Smarc register struct termios *t = (struct termios *)data; 39217545Skarels s = spltty(); 39339407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 39439407Smarc ttywait(tp); 39539407Smarc if (com == TIOCSETAF); 39639407Smarc ttyflush(tp, FREAD); 39739407Smarc } 39839407Smarc if (!(t->c_cflag&CIGNORE)) { 39935811Smarc /* 40035811Smarc * set device hardware 40135811Smarc */ 40237584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 40337584Smarc splx(s); 40435811Smarc return (error); 40537584Smarc } else { 40637584Smarc if (!(tp->t_state&TS_CARR_ON) && 40737584Smarc (tp->t_cflag&CLOCAL) && 40837584Smarc !(t->c_cflag&CLOCAL)) { 40937584Smarc tp->t_state &= ~TS_ISOPEN; 41037584Smarc tp->t_state |= TS_WOPEN; 41137584Smarc ttwakeup(tp); 41237584Smarc } 41335811Smarc tp->t_cflag = t->c_cflag; 41435811Smarc tp->t_ispeed = t->c_ispeed; 41535811Smarc tp->t_ospeed = t->c_ospeed; 41634492Skarels } 41735811Smarc ttsetwater(tp); 41812752Ssam } 41939407Smarc if (com != TIOCSETAF) { 42035811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 42135811Smarc if (t->c_lflag&ICANON) { 42235811Smarc tp->t_lflag |= PENDIN; 42335811Smarc ttwakeup(tp); 42435811Smarc } 42535811Smarc else { 42635811Smarc struct clist tq; 42735811Smarc 42835811Smarc catq(&tp->t_rawq, &tp->t_canq); 42935811Smarc tq = tp->t_rawq; 43035811Smarc tp->t_rawq = tp->t_canq; 43135811Smarc tp->t_canq = tq; 43235811Smarc } 43312752Ssam } 43435811Smarc tp->t_iflag = t->c_iflag; 43535811Smarc tp->t_oflag = t->c_oflag; 43635811Smarc tp->t_lflag = t->c_lflag; 43735811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 43812752Ssam splx(s); 43912752Ssam break; 44012752Ssam } 44112752Ssam 44212752Ssam /* 44339555Smarc * Set controlling terminal. 44439555Smarc * Session ctty vnode pointer set in vnode layer. 44534492Skarels */ 44635811Smarc case TIOCSCTTY: { 44735811Smarc register struct proc *p = u.u_procp; 44834492Skarels 44939555Smarc if (!SESS_LEADER(p) || 45039555Smarc (p->p_session->s_ttyvp || tp->t_session) && 45139555Smarc (tp->t_session != p->p_session)) 45239407Smarc return (EPERM); 45335811Smarc tp->t_session = p->p_session; 45439555Smarc tp->t_pgrp = p->p_pgrp; 45539555Smarc p->p_session->s_ttyp = tp; 45639555Smarc p->p_flag |= SCTTY; 45734492Skarels break; 45835811Smarc } 45939555Smarc 46034492Skarels /* 46135811Smarc * Set terminal process group. 46217545Skarels */ 46318650Sbloom case TIOCSPGRP: { 46435811Smarc register struct proc *p = u.u_procp; 46535811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 46617545Skarels 46739555Smarc if (!isctty(p, tp)) 46839555Smarc return (ENOTTY); 469*40030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 47039555Smarc return (EPERM); 47139555Smarc tp->t_pgrp = pgrp; 47212752Ssam break; 47318650Sbloom } 47412752Ssam 47512752Ssam case TIOCGPGRP: 47639555Smarc if (!isctty(u.u_procp, tp)) 47739555Smarc return (ENOTTY); 47839555Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 47912752Ssam break; 48012752Ssam 48117598Sbloom case TIOCSWINSZ: 48218650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 48318650Sbloom sizeof (struct winsize))) { 48417598Sbloom tp->t_winsize = *(struct winsize *)data; 48539555Smarc pgsignal(tp->t_pgrp, SIGWINCH); 48617598Sbloom } 48717598Sbloom break; 48817598Sbloom 48917598Sbloom case TIOCGWINSZ: 49017598Sbloom *(struct winsize *)data = tp->t_winsize; 49117598Sbloom break; 49217598Sbloom 49330534Skarels case TIOCCONS: 49430534Skarels if (*(int *)data) { 49530534Skarels if (constty != NULL) 49630534Skarels return (EBUSY); 49730534Skarels #ifndef UCONSOLE 49837554Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 49937554Smckusick return (error); 50030534Skarels #endif 50130534Skarels constty = tp; 50230534Skarels } else if (tp == constty) 50333404Skarels constty = NULL; 50430534Skarels break; 50530534Skarels 50635811Smarc #ifdef COMPAT_43 50735811Smarc case TIOCGETP: 50835811Smarc case TIOCSETP: 50935811Smarc case TIOCSETN: 51035811Smarc case TIOCGETC: 51135811Smarc case TIOCSETC: 51235811Smarc case TIOCSLTC: 51335811Smarc case TIOCGLTC: 51435811Smarc case TIOCLBIS: 51535811Smarc case TIOCLBIC: 51635811Smarc case TIOCLSET: 51735811Smarc case TIOCLGET: 51839407Smarc case OTIOCGETD: 51939407Smarc case OTIOCSETD: 52035811Smarc return(ttcompat(tp, com, data, flag)); 52135811Smarc #endif 52235811Smarc 52339Sbill default: 5248556Sroot return (-1); 52539Sbill } 5268556Sroot return (0); 52739Sbill } 5284484Swnj 5294484Swnj ttnread(tp) 5304484Swnj struct tty *tp; 5314484Swnj { 5324484Swnj int nread = 0; 5334484Swnj 53435811Smarc if (tp->t_lflag & PENDIN) 5354484Swnj ttypend(tp); 5364484Swnj nread = tp->t_canq.c_cc; 53735811Smarc if ((tp->t_lflag & ICANON) == 0) 5384484Swnj nread += tp->t_rawq.c_cc; 5394484Swnj return (nread); 5404484Swnj } 5414484Swnj 5425408Swnj ttselect(dev, rw) 5434484Swnj dev_t dev; 5445408Swnj int rw; 5454484Swnj { 5464484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5474484Swnj int nread; 54817545Skarels int s = spltty(); 5494484Swnj 5505408Swnj switch (rw) { 5514484Swnj 5524484Swnj case FREAD: 5534484Swnj nread = ttnread(tp); 55437584Smarc if (nread > 0 || 55537584Smarc (!(tp->t_cflag&CLOCAL) && !(tp->t_state&TS_CARR_ON))) 5565408Swnj goto win; 5574938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5585408Swnj tp->t_state |= TS_RCOLL; 5594484Swnj else 5604484Swnj tp->t_rsel = u.u_procp; 5615408Swnj break; 5624484Swnj 5635408Swnj case FWRITE: 56435811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 5655408Swnj goto win; 5665408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5675408Swnj tp->t_state |= TS_WCOLL; 5685408Swnj else 5695408Swnj tp->t_wsel = u.u_procp; 5705408Swnj break; 5714484Swnj } 5725408Swnj splx(s); 5735408Swnj return (0); 5745408Swnj win: 5755408Swnj splx(s); 5765408Swnj return (1); 5774484Swnj } 5787436Skre 5797502Sroot /* 58025391Skarels * Initial open of tty, or (re)entry to line discipline. 5817502Sroot */ 5827502Sroot ttyopen(dev, tp) 5837625Ssam dev_t dev; 5847625Ssam register struct tty *tp; 5857502Sroot { 5867502Sroot 5877502Sroot tp->t_dev = dev; 58835811Smarc 5897502Sroot tp->t_state &= ~TS_WOPEN; 59017545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 59117545Skarels tp->t_state |= TS_ISOPEN; 59217598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 59317545Skarels } 5948556Sroot return (0); 5957502Sroot } 5967502Sroot 5977502Sroot /* 59825391Skarels * "close" a line discipline 59925391Skarels */ 60025391Skarels ttylclose(tp) 60125391Skarels register struct tty *tp; 60225391Skarels { 60325391Skarels 60425391Skarels ttywflush(tp); 60525391Skarels } 60625391Skarels 60725391Skarels /* 6087502Sroot * clean tp on last close 6097502Sroot */ 6107502Sroot ttyclose(tp) 6117625Ssam register struct tty *tp; 6127502Sroot { 61330534Skarels if (constty == tp) 61430534Skarels constty = NULL; 61525391Skarels ttyflush(tp, FREAD|FWRITE); 61639555Smarc tp->t_session = NULL; 61739555Smarc tp->t_pgrp = NULL; 6187502Sroot tp->t_state = 0; 6197502Sroot } 6207502Sroot 6217502Sroot /* 62225391Skarels * Handle modem control transition on a tty. 62325391Skarels * Flag indicates new state of carrier. 62425391Skarels * Returns 0 if the line should be turned off, otherwise 1. 62525391Skarels */ 62625391Skarels ttymodem(tp, flag) 62725391Skarels register struct tty *tp; 62825391Skarels { 62925391Skarels 63035811Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag & MDMBUF)) { 63125391Skarels /* 63225391Skarels * MDMBUF: do flow control according to carrier flag 63325391Skarels */ 63425391Skarels if (flag) { 63525391Skarels tp->t_state &= ~TS_TTSTOP; 63625391Skarels ttstart(tp); 63725391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 63825391Skarels tp->t_state |= TS_TTSTOP; 63925391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 64025391Skarels } 64125391Skarels } else if (flag == 0) { 64225391Skarels /* 64325391Skarels * Lost carrier. 64425391Skarels */ 64525391Skarels tp->t_state &= ~TS_CARR_ON; 64625391Skarels if (tp->t_state & TS_ISOPEN) { 64735811Smarc if ((tp->t_lflag & NOHANG) == 0) { 64839555Smarc pgsignal(tp->t_pgrp, SIGHUP); 64939555Smarc pgsignal(tp->t_pgrp, SIGCONT); 65025391Skarels ttyflush(tp, FREAD|FWRITE); 65125391Skarels return (0); 65225391Skarels } 65325391Skarels } 65425391Skarels } else { 65525391Skarels /* 65625391Skarels * Carrier now on. 65725391Skarels */ 65825391Skarels tp->t_state |= TS_CARR_ON; 65937584Smarc ttwakeup(tp); 66025391Skarels } 66125391Skarels return (1); 66225391Skarels } 66325391Skarels 66425391Skarels /* 66525404Skarels * Default modem control routine (for other line disciplines). 66625404Skarels * Return argument flag, to turn off device on carrier drop. 66725404Skarels */ 66825415Skarels nullmodem(tp, flag) 66925415Skarels register struct tty *tp; 67025404Skarels int flag; 67125404Skarels { 67225404Skarels 67325404Skarels if (flag) 67425404Skarels tp->t_state |= TS_CARR_ON; 67539407Smarc else { 67625404Skarels tp->t_state &= ~TS_CARR_ON; 67739407Smarc if ((tp->t_lflag & NOHANG) == 0) 67839555Smarc pgsignal(tp->t_pgrp, SIGHUP); 67939407Smarc } 68025404Skarels return (flag); 68125404Skarels } 68225404Skarels 68325404Skarels /* 6847502Sroot * reinput pending characters after state switch 68517545Skarels * call at spltty(). 6867502Sroot */ 6877502Sroot ttypend(tp) 6887625Ssam register struct tty *tp; 6897502Sroot { 6907502Sroot struct clist tq; 6917502Sroot register c; 6927502Sroot 69335811Smarc tp->t_lflag &= ~PENDIN; 6949578Ssam tp->t_state |= TS_TYPEN; 6957502Sroot tq = tp->t_rawq; 6967502Sroot tp->t_rawq.c_cc = 0; 6977502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6987502Sroot while ((c = getc(&tq)) >= 0) 6997502Sroot ttyinput(c, tp); 7009578Ssam tp->t_state &= ~TS_TYPEN; 7017502Sroot } 7027502Sroot 7037502Sroot /* 70435811Smarc * 7059578Ssam * Place a character on raw TTY input queue, 7069578Ssam * putting in delimiters and waking up top 7079578Ssam * half as needed. Also echo if required. 7089578Ssam * The arguments are the character and the 7099578Ssam * appropriate tty structure. 7107502Sroot */ 7117502Sroot ttyinput(c, tp) 7127625Ssam register c; 7137625Ssam register struct tty *tp; 7147502Sroot { 71535811Smarc register int iflag = tp->t_iflag; 71635811Smarc register int lflag = tp->t_lflag; 71735811Smarc register u_char *cc = tp->t_cc; 71835811Smarc int i, err; 7197502Sroot 7209578Ssam /* 7219578Ssam * If input is pending take it first. 7229578Ssam */ 72335811Smarc if (lflag&PENDIN) 7247502Sroot ttypend(tp); 72535811Smarc /* 72635811Smarc * Gather stats. 72735811Smarc */ 7287502Sroot tk_nin++; 72935811Smarc if (lflag&ICANON) { 73035811Smarc tk_cancc++; 73135811Smarc tp->t_cancc++; 73235811Smarc } else { 73335811Smarc tk_rawcc++; 73435811Smarc tp->t_rawcc++; 73535811Smarc } 7369578Ssam /* 73735811Smarc * Handle exceptional conditions (break, parity, framing). 7389578Ssam */ 73935811Smarc if (err = (c&TTY_ERRORMASK)) { 74035811Smarc c &= ~TTY_ERRORMASK; 74135811Smarc if (err&TTY_FE && !c) { /* break */ 74235811Smarc if (iflag&IGNBRK) 74335811Smarc goto endcase; 74435811Smarc else if (iflag&BRKINT && lflag&ISIG && 74535811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 74635811Smarc c = cc[VINTR]; 74735811Smarc else { 74835811Smarc c = 0; 74935811Smarc if (iflag&PARMRK) 75035811Smarc goto parmrk; 75135811Smarc } 75235811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 75335811Smarc if (iflag&IGNPAR) 75435811Smarc goto endcase; 75535811Smarc else if (iflag&PARMRK) { 75635811Smarc parmrk: 75735811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 75835811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 75935811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 76035811Smarc goto endcase; 76135811Smarc } else 76235811Smarc c = 0; 7637502Sroot } 7649578Ssam } 7659578Ssam /* 76635811Smarc * In tandem mode, check high water mark. 7679578Ssam */ 76835811Smarc if (iflag&IXOFF) 76935811Smarc ttyblock(tp); 77035811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 7719578Ssam c &= 0177; 7729578Ssam /* 7739578Ssam * Check for literal nexting very first 7749578Ssam */ 7759578Ssam if (tp->t_state&TS_LNCH) { 77635811Smarc c |= TTY_QUOTE; 7779578Ssam tp->t_state &= ~TS_LNCH; 7789578Ssam } 7799578Ssam /* 7809578Ssam * Scan for special characters. This code 7819578Ssam * is really just a big case statement with 7829578Ssam * non-constant cases. The bottom of the 7839578Ssam * case statement is labeled ``endcase'', so goto 7849578Ssam * it after a case match, or similar. 7859578Ssam */ 78635811Smarc /* 78735811Smarc * Control chars which aren't controlled 78835811Smarc * by ICANON, ISIG, or IXON. 78935811Smarc */ 79039407Smarc if (lflag&IEXTEN) { 79135811Smarc if (CCEQ(cc[VLNEXT],c)) { 79235811Smarc if (lflag&ECHO) { 79335811Smarc if (lflag&ECHOE) 79435811Smarc ttyout("^\b", tp); 79535811Smarc else 79635811Smarc ttyecho(c, tp); 79735811Smarc } 7989578Ssam tp->t_state |= TS_LNCH; 7999578Ssam goto endcase; 8009578Ssam } 80135811Smarc if (CCEQ(cc[VFLUSHO],c)) { 80235811Smarc if (lflag&FLUSHO) 80335811Smarc tp->t_lflag &= ~FLUSHO; 8047502Sroot else { 80512752Ssam ttyflush(tp, FWRITE); 8067502Sroot ttyecho(c, tp); 8079578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 8087502Sroot ttyretype(tp); 80935811Smarc tp->t_lflag |= FLUSHO; 8107502Sroot } 8119578Ssam goto startoutput; 8129578Ssam } 81335811Smarc } 81435811Smarc /* 81535811Smarc * Signals. 81635811Smarc */ 81735811Smarc if (lflag&ISIG) { 81835811Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 81935811Smarc if ((lflag&NOFLSH) == 0) 82035811Smarc ttyflush(tp, FREAD|FWRITE); 82135811Smarc ttyecho(c, tp); 82239555Smarc pgsignal(tp->t_pgrp, 82339555Smarc CCEQ(cc[VINTR],c) ? SIGINT : SIGQUIT); 82435811Smarc goto endcase; 82535811Smarc } 82635811Smarc if (CCEQ(cc[VSUSP],c)) { 82735811Smarc if ((lflag&NOFLSH) == 0) 82812752Ssam ttyflush(tp, FREAD); 8299578Ssam ttyecho(c, tp); 83039555Smarc pgsignal(tp->t_pgrp, SIGTSTP); 8319578Ssam goto endcase; 8329578Ssam } 83339407Smarc if (CCEQ(cc[VINFO],c)) { 83439407Smarc ttyinfo(tp); 83539407Smarc goto endcase; 83639407Smarc } 8379578Ssam } 8389578Ssam /* 8399578Ssam * Handle start/stop characters. 8409578Ssam */ 84135811Smarc if (iflag&IXON) { 84235811Smarc if (CCEQ(cc[VSTOP],c)) { 84335811Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 84435811Smarc tp->t_state |= TS_TTSTOP; 84535811Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 84635811Smarc return; 84735811Smarc } 84835811Smarc if (!CCEQ(cc[VSTART], c)) 84935811Smarc return; 85035811Smarc /* 85135811Smarc * if VSTART == VSTOP then toggle 85235811Smarc */ 85335811Smarc goto endcase; 8549578Ssam } 85535811Smarc if (CCEQ(cc[VSTART], c)) 85635811Smarc goto restartoutput; 8579578Ssam } 8589578Ssam /* 85935811Smarc * IGNCR, ICRNL, & INLCR 8609578Ssam */ 86135811Smarc if (c == '\r') { 86235811Smarc if (iflag&IGNCR) 86335811Smarc goto endcase; 86435811Smarc else if (iflag&ICRNL) 86535811Smarc c = '\n'; 8669578Ssam } 86735811Smarc else if (c == '\n' && iflag&INLCR) 86835811Smarc c = '\r'; 8699578Ssam /* 87035811Smarc * Non canonical mode; don't process line editing 8719578Ssam * characters; check high water mark for wakeup. 87235811Smarc * 8739578Ssam */ 87435811Smarc if (!(lflag&ICANON)) { 8759578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 87635811Smarc if (iflag&IMAXBEL) { 87735811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 87835811Smarc (void) ttyoutput(CTRL('g'), tp); 87935811Smarc } else 88035811Smarc ttyflush(tp, FREAD | FWRITE); 88135811Smarc } else { 88235811Smarc if (putc(c, &tp->t_rawq) >= 0) { 88335811Smarc ttwakeup(tp); 88435811Smarc ttyecho(c, tp); 88535811Smarc } 8867502Sroot } 8879578Ssam goto endcase; 8889578Ssam } 8899578Ssam /* 89035811Smarc * From here on down canonical mode character 8919578Ssam * processing takes place. 8929578Ssam */ 89335811Smarc /* 89435811Smarc * erase (^H / ^?) 89535811Smarc */ 89639407Smarc if (CCEQ(cc[VERASE], c)) { 8979578Ssam if (tp->t_rawq.c_cc) 8989578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8999578Ssam goto endcase; 9009578Ssam } 90135811Smarc /* 90235811Smarc * kill (^U) 90335811Smarc */ 90435811Smarc if (CCEQ(cc[VKILL], c)) { 90537584Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 90637584Smarc !(lflag&ECHOPRT)) { 9079578Ssam while (tp->t_rawq.c_cc) 9089578Ssam ttyrub(unputc(&tp->t_rawq), tp); 9099578Ssam } else { 9109578Ssam ttyecho(c, tp); 91135811Smarc if (lflag&ECHOK || lflag&ECHOKE) 91235811Smarc ttyecho('\n', tp); 9139578Ssam while (getc(&tp->t_rawq) > 0) 9149578Ssam ; 9159578Ssam tp->t_rocount = 0; 9169578Ssam } 9179578Ssam tp->t_state &= ~TS_LOCAL; 9189578Ssam goto endcase; 9199578Ssam } 9209578Ssam /* 92135811Smarc * word erase (^W) 9229578Ssam */ 92335811Smarc if (CCEQ(cc[VWERASE], c)) { 92435811Smarc int ctype; 92535811Smarc 92635811Smarc #define CTYPE(c) ((lflag&ALTWERASE) ? (partab[(c)&TTY_CHARMASK]&0100) : 0) 92735811Smarc /* 92835811Smarc * erase whitespace 92935811Smarc */ 93035811Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 93135811Smarc ttyrub(c, tp); 93235811Smarc if (c == -1) 93334492Skarels goto endcase; 93435811Smarc /* 93535811Smarc * special case last char of token 93635811Smarc */ 93735811Smarc ttyrub(c, tp); 93835811Smarc c = unputc(&tp->t_rawq); 93935811Smarc if (c == -1 || c == ' ' || c == '\t') { 94035811Smarc if (c != -1) 94135811Smarc (void) putc(c, &tp->t_rawq); 94234492Skarels goto endcase; 94334492Skarels } 94435811Smarc /* 94535811Smarc * erase rest of token 94635811Smarc */ 94735811Smarc ctype = CTYPE(c); 94835811Smarc do { 94935811Smarc ttyrub(c, tp); 95035811Smarc c = unputc(&tp->t_rawq); 95135811Smarc if (c == -1) 95235811Smarc goto endcase; 95335811Smarc } while (c != ' ' && c != '\t' && CTYPE(c) == ctype); 95435811Smarc (void) putc(c, &tp->t_rawq); 95535811Smarc goto endcase; 95635811Smarc #undef CTYPE 9579578Ssam } 9589578Ssam /* 95935811Smarc * reprint line (^R) 96035811Smarc */ 96135811Smarc if (CCEQ(cc[VREPRINT], c)) { 96235811Smarc ttyretype(tp); 96335811Smarc goto endcase; 96435811Smarc } 96535811Smarc /* 9669578Ssam * Check for input buffer overflow 9679578Ssam */ 96810391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 96935811Smarc if (iflag&IMAXBEL) { 97035811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 97135811Smarc (void) ttyoutput(CTRL('g'), tp); 97235811Smarc } else 97335811Smarc ttyflush(tp, FREAD | FWRITE); 9749578Ssam goto endcase; 97510391Ssam } 9769578Ssam /* 9779578Ssam * Put data char in q for user and 9789578Ssam * wakeup on seeing a line delimiter. 9799578Ssam */ 9809578Ssam if (putc(c, &tp->t_rawq) >= 0) { 98135811Smarc if (ttbreakc(c)) { 9829578Ssam tp->t_rocount = 0; 9839578Ssam catq(&tp->t_rawq, &tp->t_canq); 9847502Sroot ttwakeup(tp); 9859578Ssam } else if (tp->t_rocount++ == 0) 9869578Ssam tp->t_rocol = tp->t_col; 9879578Ssam if (tp->t_state&TS_ERASE) { 98835811Smarc /* 98935811Smarc * end of prterase \.../ 99035811Smarc */ 9919578Ssam tp->t_state &= ~TS_ERASE; 9929578Ssam (void) ttyoutput('/', tp); 9939578Ssam } 9949578Ssam i = tp->t_col; 9957502Sroot ttyecho(c, tp); 99635811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 99735811Smarc /* 99835811Smarc * Place the cursor over the '^' of the ^D. 99935811Smarc */ 10009578Ssam i = MIN(2, tp->t_col - i); 10019578Ssam while (i > 0) { 10029578Ssam (void) ttyoutput('\b', tp); 10039578Ssam i--; 10049578Ssam } 10059578Ssam } 10067502Sroot } 10079578Ssam endcase: 10089578Ssam /* 100935811Smarc * IXANY means allow any character to restart output. 10109578Ssam */ 101135811Smarc if ((tp->t_state&TS_TTSTOP) && !(iflag&IXANY) 101235811Smarc && cc[VSTART] != cc[VSTOP]) 10137502Sroot return; 10149578Ssam restartoutput: 10157502Sroot tp->t_state &= ~TS_TTSTOP; 101635811Smarc tp->t_lflag &= ~FLUSHO; 10179578Ssam startoutput: 10187502Sroot ttstart(tp); 10197502Sroot } 10207502Sroot 10217502Sroot /* 10229578Ssam * Put character on TTY output queue, adding delays, 10237502Sroot * expanding tabs, and handling the CR/NL bit. 10249578Ssam * This is called both from the top half for output, 10259578Ssam * and from interrupt level for echoing. 10267502Sroot * The arguments are the character and the tty structure. 10277502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 10287502Sroot * Must be recursive. 10297502Sroot */ 10307502Sroot ttyoutput(c, tp) 10317502Sroot register c; 10327502Sroot register struct tty *tp; 10337502Sroot { 10347502Sroot register char *colp; 10357502Sroot register ctype; 103635811Smarc register long oflag = tp->t_oflag; 103735811Smarc 103835811Smarc if (!(oflag&OPOST)) { 103935811Smarc if (tp->t_lflag&FLUSHO) 10407502Sroot return (-1); 10417502Sroot if (putc(c, &tp->t_outq)) 10427625Ssam return (c); 10437502Sroot tk_nout++; 104435811Smarc tp->t_outcc++; 10457502Sroot return (-1); 10467502Sroot } 104735811Smarc c &= TTY_CHARMASK; 10487502Sroot /* 10497502Sroot * Turn tabs to spaces as required 10507502Sroot */ 105135811Smarc if (c == '\t' && oflag&OXTABS ) { 10527502Sroot register int s; 10537502Sroot 10547502Sroot c = 8 - (tp->t_col&7); 105535811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 105617545Skarels s = spltty(); /* don't interrupt tabs */ 10577502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10587502Sroot tk_nout += c; 105935811Smarc tp->t_outcc += c; 10607502Sroot splx(s); 10617502Sroot } 10627502Sroot tp->t_col += c; 10637502Sroot return (c ? -1 : '\t'); 10647502Sroot } 106535811Smarc if (c == CEOT && oflag&ONOEOT) 106635811Smarc return(-1); 10677502Sroot tk_nout++; 106835811Smarc tp->t_outcc++; 10697502Sroot /* 10707502Sroot * turn <nl> to <cr><lf> if desired. 10717502Sroot */ 107235811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 10737502Sroot return (c); 107435811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 107535811Smarc return (c); 10767502Sroot /* 10777502Sroot * Calculate delays. 10787502Sroot * The numbers here represent clock ticks 10797502Sroot * and are not necessarily optimal for all terminals. 10809578Ssam * 10819578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 108235811Smarc * 108335811Smarc * (actually, should THROW AWAY terminals which need delays) 10847502Sroot */ 10857502Sroot colp = &tp->t_col; 10867502Sroot ctype = partab[c]; 10877502Sroot c = 0; 10887502Sroot switch (ctype&077) { 10897502Sroot 10907502Sroot case ORDINARY: 10917502Sroot (*colp)++; 10927502Sroot 10937502Sroot case CONTROL: 10947502Sroot break; 10957502Sroot 10967502Sroot case BACKSPACE: 10977502Sroot if (*colp) 10987502Sroot (*colp)--; 10997502Sroot break; 11007502Sroot 110113821Ssam /* 110213821Ssam * This macro is close enough to the correct thing; 110313821Ssam * it should be replaced by real user settable delays 110413821Ssam * in any event... 110513821Ssam */ 110613821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 11077502Sroot case NEWLINE: 11087502Sroot ctype = (tp->t_flags >> 8) & 03; 11097625Ssam if (ctype == 1) { /* tty 37 */ 111026357Skarels if (*colp > 0) { 111126357Skarels c = (((unsigned)*colp) >> 4) + 3; 111226357Skarels if ((unsigned)c > 6) 111326357Skarels c = 6; 111426357Skarels } 11159578Ssam } else if (ctype == 2) /* vt05 */ 111613821Ssam c = mstohz(100); 11177502Sroot *colp = 0; 11187502Sroot break; 11197502Sroot 11207502Sroot case TAB: 11217502Sroot ctype = (tp->t_flags >> 10) & 03; 11227625Ssam if (ctype == 1) { /* tty 37 */ 11237502Sroot c = 1 - (*colp | ~07); 11247625Ssam if (c < 5) 11257502Sroot c = 0; 11267502Sroot } 11277502Sroot *colp |= 07; 11287502Sroot (*colp)++; 11297502Sroot break; 11307502Sroot 11317502Sroot case VTAB: 11329578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 11337502Sroot c = 0177; 11347502Sroot break; 11357502Sroot 11367502Sroot case RETURN: 11377502Sroot ctype = (tp->t_flags >> 12) & 03; 11389578Ssam if (ctype == 1) /* tn 300 */ 113913821Ssam c = mstohz(83); 11409578Ssam else if (ctype == 2) /* ti 700 */ 114113821Ssam c = mstohz(166); 11429578Ssam else if (ctype == 3) { /* concept 100 */ 11437502Sroot int i; 11449578Ssam 11457502Sroot if ((i = *colp) >= 0) 11469578Ssam for (; i < 9; i++) 11477502Sroot (void) putc(0177, &tp->t_outq); 11487502Sroot } 11497502Sroot *colp = 0; 11507502Sroot } 115135811Smarc if (c && (tp->t_lflag&FLUSHO) == 0) 115235811Smarc (void) putc(c|TTY_QUOTE, &tp->t_outq); 11537502Sroot return (-1); 11547502Sroot } 115513821Ssam #undef mstohz 11567502Sroot 11577502Sroot /* 11587502Sroot * Called from device's read routine after it has 11597502Sroot * calculated the tty-structure given as argument. 11607502Sroot */ 116137584Smarc ttread(tp, uio, flag) 11627625Ssam register struct tty *tp; 11637722Swnj struct uio *uio; 11647502Sroot { 11657502Sroot register struct clist *qp; 116635811Smarc register int c; 116735811Smarc register long lflag = tp->t_lflag; 116835811Smarc register u_char *cc = tp->t_cc; 11699859Ssam int s, first, error = 0; 11707502Sroot 11717502Sroot loop: 117237584Smarc s = spltty(); 11739578Ssam /* 117437584Smarc * take pending input first 11759578Ssam */ 117635811Smarc if (lflag&PENDIN) 11777502Sroot ttypend(tp); 117837584Smarc /* 117937584Smarc * Handle carrier. 118037584Smarc */ 118137584Smarc if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) { 118237584Smarc if (tp->t_state&TS_ISOPEN) { 118337584Smarc splx(s); 118437584Smarc return (0); /* EOF */ 118537728Smckusick } else if (flag & IO_NDELAY) { 118637584Smarc splx(s); 118737584Smarc return (EWOULDBLOCK); 118837584Smarc } else { 118937584Smarc /* 119037584Smarc * sleep awaiting carrier 119137584Smarc */ 119237584Smarc sleep((caddr_t)&tp->t_rawq, TTIPRI); 119337584Smarc splx(s); 119437584Smarc goto loop; 119537584Smarc } 119637584Smarc } 11979859Ssam splx(s); 11989578Ssam /* 11999578Ssam * Hang process if it's in the background. 12009578Ssam */ 120139555Smarc if (isbackground(u.u_procp, tp)) { 120224392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 120324392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 120435811Smarc u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0) 12058520Sroot return (EIO); 120635811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTIN); 12077502Sroot sleep((caddr_t)&lbolt, TTIPRI); 120823165Sbloom goto loop; 12097502Sroot } 12109578Ssam /* 121135811Smarc * If canonical, use the canonical queue, 121235811Smarc * else use the raw queue. 121337584Smarc * 121437584Smarc * XXX - should get rid of canonical queue. 121537584Smarc * (actually, should get rid of clists...) 12169578Ssam */ 121735811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 12189578Ssam /* 12199578Ssam * No input, sleep on rawq awaiting hardware 12209578Ssam * receipt and notification. 12219578Ssam */ 122217545Skarels s = spltty(); 12239578Ssam if (qp->c_cc <= 0) { 122437584Smarc /** XXX ??? ask mike why TS_CARR_ON was (once) necessary here 12259578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 12269578Ssam (tp->t_state&TS_NBIO)) { 12279859Ssam splx(s); 12289578Ssam return (EWOULDBLOCK); 12297502Sroot } 123037584Smarc **/ 123137728Smckusick if (flag & IO_NDELAY) { 123237584Smarc splx(s); 123337584Smarc return (EWOULDBLOCK); 123437584Smarc } 12359578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 12369859Ssam splx(s); 12379578Ssam goto loop; 12389578Ssam } 12399859Ssam splx(s); 12409578Ssam /* 124135811Smarc * Input present, check for input mapping and processing. 12429578Ssam */ 12439578Ssam first = 1; 12449578Ssam while ((c = getc(qp)) >= 0) { 12459578Ssam /* 124635811Smarc * delayed suspend (^Y) 12479578Ssam */ 124835811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 124939555Smarc pgsignal(tp->t_pgrp, SIGTSTP); 12509578Ssam if (first) { 12519578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12529578Ssam goto loop; 12539578Ssam } 12549578Ssam break; 12557502Sroot } 12569578Ssam /* 125735811Smarc * Interpret EOF only in canonical mode. 12589578Ssam */ 125935811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12609578Ssam break; 12619578Ssam /* 12629578Ssam * Give user character. 12639578Ssam */ 126435811Smarc error = ureadc(c , uio); 12659578Ssam if (error) 12669578Ssam break; 126714938Smckusick if (uio->uio_resid == 0) 12689578Ssam break; 12699578Ssam /* 127035811Smarc * In canonical mode check for a "break character" 12719578Ssam * marking the end of a "line of input". 12729578Ssam */ 127335811Smarc if (lflag&ICANON && ttbreakc(c)) { 12749578Ssam break; 127535811Smarc } 12769578Ssam first = 0; 12777502Sroot } 12789578Ssam /* 12799578Ssam * Look to unblock output now that (presumably) 12809578Ssam * the input queue has gone down. 12819578Ssam */ 128235811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 128335811Smarc if (cc[VSTART] != _POSIX_VDISABLE 128435811Smarc && putc(cc[VSTART], &tp->t_outq) == 0) { 12857502Sroot tp->t_state &= ~TS_TBLOCK; 12867502Sroot ttstart(tp); 12877502Sroot } 128835811Smarc } 12898520Sroot return (error); 12907502Sroot } 12917502Sroot 12927502Sroot /* 129325391Skarels * Check the output queue on tp for space for a kernel message 129425391Skarels * (from uprintf/tprintf). Allow some space over the normal 129525391Skarels * hiwater mark so we don't lose messages due to normal flow 129625391Skarels * control, but don't let the tty run amok. 129730695Skarels * Sleeps here are not interruptible, but we return prematurely 129830695Skarels * if new signals come in. 129925391Skarels */ 130025391Skarels ttycheckoutq(tp, wait) 130125391Skarels register struct tty *tp; 130225391Skarels int wait; 130325391Skarels { 130430695Skarels int hiwat, s, oldsig; 130525391Skarels 130635811Smarc hiwat = tp->t_hiwat; 130725391Skarels s = spltty(); 130830695Skarels oldsig = u.u_procp->p_sig; 130925391Skarels if (tp->t_outq.c_cc > hiwat + 200) 131029946Skarels while (tp->t_outq.c_cc > hiwat) { 131129946Skarels ttstart(tp); 131230695Skarels if (wait == 0 || u.u_procp->p_sig != oldsig) { 131329946Skarels splx(s); 131429946Skarels return (0); 131529946Skarels } 131630695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 131729946Skarels tp->t_state |= TS_ASLEEP; 131830695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 131925391Skarels } 132025391Skarels splx(s); 132125391Skarels return (1); 132225391Skarels } 132325391Skarels 132425391Skarels /* 13257502Sroot * Called from the device's write routine after it has 13267502Sroot * calculated the tty-structure given as argument. 13277502Sroot */ 132837584Smarc ttwrite(tp, uio, flag) 13297625Ssam register struct tty *tp; 13309578Ssam register struct uio *uio; 13317502Sroot { 13327502Sroot register char *cp; 133337728Smckusick register int cc, ce; 13349578Ssam int i, hiwat, cnt, error, s; 13357502Sroot char obuf[OBUFSIZ]; 13367502Sroot 133735811Smarc hiwat = tp->t_hiwat; 13389578Ssam cnt = uio->uio_resid; 13399578Ssam error = 0; 13407502Sroot loop: 134137584Smarc s = spltty(); 134237584Smarc if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) { 134337584Smarc if (tp->t_state&TS_ISOPEN) { 134437584Smarc splx(s); 134537584Smarc return (EIO); 134637728Smckusick } else if (flag & IO_NDELAY) { 134737584Smarc splx(s); 134837584Smarc return (EWOULDBLOCK); 134937584Smarc } else { 135037584Smarc /* 135137584Smarc * sleep awaiting carrier 135237584Smarc */ 135337584Smarc sleep((caddr_t)&tp->t_rawq, TTIPRI); 135437584Smarc splx(s); 135537584Smarc goto loop; 135637584Smarc } 135737584Smarc } 135837584Smarc splx(s); 13599578Ssam /* 13609578Ssam * Hang the process if it's in the background. 13619578Ssam */ 136239555Smarc if (isbackground(u.u_procp, tp) && 136335811Smarc (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 136424392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 136535811Smarc !(u.u_procp->p_sigmask & sigmask(SIGTTOU)) && 136635811Smarc u.u_procp->p_pgrp->pg_jobc) { 136735811Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU); 13687502Sroot sleep((caddr_t)&lbolt, TTIPRI); 136921776Sbloom goto loop; 13707502Sroot } 13719578Ssam /* 13729578Ssam * Process the user's data in at most OBUFSIZ 13739578Ssam * chunks. Perform lower case simulation and 13749578Ssam * similar hacks. Keep track of high water 13759578Ssam * mark, sleep on overflow awaiting device aid 13769578Ssam * in acquiring new space. 13779578Ssam */ 13787822Sroot while (uio->uio_resid > 0) { 137932067Skarels if (tp->t_outq.c_cc > hiwat) { 138032067Skarels cc = 0; 138132067Skarels goto ovhiwat; 138232067Skarels } 13839578Ssam /* 13849578Ssam * Grab a hunk of data from the user. 13859578Ssam */ 13867822Sroot cc = uio->uio_iov->iov_len; 13877822Sroot if (cc == 0) { 13887822Sroot uio->uio_iovcnt--; 13897822Sroot uio->uio_iov++; 139021776Sbloom if (uio->uio_iovcnt <= 0) 13917822Sroot panic("ttwrite"); 13927822Sroot continue; 13937822Sroot } 13947822Sroot if (cc > OBUFSIZ) 13957822Sroot cc = OBUFSIZ; 13967502Sroot cp = obuf; 139737728Smckusick error = uiomove(cp, cc, uio); 13988520Sroot if (error) 13997502Sroot break; 140035811Smarc if (tp->t_lflag&FLUSHO) 14017502Sroot continue; 14029578Ssam /* 14039578Ssam * If nothing fancy need be done, grab those characters we 14049578Ssam * can handle without any of ttyoutput's processing and 14059578Ssam * just transfer them to the output q. For those chars 14069578Ssam * which require special processing (as indicated by the 14079578Ssam * bits in partab), call ttyoutput. After processing 14089578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14099578Ssam * immediately. 14109578Ssam */ 14119578Ssam while (cc > 0) { 141235811Smarc if (!(tp->t_oflag&OPOST)) 14137502Sroot ce = cc; 14147502Sroot else { 141534492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 141634492Skarels (u_char *)partab, 077); 14179578Ssam /* 14189578Ssam * If ce is zero, then we're processing 14199578Ssam * a special character through ttyoutput. 14209578Ssam */ 14219578Ssam if (ce == 0) { 14227502Sroot tp->t_rocount = 0; 14237502Sroot if (ttyoutput(*cp, tp) >= 0) { 142421776Sbloom /* no c-lists, wait a bit */ 142521776Sbloom ttstart(tp); 142621776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 142721776Sbloom if (cc != 0) { 142821776Sbloom uio->uio_iov->iov_base -= cc; 142921776Sbloom uio->uio_iov->iov_len += cc; 143021776Sbloom uio->uio_resid += cc; 143121776Sbloom uio->uio_offset -= cc; 143221776Sbloom } 143321776Sbloom goto loop; 14347502Sroot } 14359578Ssam cp++, cc--; 143635811Smarc if ((tp->t_lflag&FLUSHO) || 14379578Ssam tp->t_outq.c_cc > hiwat) 14387502Sroot goto ovhiwat; 14399578Ssam continue; 14407502Sroot } 14417502Sroot } 14429578Ssam /* 14439578Ssam * A bunch of normal characters have been found, 14449578Ssam * transfer them en masse to the output queue and 14459578Ssam * continue processing at the top of the loop. 14469578Ssam * If there are any further characters in this 14479578Ssam * <= OBUFSIZ chunk, the first should be a character 14489578Ssam * requiring special handling by ttyoutput. 14499578Ssam */ 14507502Sroot tp->t_rocount = 0; 14519578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14529578Ssam ce -= i; 14539578Ssam tp->t_col += ce; 14549578Ssam cp += ce, cc -= ce, tk_nout += ce; 145535811Smarc tp->t_outcc += ce; 14569578Ssam if (i > 0) { 14579578Ssam /* out of c-lists, wait a bit */ 14587502Sroot ttstart(tp); 14597502Sroot sleep((caddr_t)&lbolt, TTOPRI); 146021776Sbloom uio->uio_iov->iov_base -= cc; 146121776Sbloom uio->uio_iov->iov_len += cc; 146221776Sbloom uio->uio_resid += cc; 146321776Sbloom uio->uio_offset -= cc; 146421776Sbloom goto loop; 14657502Sroot } 146635811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 14677502Sroot goto ovhiwat; 14687502Sroot } 146935811Smarc ttstart(tp); 14707502Sroot } 14718520Sroot return (error); 14727502Sroot ovhiwat: 14739578Ssam if (cc != 0) { 14749578Ssam uio->uio_iov->iov_base -= cc; 14759578Ssam uio->uio_iov->iov_len += cc; 14769578Ssam uio->uio_resid += cc; 14779578Ssam uio->uio_offset -= cc; 14789578Ssam } 147932067Skarels ttstart(tp); 148032067Skarels s = spltty(); 14819578Ssam /* 148235811Smarc * This can only occur if FLUSHO is set in t_lflag, 148332067Skarels * or if ttstart/oproc is synchronous (or very fast). 14849578Ssam */ 14857502Sroot if (tp->t_outq.c_cc <= hiwat) { 14869578Ssam splx(s); 14877502Sroot goto loop; 14887502Sroot } 148937728Smckusick if (flag & IO_NDELAY) { 149017545Skarels splx(s); 14917822Sroot if (uio->uio_resid == cnt) 14928520Sroot return (EWOULDBLOCK); 14938520Sroot return (0); 14947502Sroot } 14957502Sroot tp->t_state |= TS_ASLEEP; 14967502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14979578Ssam splx(s); 14987502Sroot goto loop; 14997502Sroot } 15007502Sroot 15017502Sroot /* 15027502Sroot * Rubout one character from the rawq of tp 15037502Sroot * as cleanly as possible. 15047502Sroot */ 15057502Sroot ttyrub(c, tp) 15067625Ssam register c; 15077625Ssam register struct tty *tp; 15087502Sroot { 15097502Sroot register char *cp; 15107502Sroot register int savecol; 15117502Sroot int s; 15127502Sroot char *nextc(); 15137502Sroot 151435811Smarc if ((tp->t_lflag&ECHO) == 0) 15157502Sroot return; 151635811Smarc tp->t_lflag &= ~FLUSHO; 151735811Smarc if (tp->t_lflag&ECHOE) { 15187502Sroot if (tp->t_rocount == 0) { 15197502Sroot /* 15207502Sroot * Screwed by ttwrite; retype 15217502Sroot */ 15227502Sroot ttyretype(tp); 15237502Sroot return; 15247502Sroot } 152535811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 15267502Sroot ttyrubo(tp, 2); 152735811Smarc else switch (partab[c&=0377]&077) { 15287502Sroot 15297502Sroot case ORDINARY: 153035811Smarc ttyrubo(tp, 1); 15317502Sroot break; 15327502Sroot 15337502Sroot case VTAB: 15347502Sroot case BACKSPACE: 15357502Sroot case CONTROL: 15367502Sroot case RETURN: 153735811Smarc if (tp->t_lflag&ECHOCTL) 15387502Sroot ttyrubo(tp, 2); 15397502Sroot break; 15407502Sroot 154135811Smarc case TAB: { 154235811Smarc int c; 154335811Smarc 15447502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15457502Sroot ttyretype(tp); 15467502Sroot return; 15477502Sroot } 154817545Skarels s = spltty(); 15497502Sroot savecol = tp->t_col; 15509578Ssam tp->t_state |= TS_CNTTB; 155135811Smarc tp->t_lflag |= FLUSHO; 15527502Sroot tp->t_col = tp->t_rocol; 15539578Ssam cp = tp->t_rawq.c_cf; 155439407Smarc if (cp) 155539407Smarc c = *cp; /* XXX FIX NEXTC */ 155635811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 155735811Smarc ttyecho(c, tp); 155835811Smarc tp->t_lflag &= ~FLUSHO; 15599578Ssam tp->t_state &= ~TS_CNTTB; 15607502Sroot splx(s); 15617502Sroot /* 15627502Sroot * savecol will now be length of the tab 15637502Sroot */ 15647502Sroot savecol -= tp->t_col; 15657502Sroot tp->t_col += savecol; 15667502Sroot if (savecol > 8) 15677502Sroot savecol = 8; /* overflow screw */ 15687502Sroot while (--savecol >= 0) 15697502Sroot (void) ttyoutput('\b', tp); 15707502Sroot break; 157135811Smarc } 15727502Sroot 15737502Sroot default: 157437584Smarc /* XXX */ 157535811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 157635811Smarc c, partab[c&=0377]&077); 157735811Smarc /*panic("ttyrub");*/ 15787502Sroot } 157935811Smarc } else if (tp->t_lflag&ECHOPRT) { 15809578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15817502Sroot (void) ttyoutput('\\', tp); 15829578Ssam tp->t_state |= TS_ERASE; 15837502Sroot } 15847502Sroot ttyecho(c, tp); 15857502Sroot } else 158635811Smarc ttyecho(tp->t_cc[VERASE], tp); 15877502Sroot tp->t_rocount--; 15887502Sroot } 15897502Sroot 15907502Sroot /* 15917502Sroot * Crt back over cnt chars perhaps 15927502Sroot * erasing them. 15937502Sroot */ 15947502Sroot ttyrubo(tp, cnt) 15957625Ssam register struct tty *tp; 15967625Ssam int cnt; 15977502Sroot { 15987502Sroot 15997502Sroot while (--cnt >= 0) 160035811Smarc ttyout("\b \b", tp); 16017502Sroot } 16027502Sroot 16037502Sroot /* 16047502Sroot * Reprint the rawq line. 16057502Sroot * We assume c_cc has already been checked. 16067502Sroot */ 16077502Sroot ttyretype(tp) 16087625Ssam register struct tty *tp; 16097502Sroot { 16107502Sroot register char *cp; 16117502Sroot char *nextc(); 161235811Smarc int s, c; 16137502Sroot 161435811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 161535811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 16167502Sroot (void) ttyoutput('\n', tp); 161717545Skarels s = spltty(); 161835811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 161935811Smarc BIT OF FIRST CHAR ****/ 162035811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 162135811Smarc ttyecho(c, tp); 162235811Smarc } 162335811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 162435811Smarc ttyecho(c, tp); 162535811Smarc } 16269578Ssam tp->t_state &= ~TS_ERASE; 16277502Sroot splx(s); 16287502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16297502Sroot tp->t_rocol = 0; 16307502Sroot } 16317502Sroot 16327502Sroot /* 163335811Smarc * Echo a typed character to the terminal. 16347502Sroot */ 16357502Sroot ttyecho(c, tp) 16367625Ssam register c; 16377625Ssam register struct tty *tp; 16387502Sroot { 16399578Ssam if ((tp->t_state&TS_CNTTB) == 0) 164035811Smarc tp->t_lflag &= ~FLUSHO; 164135811Smarc if ((tp->t_lflag&ECHO) == 0 && !(tp->t_lflag&ECHONL && c == '\n')) 16427502Sroot return; 164335811Smarc if (tp->t_lflag&ECHOCTL) { 164435811Smarc if ((c&TTY_CHARMASK)<=037 && c!='\t' && c!='\n' || c==0177) { 16457502Sroot (void) ttyoutput('^', tp); 164635811Smarc c &= TTY_CHARMASK; 16477502Sroot if (c == 0177) 16487502Sroot c = '?'; 16497502Sroot else 16507502Sroot c += 'A' - 1; 16517502Sroot } 16527502Sroot } 165335811Smarc (void) ttyoutput(c, tp); 16547502Sroot } 16557502Sroot 16567502Sroot /* 16577502Sroot * send string cp to tp 16587502Sroot */ 16597502Sroot ttyout(cp, tp) 16607625Ssam register char *cp; 16617625Ssam register struct tty *tp; 16627502Sroot { 16637502Sroot register char c; 16647502Sroot 16657502Sroot while (c = *cp++) 16667502Sroot (void) ttyoutput(c, tp); 16677502Sroot } 16687502Sroot 16697502Sroot ttwakeup(tp) 16707502Sroot struct tty *tp; 16717502Sroot { 16727502Sroot 16737502Sroot if (tp->t_rsel) { 16747502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16757502Sroot tp->t_state &= ~TS_RCOLL; 16767502Sroot tp->t_rsel = 0; 16777502Sroot } 167812752Ssam if (tp->t_state & TS_ASYNC) 167939555Smarc pgsignal(tp->t_pgrp, SIGIO); 16807502Sroot wakeup((caddr_t)&tp->t_rawq); 16817502Sroot } 168235811Smarc 168335811Smarc /* 168435811Smarc * set tty hi and low water marks 168535811Smarc * 168635811Smarc * Try to arrange the dynamics so there's about one second 168735811Smarc * from hi to low water. 168835811Smarc * 168935811Smarc */ 169035811Smarc ttsetwater(tp) 169135811Smarc struct tty *tp; 169235811Smarc { 169335811Smarc register cps = tp->t_ospeed / 10; 169435811Smarc register x; 169535811Smarc 169635811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 169735811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 169835811Smarc x += cps; 169935811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 170035811Smarc tp->t_hiwat = roundup(x, CBSIZE); 170135811Smarc #undef clamp 170235811Smarc } 170335811Smarc 170435811Smarc ttspeedtab(speed, table) 170535811Smarc struct speedtab table[]; 170635811Smarc { 170735811Smarc register int i; 170835811Smarc 170935811Smarc for (i = 0; table[i].sp_speed != -1; i++) 171035811Smarc if (table[i].sp_speed == speed) 171135811Smarc return(table[i].sp_code); 171235811Smarc return(-1); 171335811Smarc } 171439407Smarc 171539407Smarc /* 171639407Smarc * (^T) 171739407Smarc * Report on state of foreground process group. 171839407Smarc */ 171939407Smarc ttyinfo(tp) 172039407Smarc struct tty *tp; 172139407Smarc { 172239407Smarc register struct proc *p; 172339407Smarc 172439407Smarc if (ttycheckoutq(tp,0) == 0) 172539407Smarc return; 172639555Smarc if (tp->t_session == NULL) 172739555Smarc ttyprintf(tp, "kernel: not a controlling terminal\n"); 172839555Smarc else if (tp->t_pgrp == NULL || 172939555Smarc (p = tp->t_pgrp->pg_mem) == NULL) 173039407Smarc ttyprintf(tp, "kernel: no foreground process group\n"); 173139407Smarc else { 173239407Smarc int i = 0; 173339555Smarc 173439407Smarc for (; p != NULL; p = p->p_pgrpnxt) { 173539407Smarc ttyprintf(tp, 173639407Smarc "kernel: pid: %d state: %x wchan: %x ticks: %d\n", 173739407Smarc p->p_pid, p->p_stat, p->p_wchan, p->p_cpticks); 173839407Smarc if (++i > 6) { 173939407Smarc ttyprintf(tp, "kernel: more...\n"); 174039407Smarc break; 174139407Smarc } 174239407Smarc } 174339407Smarc } 174439407Smarc } 174539407Smarc 174639407Smarc #define TOTTY 0x2 /* XXX should be in header */ 174739407Smarc /*VARARGS2*/ 174839407Smarc ttyprintf(tp, fmt, x1) 174939555Smarc struct tty *tp; 175039407Smarc char *fmt; 175139407Smarc unsigned x1; 175239407Smarc { 175339555Smarc prf(fmt, &x1, TOTTY, (caddr_t)tp); 175439407Smarc } 175539555Smarc 175639555Smarc /* 175739555Smarc * Output char to tty; console putchar style. 175839555Smarc */ 175939555Smarc tputchar(c, tp) 176039555Smarc int c; 176139555Smarc struct tty *tp; 176239555Smarc { 176339555Smarc register s = spltty(); 176439555Smarc 176539555Smarc if ((tp->t_state & (TS_CARR_ON | TS_ISOPEN)) 176639555Smarc == (TS_CARR_ON | TS_ISOPEN)) { 176739555Smarc if (c == '\n') 176839555Smarc (void) ttyoutput('\r', tp); 176939555Smarc (void) ttyoutput(c, tp); 177039555Smarc ttstart(tp); 177139555Smarc splx(s); 177239555Smarc return (0); 177339555Smarc } 177439555Smarc splx(s); 177539555Smarc return (-1); 177639555Smarc } 1777