1*13533Ssam /* tty.c 4.43 83/07/01 */ 239Sbill 39760Ssam #include "../machine/reg.h" 49760Ssam 539Sbill #include "../h/param.h" 639Sbill #include "../h/systm.h" 739Sbill #include "../h/dir.h" 839Sbill #include "../h/user.h" 99578Ssam #include "../h/ioctl.h" 1039Sbill #include "../h/tty.h" 1139Sbill #include "../h/proc.h" 1239Sbill #include "../h/inode.h" 1339Sbill #include "../h/file.h" 1439Sbill #include "../h/conf.h" 1539Sbill #include "../h/buf.h" 16340Sbill #include "../h/dk.h" 177722Swnj #include "../h/uio.h" 188154Sroot #include "../h/kernel.h" 1939Sbill 207436Skre /* 217436Skre * Table giving parity for characters and indicating 227436Skre * character classes to tty driver. In particular, 237436Skre * if the low 6 bits are 0, then the character needs 247436Skre * no special processing on output. 257436Skre */ 2639Sbill 277436Skre char partab[] = { 287436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 297436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 307436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 317436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 327436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 337436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 347436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 357436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 367436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 377436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 387436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 397436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 407436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 417436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 427436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 437436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 447436Skre 457436Skre /* 467436Skre * 7 bit ascii ends with the last character above, 477436Skre * but we contine through all 256 codes for the sake 487436Skre * of the tty output routines which use special vax 497436Skre * instructions which need a 256 character trt table. 507436Skre */ 517436Skre 527436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 537436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 547436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 557436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 567436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 577436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 587436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 597436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 607436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 617436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 627436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 637436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 647436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 657436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 667436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 677436Skre 0007,0007,0007,0007,0007,0007,0007,0007 687436Skre }; 697436Skre 70146Sbill /* 7139Sbill * Input mapping table-- if an entry is non-zero, when the 7239Sbill * corresponding character is typed preceded by "\" the escape 7339Sbill * sequence is replaced by the table value. Mostly used for 7439Sbill * upper-case only terminals. 7539Sbill */ 7639Sbill char maptab[] ={ 7739Sbill 000,000,000,000,000,000,000,000, 7839Sbill 000,000,000,000,000,000,000,000, 7939Sbill 000,000,000,000,000,000,000,000, 8039Sbill 000,000,000,000,000,000,000,000, 8139Sbill 000,'|',000,000,000,000,000,'`', 8239Sbill '{','}',000,000,000,000,000,000, 8339Sbill 000,000,000,000,000,000,000,000, 8439Sbill 000,000,000,000,000,000,000,000, 8539Sbill 000,000,000,000,000,000,000,000, 8639Sbill 000,000,000,000,000,000,000,000, 8739Sbill 000,000,000,000,000,000,000,000, 8839Sbill 000,000,000,000,000,000,'~',000, 8939Sbill 000,'A','B','C','D','E','F','G', 9039Sbill 'H','I','J','K','L','M','N','O', 9139Sbill 'P','Q','R','S','T','U','V','W', 9239Sbill 'X','Y','Z',000,000,000,000,000, 9339Sbill }; 9439Sbill 95925Sbill short tthiwat[16] = 968954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 97925Sbill short ttlowat[16] = 98925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 99925Sbill 1009578Ssam struct ttychars ttydefaults = { 1019578Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 1029578Ssam CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 1039578Ssam }; 10439Sbill 10539Sbill ttychars(tp) 1069578Ssam struct tty *tp; 10739Sbill { 108174Sbill 1099578Ssam tp->t_chars = ttydefaults; 11039Sbill } 11139Sbill 11239Sbill /* 113903Sbill * Wait for output to drain, then flush input waiting. 11439Sbill */ 11512752Ssam ttywflush(tp) 1165408Swnj register struct tty *tp; 11739Sbill { 11839Sbill 11912752Ssam ttywait(tp); 12012752Ssam ttyflush(tp, FREAD); 12112752Ssam } 12212752Ssam 12312752Ssam ttywait(tp) 12412752Ssam register struct tty *tp; 12512752Ssam { 12612752Ssam register int s = spl5(); 12712752Ssam 1285622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1295622Swnj && tp->t_oproc) { /* kludge for pty */ 130903Sbill (*tp->t_oproc)(tp); 1315408Swnj tp->t_state |= TS_ASLEEP; 132903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 133903Sbill } 1349859Ssam splx(s); 13539Sbill } 13639Sbill 13739Sbill /* 1389578Ssam * Flush all TTY queues 13939Sbill */ 14012752Ssam ttyflush(tp, rw) 1417625Ssam register struct tty *tp; 14239Sbill { 143903Sbill register s; 144903Sbill 145903Sbill s = spl6(); 146903Sbill if (rw & FREAD) { 147903Sbill while (getc(&tp->t_canq) >= 0) 148903Sbill ; 149903Sbill wakeup((caddr_t)&tp->t_rawq); 150903Sbill } 151903Sbill if (rw & FWRITE) { 152903Sbill wakeup((caddr_t)&tp->t_outq); 1535408Swnj tp->t_state &= ~TS_TTSTOP; 1545426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 155903Sbill while (getc(&tp->t_outq) >= 0) 156903Sbill ; 157903Sbill } 158903Sbill if (rw & FREAD) { 159903Sbill while (getc(&tp->t_rawq) >= 0) 160903Sbill ; 161903Sbill tp->t_delct = 0; 1629578Ssam tp->t_rocount = 0; 163903Sbill tp->t_rocol = 0; 1649578Ssam tp->t_state &= ~TS_LOCAL; 165903Sbill } 166903Sbill splx(s); 16739Sbill } 16839Sbill 169903Sbill /* 170903Sbill * Send stop character on input overflow. 171903Sbill */ 172903Sbill ttyblock(tp) 1737625Ssam register struct tty *tp; 17439Sbill { 175903Sbill register x; 1769578Ssam 177903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 178903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 17912752Ssam ttyflush(tp, FREAD|FWRITE); 1805408Swnj tp->t_state &= ~TS_TBLOCK; 181903Sbill } 1829578Ssam if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) { 1839578Ssam tp->t_state |= TS_TBLOCK; 1849578Ssam ttstart(tp); 185903Sbill } 18639Sbill } 18739Sbill 18839Sbill /* 189903Sbill * Restart typewriter output following a delay 190903Sbill * timeout. 191903Sbill * The name of the routine is passed to the timeout 192903Sbill * subroutine and it is called during a clock interrupt. 193121Sbill */ 194903Sbill ttrstrt(tp) 1957625Ssam register struct tty *tp; 196121Sbill { 197121Sbill 1989578Ssam if (tp == 0) 1999578Ssam panic("ttrstrt"); 2005408Swnj tp->t_state &= ~TS_TIMEOUT; 201903Sbill ttstart(tp); 202121Sbill } 203121Sbill 204121Sbill /* 205903Sbill * Start output on the typewriter. It is used from the top half 206903Sbill * after some characters have been put on the output queue, 207903Sbill * from the interrupt routine to transmit the next 208903Sbill * character, and after a timeout has finished. 20939Sbill */ 210903Sbill ttstart(tp) 2117625Ssam register struct tty *tp; 21239Sbill { 213903Sbill register s; 21439Sbill 215903Sbill s = spl5(); 2169578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2175622Swnj tp->t_oproc) /* kludge for pty */ 218903Sbill (*tp->t_oproc)(tp); 219903Sbill splx(s); 22039Sbill } 22139Sbill 22239Sbill /* 223903Sbill * Common code for tty ioctls. 22439Sbill */ 2251780Sbill /*ARGSUSED*/ 2267625Ssam ttioctl(tp, com, data, flag) 2277625Ssam register struct tty *tp; 2287625Ssam caddr_t data; 22939Sbill { 2308520Sroot int dev = tp->t_dev; 23139Sbill extern int nldisp; 2328556Sroot int s; 23312752Ssam register int newflags; 23439Sbill 235903Sbill /* 236903Sbill * If the ioctl involves modification, 237903Sbill * insist on being able to write the device, 238903Sbill * and hang if in the background. 239903Sbill */ 2407625Ssam switch (com) { 24139Sbill 242915Sbill case TIOCSETD: 243915Sbill case TIOCSETP: 244915Sbill case TIOCSETN: 245903Sbill case TIOCFLUSH: 246903Sbill case TIOCSETC: 247903Sbill case TIOCSLTC: 248903Sbill case TIOCSPGRP: 249903Sbill case TIOCLBIS: 250903Sbill case TIOCLBIC: 251903Sbill case TIOCLSET: 2529325Ssam case TIOCSTI: 253903Sbill while (tp->t_line == NTTYDISC && 254903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 255903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 256903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2578556Sroot u.u_signal[SIGTTOU] != SIG_HOLD) { 258903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 259903Sbill sleep((caddr_t)&lbolt, TTOPRI); 260903Sbill } 261903Sbill break; 262903Sbill } 263903Sbill 2649578Ssam /* 2659578Ssam * Process the ioctl. 2669578Ssam */ 2677625Ssam switch (com) { 268903Sbill 2698556Sroot /* get discipline number */ 27039Sbill case TIOCGETD: 2717625Ssam *(int *)data = tp->t_line; 27239Sbill break; 27339Sbill 2748556Sroot /* set line discipline */ 2757625Ssam case TIOCSETD: { 2767625Ssam register int t = *(int *)data; 2779578Ssam int error = 0; 2787625Ssam 27910851Ssam if (t >= nldisp) 28010851Ssam return (ENXIO); 2818556Sroot s = spl5(); 28239Sbill if (tp->t_line) 28339Sbill (*linesw[tp->t_line].l_close)(tp); 28439Sbill if (t) 2858556Sroot error = (*linesw[t].l_open)(dev, tp); 2868556Sroot splx(s); 28710851Ssam if (error) { 28810851Ssam s = spl5(); 28910851Ssam if (tp->t_line) 29010851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 29110851Ssam splx(s); 2928556Sroot return (error); 29310851Ssam } 2948556Sroot tp->t_line = t; 29539Sbill break; 2967625Ssam } 29739Sbill 2988556Sroot /* prevent more opens on channel */ 2995614Swnj case TIOCEXCL: 3005614Swnj tp->t_state |= TS_XCLUDE; 3015614Swnj break; 3025614Swnj 3035614Swnj case TIOCNXCL: 3045614Swnj tp->t_state &= ~TS_XCLUDE; 3055614Swnj break; 3065614Swnj 3078556Sroot /* hang up line on last close */ 30839Sbill case TIOCHPCL: 3095408Swnj tp->t_state |= TS_HUPCLS; 31039Sbill break; 31139Sbill 3123942Sbugs case TIOCFLUSH: { 3137625Ssam register int flags = *(int *)data; 3147625Ssam 3157625Ssam if (flags == 0) 3163942Sbugs flags = FREAD|FWRITE; 3177625Ssam else 3187625Ssam flags &= FREAD|FWRITE; 31912752Ssam ttyflush(tp, flags); 32039Sbill break; 3213944Sbugs } 32239Sbill 3238556Sroot /* return number of characters immediately available */ 3247625Ssam case FIONREAD: 3257625Ssam *(off_t *)data = ttnread(tp); 326174Sbill break; 327174Sbill 32813077Ssam case TIOCOUTQ: 32913077Ssam *(int *)data = tp->t_outq.c_cc; 33013077Ssam break; 33113077Ssam 3328589Sroot case TIOCSTOP: 3338589Sroot s = spl5(); 3349578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3355573Swnj tp->t_state |= TS_TTSTOP; 3365573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3375573Swnj } 3387625Ssam splx(s); 3395573Swnj break; 3405573Swnj 3418589Sroot case TIOCSTART: 3428589Sroot s = spl5(); 3439578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3445573Swnj tp->t_state &= ~TS_TTSTOP; 3459578Ssam tp->t_flags &= ~FLUSHO; 3465573Swnj ttstart(tp); 3475573Swnj } 3487625Ssam splx(s); 3495573Swnj break; 3505573Swnj 3519325Ssam /* 3529325Ssam * Simulate typing of a character at the terminal. 3539325Ssam */ 3549325Ssam case TIOCSTI: 3559325Ssam if (u.u_uid && u.u_ttyp != tp) 3569325Ssam return (EACCES); 3579578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3589325Ssam break; 3599325Ssam 36012752Ssam case TIOCSETP: 36112752Ssam case TIOCSETN: { 36212752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 36312752Ssam 36412752Ssam tp->t_erase = sg->sg_erase; 36512752Ssam tp->t_kill = sg->sg_kill; 36612752Ssam tp->t_ispeed = sg->sg_ispeed; 36712752Ssam tp->t_ospeed = sg->sg_ospeed; 36812752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 36912752Ssam s = spl5(); 37012752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 37112752Ssam ttywait(tp); 37212752Ssam ttyflush(tp, FREAD); 37312752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 37412752Ssam if (newflags&CBREAK) { 37512752Ssam struct clist tq; 37612752Ssam 37712752Ssam catq(&tp->t_rawq, &tp->t_canq); 37812752Ssam tq = tp->t_rawq; 37912752Ssam tp->t_rawq = tp->t_canq; 38012752Ssam tp->t_canq = tq; 38112752Ssam } else { 38212752Ssam tp->t_flags |= PENDIN; 38312752Ssam ttwakeup(tp); 38412752Ssam } 38512752Ssam } 38612752Ssam tp->t_flags = newflags; 38712752Ssam if (tp->t_flags&RAW) { 38812752Ssam tp->t_state &= ~TS_TTSTOP; 38912752Ssam ttstart(tp); 39012752Ssam } 39112752Ssam splx(s); 39212752Ssam break; 39312752Ssam } 39412752Ssam 39512752Ssam /* send current parameters to user */ 39612752Ssam case TIOCGETP: { 39712752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 39812752Ssam 39912752Ssam sg->sg_ispeed = tp->t_ispeed; 40012752Ssam sg->sg_ospeed = tp->t_ospeed; 40112752Ssam sg->sg_erase = tp->t_erase; 40212752Ssam sg->sg_kill = tp->t_kill; 40312752Ssam sg->sg_flags = tp->t_flags; 40412752Ssam break; 40512752Ssam } 40612752Ssam 40712752Ssam case FIONBIO: 40812752Ssam if (*(int *)data) 40912752Ssam tp->t_state |= TS_NBIO; 41012752Ssam else 41112752Ssam tp->t_state &= ~TS_NBIO; 41212752Ssam break; 41312752Ssam 41412752Ssam case FIOASYNC: 41512752Ssam if (*(int *)data) 41612752Ssam tp->t_state |= TS_ASYNC; 41712752Ssam else 41812752Ssam tp->t_state &= ~TS_ASYNC; 41912752Ssam break; 42012752Ssam 42113077Ssam case TIOCGETC: 42213077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 42313077Ssam break; 42413077Ssam 42513077Ssam case TIOCSETC: 42613077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 42713077Ssam break; 42813077Ssam 42912752Ssam /* set/get local special characters */ 43012752Ssam case TIOCSLTC: 43112752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 43212752Ssam break; 43312752Ssam 43412752Ssam case TIOCGLTC: 43512752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 43612752Ssam break; 43712752Ssam 43812752Ssam /* 43912752Ssam * Modify local mode word. 44012752Ssam */ 44112752Ssam case TIOCLBIS: 44212752Ssam tp->t_flags |= *(int *)data << 16; 44312752Ssam break; 44412752Ssam 44512752Ssam case TIOCLBIC: 44612752Ssam tp->t_flags &= ~(*(int *)data << 16); 44712752Ssam break; 44812752Ssam 44912752Ssam case TIOCLSET: 45012752Ssam tp->t_flags &= 0xffff; 45112752Ssam tp->t_flags |= *(int *)data << 16; 45212752Ssam break; 45312752Ssam 45412752Ssam case TIOCLGET: 45512752Ssam *(int *)data = tp->t_flags >> 16; 45612752Ssam break; 45712752Ssam 45812752Ssam /* should allow SPGRP and GPGRP only if tty open for reading */ 45912752Ssam case TIOCSPGRP: 46012752Ssam tp->t_pgrp = *(int *)data; 46112752Ssam break; 46212752Ssam 46312752Ssam case TIOCGPGRP: 46412752Ssam *(int *)data = tp->t_pgrp; 46512752Ssam break; 46612752Ssam 46739Sbill default: 4688556Sroot return (-1); 46939Sbill } 4708556Sroot return (0); 47139Sbill } 4724484Swnj 4734484Swnj ttnread(tp) 4744484Swnj struct tty *tp; 4754484Swnj { 4764484Swnj int nread = 0; 4774484Swnj 4789578Ssam if (tp->t_flags & PENDIN) 4794484Swnj ttypend(tp); 4804484Swnj nread = tp->t_canq.c_cc; 4814484Swnj if (tp->t_flags & (RAW|CBREAK)) 4824484Swnj nread += tp->t_rawq.c_cc; 4834484Swnj return (nread); 4844484Swnj } 4854484Swnj 4865408Swnj ttselect(dev, rw) 4874484Swnj dev_t dev; 4885408Swnj int rw; 4894484Swnj { 4904484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4914484Swnj int nread; 4925408Swnj int s = spl5(); 4934484Swnj 4945408Swnj switch (rw) { 4954484Swnj 4964484Swnj case FREAD: 4974484Swnj nread = ttnread(tp); 4984484Swnj if (nread > 0) 4995408Swnj goto win; 5004938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5015408Swnj tp->t_state |= TS_RCOLL; 5024484Swnj else 5034484Swnj tp->t_rsel = u.u_procp; 5045408Swnj break; 5054484Swnj 5065408Swnj case FWRITE: 5075408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5085408Swnj goto win; 5095408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5105408Swnj tp->t_state |= TS_WCOLL; 5115408Swnj else 5125408Swnj tp->t_wsel = u.u_procp; 5135408Swnj break; 5144484Swnj } 5155408Swnj splx(s); 5165408Swnj return (0); 5175408Swnj win: 5185408Swnj splx(s); 5195408Swnj return (1); 5204484Swnj } 5217436Skre 5227502Sroot /* 5239578Ssam * Establish a process group for distribution of 5247502Sroot * quits and interrupts from the tty. 5257502Sroot */ 5267502Sroot ttyopen(dev, tp) 5277625Ssam dev_t dev; 5287625Ssam register struct tty *tp; 5297502Sroot { 5307502Sroot register struct proc *pp; 5317502Sroot 5327502Sroot pp = u.u_procp; 5337502Sroot tp->t_dev = dev; 5347625Ssam if (pp->p_pgrp == 0) { 5357502Sroot u.u_ttyp = tp; 5367502Sroot u.u_ttyd = dev; 5377502Sroot if (tp->t_pgrp == 0) 5387502Sroot tp->t_pgrp = pp->p_pid; 5397502Sroot pp->p_pgrp = tp->t_pgrp; 5407502Sroot } 5417502Sroot tp->t_state &= ~TS_WOPEN; 5427502Sroot tp->t_state |= TS_ISOPEN; 5437502Sroot if (tp->t_line != NTTYDISC) 54412752Ssam ttywflush(tp); 5458556Sroot return (0); 5467502Sroot } 5477502Sroot 5487502Sroot /* 5497502Sroot * clean tp on last close 5507502Sroot */ 5517502Sroot ttyclose(tp) 5527625Ssam register struct tty *tp; 5537502Sroot { 5547502Sroot 5557502Sroot if (tp->t_line) { 55612752Ssam ttywflush(tp); 5577502Sroot tp->t_line = 0; 5587502Sroot return; 5597502Sroot } 5607502Sroot tp->t_pgrp = 0; 56112752Ssam ttywflush(tp); 5627502Sroot tp->t_state = 0; 5637502Sroot } 5647502Sroot 5657502Sroot /* 5667502Sroot * reinput pending characters after state switch 5677502Sroot * call at spl5(). 5687502Sroot */ 5697502Sroot ttypend(tp) 5707625Ssam register struct tty *tp; 5717502Sroot { 5727502Sroot struct clist tq; 5737502Sroot register c; 5747502Sroot 5759578Ssam tp->t_flags &= ~PENDIN; 5769578Ssam tp->t_state |= TS_TYPEN; 5777502Sroot tq = tp->t_rawq; 5787502Sroot tp->t_rawq.c_cc = 0; 5797502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5807502Sroot while ((c = getc(&tq)) >= 0) 5817502Sroot ttyinput(c, tp); 5829578Ssam tp->t_state &= ~TS_TYPEN; 5837502Sroot } 5847502Sroot 5857502Sroot /* 5869578Ssam * Place a character on raw TTY input queue, 5879578Ssam * putting in delimiters and waking up top 5889578Ssam * half as needed. Also echo if required. 5899578Ssam * The arguments are the character and the 5909578Ssam * appropriate tty structure. 5917502Sroot */ 5927502Sroot ttyinput(c, tp) 5937625Ssam register c; 5947625Ssam register struct tty *tp; 5957502Sroot { 5969578Ssam register int t_flags = tp->t_flags; 5977502Sroot int i; 5987502Sroot 5999578Ssam /* 6009578Ssam * If input is pending take it first. 6019578Ssam */ 6029578Ssam if (t_flags&PENDIN) 6037502Sroot ttypend(tp); 6047502Sroot tk_nin++; 6057502Sroot c &= 0377; 6069578Ssam 6079578Ssam /* 6089578Ssam * In tandem mode, check high water mark. 6099578Ssam */ 6107502Sroot if (t_flags&TANDEM) 6117502Sroot ttyblock(tp); 6129578Ssam 6139578Ssam if (t_flags&RAW) { 6149578Ssam /* 6159578Ssam * Raw mode, just put character 6169578Ssam * in input q w/o interpretation. 6179578Ssam */ 6189578Ssam if (tp->t_rawq.c_cc > TTYHOG) 61912752Ssam ttyflush(tp, FREAD|FWRITE); 6209578Ssam else { 6219578Ssam if (putc(c, &tp->t_rawq) >= 0) 6229578Ssam ttwakeup(tp); 6239578Ssam ttyecho(c, tp); 6247502Sroot } 6259578Ssam goto endcase; 6269578Ssam } 6279578Ssam 6289578Ssam /* 6299578Ssam * Ignore any high bit added during 6309578Ssam * previous ttyinput processing. 6319578Ssam */ 6329578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6339578Ssam c &= 0177; 6349578Ssam /* 6359578Ssam * Check for literal nexting very first 6369578Ssam */ 6379578Ssam if (tp->t_state&TS_LNCH) { 6389578Ssam c |= 0200; 6399578Ssam tp->t_state &= ~TS_LNCH; 6409578Ssam } 6419578Ssam 6429578Ssam /* 6439578Ssam * Scan for special characters. This code 6449578Ssam * is really just a big case statement with 6459578Ssam * non-constant cases. The bottom of the 6469578Ssam * case statement is labeled ``endcase'', so goto 6479578Ssam * it after a case match, or similar. 6489578Ssam */ 6499578Ssam if (tp->t_line == NTTYDISC) { 6509578Ssam if (c == tp->t_lnextc) { 6517502Sroot if (tp->t_flags&ECHO) 6527502Sroot ttyout("^\b", tp); 6539578Ssam tp->t_state |= TS_LNCH; 6549578Ssam goto endcase; 6559578Ssam } 6569578Ssam if (c == tp->t_flushc) { 6579578Ssam if (tp->t_flags&FLUSHO) 6589578Ssam tp->t_flags &= ~FLUSHO; 6597502Sroot else { 66012752Ssam ttyflush(tp, FWRITE); 6617502Sroot ttyecho(c, tp); 6629578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6637502Sroot ttyretype(tp); 6649578Ssam tp->t_flags |= FLUSHO; 6657502Sroot } 6669578Ssam goto startoutput; 6679578Ssam } 6689578Ssam if (c == tp->t_suspc) { 6699578Ssam if ((tp->t_flags&NOFLSH) == 0) 67012752Ssam ttyflush(tp, FREAD); 6719578Ssam ttyecho(c, tp); 6729578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6739578Ssam goto endcase; 6749578Ssam } 6759578Ssam } 6769578Ssam 6779578Ssam /* 6789578Ssam * Handle start/stop characters. 6799578Ssam */ 6809578Ssam if (c == tp->t_stopc) { 6819578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6829578Ssam tp->t_state |= TS_TTSTOP; 6839578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6847502Sroot return; 6859578Ssam } 6869578Ssam if (c != tp->t_startc) 6879578Ssam return; 6889578Ssam goto endcase; 6899578Ssam } 6909578Ssam if (c == tp->t_startc) 6919578Ssam goto restartoutput; 6929578Ssam 6939578Ssam /* 6949578Ssam * Look for interrupt/quit chars. 6959578Ssam */ 6969578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 6979578Ssam if ((tp->t_flags&NOFLSH) == 0) 69812752Ssam ttyflush(tp, FREAD|FWRITE); 6999578Ssam ttyecho(c, tp); 7009578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7019578Ssam goto endcase; 7029578Ssam } 7039578Ssam 7049578Ssam /* 7059578Ssam * Cbreak mode, don't process line editing 7069578Ssam * characters; check high water mark for wakeup. 7079578Ssam */ 7089578Ssam if (t_flags&CBREAK) { 7099578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7107502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7117502Sroot tp->t_line == NTTYDISC) 7127502Sroot (void) ttyoutput(CTRL(g), tp); 7137502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7147502Sroot ttwakeup(tp); 7157502Sroot ttyecho(c, tp); 7167502Sroot } 7179578Ssam goto endcase; 7189578Ssam } 7199578Ssam 7209578Ssam /* 7219578Ssam * From here on down cooked mode character 7229578Ssam * processing takes place. 7239578Ssam */ 7249578Ssam if ((tp->t_state&TS_QUOT) && 7259578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7269578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7279578Ssam c |= 0200; 7289578Ssam } 7299578Ssam if (c == tp->t_erase) { 7309578Ssam if (tp->t_rawq.c_cc) 7319578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7329578Ssam goto endcase; 7339578Ssam } 7349578Ssam if (c == tp->t_kill) { 7359578Ssam if (tp->t_flags&CRTKIL && 7369578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7379578Ssam while (tp->t_rawq.c_cc) 7389578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7399578Ssam } else { 7409578Ssam ttyecho(c, tp); 7419578Ssam ttyecho('\n', tp); 7429578Ssam while (getc(&tp->t_rawq) > 0) 7439578Ssam ; 7449578Ssam tp->t_rocount = 0; 7459578Ssam } 7469578Ssam tp->t_state &= ~TS_LOCAL; 7479578Ssam goto endcase; 7489578Ssam } 7499578Ssam 7509578Ssam /* 7519578Ssam * New line discipline, 7529578Ssam * check word erase/reprint line. 7539578Ssam */ 7549578Ssam if (tp->t_line == NTTYDISC) { 7559578Ssam if (c == tp->t_werasc) { 7569578Ssam if (tp->t_rawq.c_cc == 0) 7579578Ssam goto endcase; 7589578Ssam do { 7599578Ssam c = unputc(&tp->t_rawq); 7609578Ssam if (c != ' ' && c != '\t') 7619578Ssam goto erasenb; 7629578Ssam ttyrub(c, tp); 7639578Ssam } while (tp->t_rawq.c_cc); 7649578Ssam goto endcase; 7659578Ssam erasenb: 7669578Ssam do { 7679578Ssam ttyrub(c, tp); 7689578Ssam if (tp->t_rawq.c_cc == 0) 7699578Ssam goto endcase; 7709578Ssam c = unputc(&tp->t_rawq); 7719578Ssam } while (c != ' ' && c != '\t'); 7729578Ssam (void) putc(c, &tp->t_rawq); 7739578Ssam goto endcase; 7749578Ssam } 7759578Ssam if (c == tp->t_rprntc) { 7769578Ssam ttyretype(tp); 7779578Ssam goto endcase; 7789578Ssam } 7799578Ssam } 7809578Ssam 7819578Ssam /* 7829578Ssam * Check for input buffer overflow 7839578Ssam */ 78410391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 78510391Ssam if (tp->t_line == NTTYDISC) 78610391Ssam (void) ttyoutput(CTRL(g), tp); 7879578Ssam goto endcase; 78810391Ssam } 7899578Ssam 7909578Ssam /* 7919578Ssam * Put data char in q for user and 7929578Ssam * wakeup on seeing a line delimiter. 7939578Ssam */ 7949578Ssam if (putc(c, &tp->t_rawq) >= 0) { 7959578Ssam if (ttbreakc(c, tp)) { 7969578Ssam tp->t_rocount = 0; 7979578Ssam catq(&tp->t_rawq, &tp->t_canq); 7987502Sroot ttwakeup(tp); 7999578Ssam } else if (tp->t_rocount++ == 0) 8009578Ssam tp->t_rocol = tp->t_col; 8019578Ssam tp->t_state &= ~TS_QUOT; 8029578Ssam if (c == '\\') 8039578Ssam tp->t_state |= TS_QUOT; 8049578Ssam if (tp->t_state&TS_ERASE) { 8059578Ssam tp->t_state &= ~TS_ERASE; 8069578Ssam (void) ttyoutput('/', tp); 8079578Ssam } 8089578Ssam i = tp->t_col; 8097502Sroot ttyecho(c, tp); 8109578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8119578Ssam i = MIN(2, tp->t_col - i); 8129578Ssam while (i > 0) { 8139578Ssam (void) ttyoutput('\b', tp); 8149578Ssam i--; 8159578Ssam } 8169578Ssam } 8177502Sroot } 8189578Ssam 8199578Ssam endcase: 8209578Ssam /* 8219578Ssam * If DEC-style start/stop is enabled don't restart 8229578Ssam * output until seeing the start character. 8239578Ssam */ 8249578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8259578Ssam tp->t_startc != tp->t_stopc) 8267502Sroot return; 8279578Ssam 8289578Ssam restartoutput: 8297502Sroot tp->t_state &= ~TS_TTSTOP; 8309578Ssam tp->t_flags &= ~FLUSHO; 8319578Ssam 8329578Ssam startoutput: 8337502Sroot ttstart(tp); 8347502Sroot } 8357502Sroot 8367502Sroot /* 8379578Ssam * Put character on TTY output queue, adding delays, 8387502Sroot * expanding tabs, and handling the CR/NL bit. 8399578Ssam * This is called both from the top half for output, 8409578Ssam * and from interrupt level for echoing. 8417502Sroot * The arguments are the character and the tty structure. 8427502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8437502Sroot * Must be recursive. 8447502Sroot */ 8457502Sroot ttyoutput(c, tp) 8467502Sroot register c; 8477502Sroot register struct tty *tp; 8487502Sroot { 8497502Sroot register char *colp; 8507502Sroot register ctype; 8517502Sroot 8529578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8539578Ssam if (tp->t_flags&FLUSHO) 8547502Sroot return (-1); 8557502Sroot if (putc(c, &tp->t_outq)) 8567625Ssam return (c); 8577502Sroot tk_nout++; 8587502Sroot return (-1); 8597502Sroot } 8609578Ssam 8617502Sroot /* 8629578Ssam * Ignore EOT in normal mode to avoid 8639578Ssam * hanging up certain terminals. 8647502Sroot */ 8657502Sroot c &= 0177; 8669578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8677502Sroot return (-1); 8687502Sroot /* 8697502Sroot * Turn tabs to spaces as required 8707502Sroot */ 8719578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8727502Sroot register int s; 8737502Sroot 8747502Sroot c = 8 - (tp->t_col&7); 8759578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8767502Sroot s = spl5(); /* don't interrupt tabs */ 8777502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8787502Sroot tk_nout += c; 8797502Sroot splx(s); 8807502Sroot } 8817502Sroot tp->t_col += c; 8827502Sroot return (c ? -1 : '\t'); 8837502Sroot } 8847502Sroot tk_nout++; 8857502Sroot /* 8867502Sroot * for upper-case-only terminals, 8877502Sroot * generate escapes. 8887502Sroot */ 8897502Sroot if (tp->t_flags&LCASE) { 8907502Sroot colp = "({)}!|^~'`"; 8917625Ssam while (*colp++) 8927625Ssam if (c == *colp++) { 8937502Sroot if (ttyoutput('\\', tp) >= 0) 8947502Sroot return (c); 8957502Sroot c = colp[-2]; 8967502Sroot break; 8977502Sroot } 8989578Ssam if ('A' <= c && c <= 'Z') { 8997502Sroot if (ttyoutput('\\', tp) >= 0) 9007502Sroot return (c); 9019578Ssam } else if ('a' <= c && c <= 'z') 9027502Sroot c += 'A' - 'a'; 9037502Sroot } 9049578Ssam 9057502Sroot /* 9067502Sroot * turn <nl> to <cr><lf> if desired. 9077502Sroot */ 9089578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9097502Sroot if (ttyoutput('\r', tp) >= 0) 9107502Sroot return (c); 9119578Ssam if (c == '~' && tp->t_flags&TILDE) 9127502Sroot c = '`'; 9139578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9147502Sroot return (c); 9157502Sroot /* 9167502Sroot * Calculate delays. 9177502Sroot * The numbers here represent clock ticks 9187502Sroot * and are not necessarily optimal for all terminals. 9197502Sroot * The delays are indicated by characters above 0200. 9207502Sroot * In raw mode there are no delays and the 9217502Sroot * transmission path is 8 bits wide. 9229578Ssam * 9239578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9247502Sroot */ 9257502Sroot colp = &tp->t_col; 9267502Sroot ctype = partab[c]; 9277502Sroot c = 0; 9287502Sroot switch (ctype&077) { 9297502Sroot 9307502Sroot case ORDINARY: 9317502Sroot (*colp)++; 9327502Sroot 9337502Sroot case CONTROL: 9347502Sroot break; 9357502Sroot 9367502Sroot case BACKSPACE: 9377502Sroot if (*colp) 9387502Sroot (*colp)--; 9397502Sroot break; 9407502Sroot 9417502Sroot case NEWLINE: 9427502Sroot ctype = (tp->t_flags >> 8) & 03; 9437625Ssam if (ctype == 1) { /* tty 37 */ 94412752Ssam if (*colp > 0) 9457502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9469578Ssam } else if (ctype == 2) /* vt05 */ 9477502Sroot c = 6; 9487502Sroot *colp = 0; 9497502Sroot break; 9507502Sroot 9517502Sroot case TAB: 9527502Sroot ctype = (tp->t_flags >> 10) & 03; 9537625Ssam if (ctype == 1) { /* tty 37 */ 9547502Sroot c = 1 - (*colp | ~07); 9557625Ssam if (c < 5) 9567502Sroot c = 0; 9577502Sroot } 9587502Sroot *colp |= 07; 9597502Sroot (*colp)++; 9607502Sroot break; 9617502Sroot 9627502Sroot case VTAB: 9639578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9647502Sroot c = 0177; 9657502Sroot break; 9667502Sroot 9677502Sroot case RETURN: 9687502Sroot ctype = (tp->t_flags >> 12) & 03; 9699578Ssam if (ctype == 1) /* tn 300 */ 9707502Sroot c = 5; 9719578Ssam else if (ctype == 2) /* ti 700 */ 9727502Sroot c = 10; 9739578Ssam else if (ctype == 3) { /* concept 100 */ 9747502Sroot int i; 9759578Ssam 9767502Sroot if ((i = *colp) >= 0) 9779578Ssam for (; i < 9; i++) 9787502Sroot (void) putc(0177, &tp->t_outq); 9797502Sroot } 9807502Sroot *colp = 0; 9817502Sroot } 9829578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9837502Sroot (void) putc(c|0200, &tp->t_outq); 9847502Sroot return (-1); 9857502Sroot } 9867502Sroot 9877502Sroot /* 9887502Sroot * Called from device's read routine after it has 9897502Sroot * calculated the tty-structure given as argument. 9907502Sroot */ 9917722Swnj ttread(tp, uio) 9927625Ssam register struct tty *tp; 9937722Swnj struct uio *uio; 9947502Sroot { 9957502Sroot register struct clist *qp; 9969578Ssam register c, t_flags; 9979859Ssam int s, first, error = 0; 9987502Sroot 9997502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10008520Sroot return (EIO); 10017502Sroot loop: 10029578Ssam /* 10039578Ssam * Take any pending input first. 10049578Ssam */ 10059859Ssam s = spl5(); 10069578Ssam if (tp->t_flags&PENDIN) 10077502Sroot ttypend(tp); 10089859Ssam splx(s); 10099578Ssam 10109578Ssam /* 10119578Ssam * Hang process if it's in the background. 10129578Ssam */ 10137502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 10147502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 10157502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 10167502Sroot /* 10177502Sroot (u.u_procp->p_flag&SDETACH) || 10187502Sroot */ 10197502Sroot u.u_procp->p_flag&SVFORK) 10208520Sroot return (EIO); 10217502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10227502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10237502Sroot } 10249578Ssam t_flags = tp->t_flags; 10259578Ssam 10269578Ssam /* 10279578Ssam * In raw mode take characters directly from the 10289578Ssam * raw queue w/o processing. Interlock against 10299578Ssam * device interrupts when interrogating rawq. 10309578Ssam */ 10319578Ssam if (t_flags&RAW) { 10329859Ssam s = spl5(); 10337502Sroot if (tp->t_rawq.c_cc <= 0) { 10349578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10357502Sroot (tp->t_state&TS_NBIO)) { 10369859Ssam splx(s); 10379578Ssam return (0); 10387502Sroot } 10397502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10409859Ssam splx(s); 10417502Sroot goto loop; 10427502Sroot } 10439859Ssam splx(s); 10449859Ssam while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt) 10458520Sroot error = passuc(getc(&tp->t_rawq), uio); 10469859Ssam goto checktandem; 10479578Ssam } 10489578Ssam 10499578Ssam /* 10509578Ssam * In cbreak mode use the rawq, otherwise 10519578Ssam * take characters from the canonicalized q. 10529578Ssam */ 10539578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10549578Ssam 10559578Ssam /* 10569578Ssam * No input, sleep on rawq awaiting hardware 10579578Ssam * receipt and notification. 10589578Ssam */ 10599859Ssam s = spl5(); 10609578Ssam if (qp->c_cc <= 0) { 10619578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10629578Ssam (tp->t_state&TS_NBIO)) { 10639859Ssam splx(s); 10649578Ssam return (EWOULDBLOCK); 10657502Sroot } 10669578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10679859Ssam splx(s); 10689578Ssam goto loop; 10699578Ssam } 10709859Ssam splx(s); 10719578Ssam 10729578Ssam /* 10739578Ssam * Input present, perform input mapping 10749578Ssam * and processing (we're not in raw mode). 10759578Ssam */ 10769578Ssam first = 1; 10779578Ssam while ((c = getc(qp)) >= 0) { 10789578Ssam if (t_flags&CRMOD && c == '\r') 10799578Ssam c = '\n'; 10809578Ssam /* 10819578Ssam * Hack lower case simulation on 10829578Ssam * upper case only terminals. 10839578Ssam */ 10849578Ssam if (t_flags&LCASE && c <= 0177) 10859578Ssam if (tp->t_state&TS_BKSL) { 10869578Ssam if (maptab[c]) 10879578Ssam c = maptab[c]; 10889578Ssam tp->t_state &= ~TS_BKSL; 10899578Ssam } else if (c >= 'A' && c <= 'Z') 10909578Ssam c += 'a' - 'A'; 10919578Ssam else if (c == '\\') { 10929578Ssam tp->t_state |= TS_BKSL; 10939578Ssam continue; 10947502Sroot } 10959578Ssam /* 10969578Ssam * Check for delayed suspend character. 10979578Ssam */ 10989578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 10999578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11009578Ssam if (first) { 11019578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11029578Ssam goto loop; 11039578Ssam } 11049578Ssam break; 11057502Sroot } 11069578Ssam /* 11079578Ssam * Interpret EOF only in cooked mode. 11089578Ssam */ 11099578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11109578Ssam break; 11119578Ssam /* 11129578Ssam * Give user character. 11139578Ssam */ 11149578Ssam error = passuc(c & 0177, uio); 11159578Ssam if (error) 11169578Ssam break; 11179578Ssam if (uio->uio_iovcnt == 0) 11189578Ssam break; 11199578Ssam /* 11209578Ssam * In cooked mode check for a "break character" 11219578Ssam * marking the end of a "line of input". 11229578Ssam */ 11239578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11249578Ssam break; 11259578Ssam first = 0; 11267502Sroot } 11279578Ssam tp->t_state &= ~TS_BKSL; 11289578Ssam 11299859Ssam checktandem: 11309578Ssam /* 11319578Ssam * Look to unblock output now that (presumably) 11329578Ssam * the input queue has gone down. 11339578Ssam */ 11349859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11359578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11367502Sroot tp->t_state &= ~TS_TBLOCK; 11377502Sroot ttstart(tp); 11387502Sroot } 11398520Sroot return (error); 11407502Sroot } 11417502Sroot 11427502Sroot /* 11437502Sroot * Called from the device's write routine after it has 11447502Sroot * calculated the tty-structure given as argument. 11457502Sroot */ 11467822Sroot ttwrite(tp, uio) 11477625Ssam register struct tty *tp; 11489578Ssam register struct uio *uio; 11497502Sroot { 11507502Sroot register char *cp; 11519578Ssam register int cc, ce, c; 11529578Ssam int i, hiwat, cnt, error, s; 11537502Sroot char obuf[OBUFSIZ]; 11547502Sroot 11559578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11568520Sroot return (EIO); 11579578Ssam hiwat = TTHIWAT(tp); 11589578Ssam cnt = uio->uio_resid; 11599578Ssam error = 0; 11607502Sroot loop: 11619578Ssam /* 11629578Ssam * Hang the process if it's in the background. 11639578Ssam */ 11647502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11659578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11667502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11677502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11687502Sroot /* 11697502Sroot && 11707502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11717502Sroot */ 11727502Sroot ) { 11737502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11747502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11757502Sroot } 11769578Ssam 11779578Ssam /* 11789578Ssam * Process the user's data in at most OBUFSIZ 11799578Ssam * chunks. Perform lower case simulation and 11809578Ssam * similar hacks. Keep track of high water 11819578Ssam * mark, sleep on overflow awaiting device aid 11829578Ssam * in acquiring new space. 11839578Ssam */ 11847822Sroot while (uio->uio_resid > 0) { 11859578Ssam /* 11869578Ssam * Grab a hunk of data from the user. 11879578Ssam */ 11887822Sroot cc = uio->uio_iov->iov_len; 11897822Sroot if (cc == 0) { 11907822Sroot uio->uio_iovcnt--; 11917822Sroot uio->uio_iov++; 11927822Sroot if (uio->uio_iovcnt < 0) 11937822Sroot panic("ttwrite"); 11947822Sroot continue; 11957822Sroot } 11967822Sroot if (cc > OBUFSIZ) 11977822Sroot cc = OBUFSIZ; 11987502Sroot cp = obuf; 119912752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12008520Sroot if (error) 12017502Sroot break; 12027502Sroot if (tp->t_outq.c_cc > hiwat) 12037502Sroot goto ovhiwat; 12049578Ssam if (tp->t_flags&FLUSHO) 12057502Sroot continue; 12069578Ssam /* 12079578Ssam * If we're mapping lower case or kludging tildes, 12089578Ssam * then we've got to look at each character, so 12099578Ssam * just feed the stuff to ttyoutput... 12109578Ssam */ 12119578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12129578Ssam while (cc > 0) { 12137502Sroot c = *cp++; 12147502Sroot tp->t_rocount = 0; 12157625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12167502Sroot /* out of clists, wait a bit */ 12177502Sroot ttstart(tp); 12187502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12197502Sroot tp->t_rocount = 0; 12207502Sroot } 12217502Sroot --cc; 12227502Sroot if (tp->t_outq.c_cc > hiwat) 12237502Sroot goto ovhiwat; 12247502Sroot } 12257502Sroot continue; 12267502Sroot } 12279578Ssam /* 12289578Ssam * If nothing fancy need be done, grab those characters we 12299578Ssam * can handle without any of ttyoutput's processing and 12309578Ssam * just transfer them to the output q. For those chars 12319578Ssam * which require special processing (as indicated by the 12329578Ssam * bits in partab), call ttyoutput. After processing 12339578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12349578Ssam * immediately. 12359578Ssam */ 12369578Ssam while (cc > 0) { 12379578Ssam if (tp->t_flags & (RAW|LITOUT)) 12387502Sroot ce = cc; 12397502Sroot else { 124012752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 124112752Ssam (caddr_t)partab, 077); 12429578Ssam /* 12439578Ssam * If ce is zero, then we're processing 12449578Ssam * a special character through ttyoutput. 12459578Ssam */ 12469578Ssam if (ce == 0) { 12477502Sroot tp->t_rocount = 0; 12487502Sroot if (ttyoutput(*cp, tp) >= 0) { 12499578Ssam /* no c-lists, wait a bit */ 12507502Sroot ttstart(tp); 12517502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12527502Sroot continue; 12537502Sroot } 12549578Ssam cp++, cc--; 12559578Ssam if (tp->t_flags&FLUSHO || 12569578Ssam tp->t_outq.c_cc > hiwat) 12577502Sroot goto ovhiwat; 12589578Ssam continue; 12597502Sroot } 12607502Sroot } 12619578Ssam /* 12629578Ssam * A bunch of normal characters have been found, 12639578Ssam * transfer them en masse to the output queue and 12649578Ssam * continue processing at the top of the loop. 12659578Ssam * If there are any further characters in this 12669578Ssam * <= OBUFSIZ chunk, the first should be a character 12679578Ssam * requiring special handling by ttyoutput. 12689578Ssam */ 12697502Sroot tp->t_rocount = 0; 12709578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12719578Ssam ce -= i; 12729578Ssam tp->t_col += ce; 12739578Ssam cp += ce, cc -= ce, tk_nout += ce; 12749578Ssam if (i > 0) { 12759578Ssam /* out of c-lists, wait a bit */ 12767502Sroot ttstart(tp); 12777502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12787502Sroot } 12799578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12807502Sroot goto ovhiwat; 12817502Sroot } 12827502Sroot } 12837502Sroot ttstart(tp); 12848520Sroot return (error); 12857502Sroot 12867502Sroot ovhiwat: 12879578Ssam s = spl5(); 12889578Ssam if (cc != 0) { 12899578Ssam uio->uio_iov->iov_base -= cc; 12909578Ssam uio->uio_iov->iov_len += cc; 12919578Ssam uio->uio_resid += cc; 12929578Ssam uio->uio_offset -= cc; 12939578Ssam } 12949578Ssam /* 12959578Ssam * This can only occur if FLUSHO 12969578Ssam * is also set in t_flags. 12979578Ssam */ 12987502Sroot if (tp->t_outq.c_cc <= hiwat) { 12999578Ssam splx(s); 13007502Sroot goto loop; 13017502Sroot } 13027502Sroot ttstart(tp); 13039578Ssam if (tp->t_state&TS_NBIO) { 13047822Sroot if (uio->uio_resid == cnt) 13058520Sroot return (EWOULDBLOCK); 13068520Sroot return (0); 13077502Sroot } 13087502Sroot tp->t_state |= TS_ASLEEP; 13097502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13109578Ssam splx(s); 13117502Sroot goto loop; 13127502Sroot } 13137502Sroot 13147502Sroot /* 13157502Sroot * Rubout one character from the rawq of tp 13167502Sroot * as cleanly as possible. 13177502Sroot */ 13187502Sroot ttyrub(c, tp) 13197625Ssam register c; 13207625Ssam register struct tty *tp; 13217502Sroot { 13227502Sroot register char *cp; 13237502Sroot register int savecol; 13247502Sroot int s; 13257502Sroot char *nextc(); 13267502Sroot 13279578Ssam if ((tp->t_flags&ECHO) == 0) 13287502Sroot return; 13299578Ssam tp->t_flags &= ~FLUSHO; 13307502Sroot c &= 0377; 13319578Ssam if (tp->t_flags&CRTBS) { 13327502Sroot if (tp->t_rocount == 0) { 13337502Sroot /* 13347502Sroot * Screwed by ttwrite; retype 13357502Sroot */ 13367502Sroot ttyretype(tp); 13377502Sroot return; 13387502Sroot } 13399578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13407502Sroot ttyrubo(tp, 2); 13419578Ssam else switch (partab[c&=0177]&0177) { 13427502Sroot 13437502Sroot case ORDINARY: 13447502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13457502Sroot ttyrubo(tp, 2); 13467502Sroot else 13477502Sroot ttyrubo(tp, 1); 13487502Sroot break; 13497502Sroot 13507502Sroot case VTAB: 13517502Sroot case BACKSPACE: 13527502Sroot case CONTROL: 13537502Sroot case RETURN: 13549578Ssam if (tp->t_flags&CTLECH) 13557502Sroot ttyrubo(tp, 2); 13567502Sroot break; 13577502Sroot 13587502Sroot case TAB: 13597502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13607502Sroot ttyretype(tp); 13617502Sroot return; 13627502Sroot } 13637502Sroot s = spl5(); 13647502Sroot savecol = tp->t_col; 13659578Ssam tp->t_state |= TS_CNTTB; 13669578Ssam tp->t_flags |= FLUSHO; 13677502Sroot tp->t_col = tp->t_rocol; 13689578Ssam cp = tp->t_rawq.c_cf; 13699578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13707502Sroot ttyecho(*cp, tp); 13719578Ssam tp->t_flags &= ~FLUSHO; 13729578Ssam tp->t_state &= ~TS_CNTTB; 13737502Sroot splx(s); 13747502Sroot /* 13757502Sroot * savecol will now be length of the tab 13767502Sroot */ 13777502Sroot savecol -= tp->t_col; 13787502Sroot tp->t_col += savecol; 13797502Sroot if (savecol > 8) 13807502Sroot savecol = 8; /* overflow screw */ 13817502Sroot while (--savecol >= 0) 13827502Sroot (void) ttyoutput('\b', tp); 13837502Sroot break; 13847502Sroot 13857502Sroot default: 13867502Sroot panic("ttyrub"); 13877502Sroot } 13889578Ssam } else if (tp->t_flags&PRTERA) { 13899578Ssam if ((tp->t_state&TS_ERASE) == 0) { 13907502Sroot (void) ttyoutput('\\', tp); 13919578Ssam tp->t_state |= TS_ERASE; 13927502Sroot } 13937502Sroot ttyecho(c, tp); 13947502Sroot } else 13957502Sroot ttyecho(tp->t_erase, tp); 13967502Sroot tp->t_rocount--; 13977502Sroot } 13987502Sroot 13997502Sroot /* 14007502Sroot * Crt back over cnt chars perhaps 14017502Sroot * erasing them. 14027502Sroot */ 14037502Sroot ttyrubo(tp, cnt) 14047625Ssam register struct tty *tp; 14057625Ssam int cnt; 14067502Sroot { 14079578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14087502Sroot 14097502Sroot while (--cnt >= 0) 14109578Ssam ttyout(rubostring, tp); 14117502Sroot } 14127502Sroot 14137502Sroot /* 14147502Sroot * Reprint the rawq line. 14157502Sroot * We assume c_cc has already been checked. 14167502Sroot */ 14177502Sroot ttyretype(tp) 14187625Ssam register struct tty *tp; 14197502Sroot { 14207502Sroot register char *cp; 14217502Sroot char *nextc(); 14227502Sroot int s; 14237502Sroot 14249578Ssam if (tp->t_rprntc != 0377) 14259578Ssam ttyecho(tp->t_rprntc, tp); 14267502Sroot (void) ttyoutput('\n', tp); 14277502Sroot s = spl5(); 14287502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14297502Sroot ttyecho(*cp, tp); 14307502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14317502Sroot ttyecho(*cp, tp); 14329578Ssam tp->t_state &= ~TS_ERASE; 14337502Sroot splx(s); 14347502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14357502Sroot tp->t_rocol = 0; 14367502Sroot } 14377502Sroot 14387502Sroot /* 14397502Sroot * Echo a typed character to the terminal 14407502Sroot */ 14417502Sroot ttyecho(c, tp) 14427625Ssam register c; 14437625Ssam register struct tty *tp; 14447502Sroot { 14457502Sroot 14469578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14479578Ssam tp->t_flags &= ~FLUSHO; 14487502Sroot if ((tp->t_flags&ECHO) == 0) 14497502Sroot return; 14507502Sroot c &= 0377; 14517502Sroot if (tp->t_flags&RAW) { 14527502Sroot (void) ttyoutput(c, tp); 14537502Sroot return; 14547502Sroot } 14557502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14567502Sroot c = '\n'; 14579578Ssam if (tp->t_flags&CTLECH) { 14587502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14597502Sroot (void) ttyoutput('^', tp); 14607502Sroot c &= 0177; 14617502Sroot if (c == 0177) 14627502Sroot c = '?'; 14637502Sroot else if (tp->t_flags&LCASE) 14647502Sroot c += 'a' - 1; 14657502Sroot else 14667502Sroot c += 'A' - 1; 14677502Sroot } 14687502Sroot } 14697502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14707502Sroot c += 'a' - 'A'; 14719578Ssam (void) ttyoutput(c&0177, tp); 14727502Sroot } 14737502Sroot 14747502Sroot /* 14757502Sroot * Is c a break char for tp? 14767502Sroot */ 14777502Sroot ttbreakc(c, tp) 14787625Ssam register c; 14797625Ssam register struct tty *tp; 14807502Sroot { 14819578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14827502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14837502Sroot } 14847502Sroot 14857502Sroot /* 14867502Sroot * send string cp to tp 14877502Sroot */ 14887502Sroot ttyout(cp, tp) 14897625Ssam register char *cp; 14907625Ssam register struct tty *tp; 14917502Sroot { 14927502Sroot register char c; 14937502Sroot 14947502Sroot while (c = *cp++) 14957502Sroot (void) ttyoutput(c, tp); 14967502Sroot } 14977502Sroot 14987502Sroot ttwakeup(tp) 14997502Sroot struct tty *tp; 15007502Sroot { 15017502Sroot 15027502Sroot if (tp->t_rsel) { 15037502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15047502Sroot tp->t_state &= ~TS_RCOLL; 15057502Sroot tp->t_rsel = 0; 15067502Sroot } 150712752Ssam if (tp->t_state & TS_ASYNC) 150812752Ssam gsignal(tp->t_pgrp, SIGIO); 15097502Sroot wakeup((caddr_t)&tp->t_rawq); 15107502Sroot } 15117502Sroot 1512*13533Ssam #if !defined(vax) 15139578Ssam scanc(size, cp, table, mask) 15149578Ssam register int size; 15159578Ssam register char *cp, table[]; 15169578Ssam register int mask; 15177502Sroot { 15189578Ssam register int i = 0; 15197502Sroot 15209578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15219578Ssam i++; 15229578Ssam return (i); 15237502Sroot } 15249578Ssam #endif 1525