1*13809Ssam /* tty.c 4.45 83/07/06 */ 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 128*13809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 129*13809Ssam tp->t_state&TS_CARR_ON && 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; 38313801Ssam newflags |= PENDIN; 38412752Ssam ttwakeup(tp); 38512752Ssam } 38612752Ssam } 38712752Ssam tp->t_flags = newflags; 38812752Ssam if (tp->t_flags&RAW) { 38912752Ssam tp->t_state &= ~TS_TTSTOP; 39012752Ssam ttstart(tp); 39112752Ssam } 39212752Ssam splx(s); 39312752Ssam break; 39412752Ssam } 39512752Ssam 39612752Ssam /* send current parameters to user */ 39712752Ssam case TIOCGETP: { 39812752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 39912752Ssam 40012752Ssam sg->sg_ispeed = tp->t_ispeed; 40112752Ssam sg->sg_ospeed = tp->t_ospeed; 40212752Ssam sg->sg_erase = tp->t_erase; 40312752Ssam sg->sg_kill = tp->t_kill; 40412752Ssam sg->sg_flags = tp->t_flags; 40512752Ssam break; 40612752Ssam } 40712752Ssam 40812752Ssam case FIONBIO: 40912752Ssam if (*(int *)data) 41012752Ssam tp->t_state |= TS_NBIO; 41112752Ssam else 41212752Ssam tp->t_state &= ~TS_NBIO; 41312752Ssam break; 41412752Ssam 41512752Ssam case FIOASYNC: 41612752Ssam if (*(int *)data) 41712752Ssam tp->t_state |= TS_ASYNC; 41812752Ssam else 41912752Ssam tp->t_state &= ~TS_ASYNC; 42012752Ssam break; 42112752Ssam 42213077Ssam case TIOCGETC: 42313077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 42413077Ssam break; 42513077Ssam 42613077Ssam case TIOCSETC: 42713077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 42813077Ssam break; 42913077Ssam 43012752Ssam /* set/get local special characters */ 43112752Ssam case TIOCSLTC: 43212752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 43312752Ssam break; 43412752Ssam 43512752Ssam case TIOCGLTC: 43612752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 43712752Ssam break; 43812752Ssam 43912752Ssam /* 44012752Ssam * Modify local mode word. 44112752Ssam */ 44212752Ssam case TIOCLBIS: 44312752Ssam tp->t_flags |= *(int *)data << 16; 44412752Ssam break; 44512752Ssam 44612752Ssam case TIOCLBIC: 44712752Ssam tp->t_flags &= ~(*(int *)data << 16); 44812752Ssam break; 44912752Ssam 45012752Ssam case TIOCLSET: 45112752Ssam tp->t_flags &= 0xffff; 45212752Ssam tp->t_flags |= *(int *)data << 16; 45312752Ssam break; 45412752Ssam 45512752Ssam case TIOCLGET: 45612752Ssam *(int *)data = tp->t_flags >> 16; 45712752Ssam break; 45812752Ssam 45912752Ssam /* should allow SPGRP and GPGRP only if tty open for reading */ 46012752Ssam case TIOCSPGRP: 46112752Ssam tp->t_pgrp = *(int *)data; 46212752Ssam break; 46312752Ssam 46412752Ssam case TIOCGPGRP: 46512752Ssam *(int *)data = tp->t_pgrp; 46612752Ssam break; 46712752Ssam 46839Sbill default: 4698556Sroot return (-1); 47039Sbill } 4718556Sroot return (0); 47239Sbill } 4734484Swnj 4744484Swnj ttnread(tp) 4754484Swnj struct tty *tp; 4764484Swnj { 4774484Swnj int nread = 0; 4784484Swnj 4799578Ssam if (tp->t_flags & PENDIN) 4804484Swnj ttypend(tp); 4814484Swnj nread = tp->t_canq.c_cc; 4824484Swnj if (tp->t_flags & (RAW|CBREAK)) 4834484Swnj nread += tp->t_rawq.c_cc; 4844484Swnj return (nread); 4854484Swnj } 4864484Swnj 4875408Swnj ttselect(dev, rw) 4884484Swnj dev_t dev; 4895408Swnj int rw; 4904484Swnj { 4914484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4924484Swnj int nread; 4935408Swnj int s = spl5(); 4944484Swnj 4955408Swnj switch (rw) { 4964484Swnj 4974484Swnj case FREAD: 4984484Swnj nread = ttnread(tp); 4994484Swnj if (nread > 0) 5005408Swnj goto win; 5014938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5025408Swnj tp->t_state |= TS_RCOLL; 5034484Swnj else 5044484Swnj tp->t_rsel = u.u_procp; 5055408Swnj break; 5064484Swnj 5075408Swnj case FWRITE: 5085408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5095408Swnj goto win; 5105408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5115408Swnj tp->t_state |= TS_WCOLL; 5125408Swnj else 5135408Swnj tp->t_wsel = u.u_procp; 5145408Swnj break; 5154484Swnj } 5165408Swnj splx(s); 5175408Swnj return (0); 5185408Swnj win: 5195408Swnj splx(s); 5205408Swnj return (1); 5214484Swnj } 5227436Skre 5237502Sroot /* 5249578Ssam * Establish a process group for distribution of 5257502Sroot * quits and interrupts from the tty. 5267502Sroot */ 5277502Sroot ttyopen(dev, tp) 5287625Ssam dev_t dev; 5297625Ssam register struct tty *tp; 5307502Sroot { 5317502Sroot register struct proc *pp; 5327502Sroot 5337502Sroot pp = u.u_procp; 5347502Sroot tp->t_dev = dev; 5357625Ssam if (pp->p_pgrp == 0) { 5367502Sroot u.u_ttyp = tp; 5377502Sroot u.u_ttyd = dev; 5387502Sroot if (tp->t_pgrp == 0) 5397502Sroot tp->t_pgrp = pp->p_pid; 5407502Sroot pp->p_pgrp = tp->t_pgrp; 5417502Sroot } 5427502Sroot tp->t_state &= ~TS_WOPEN; 5437502Sroot tp->t_state |= TS_ISOPEN; 5447502Sroot if (tp->t_line != NTTYDISC) 54512752Ssam ttywflush(tp); 5468556Sroot return (0); 5477502Sroot } 5487502Sroot 5497502Sroot /* 5507502Sroot * clean tp on last close 5517502Sroot */ 5527502Sroot ttyclose(tp) 5537625Ssam register struct tty *tp; 5547502Sroot { 5557502Sroot 5567502Sroot if (tp->t_line) { 55712752Ssam ttywflush(tp); 5587502Sroot tp->t_line = 0; 5597502Sroot return; 5607502Sroot } 5617502Sroot tp->t_pgrp = 0; 56212752Ssam ttywflush(tp); 5637502Sroot tp->t_state = 0; 5647502Sroot } 5657502Sroot 5667502Sroot /* 5677502Sroot * reinput pending characters after state switch 5687502Sroot * call at spl5(). 5697502Sroot */ 5707502Sroot ttypend(tp) 5717625Ssam register struct tty *tp; 5727502Sroot { 5737502Sroot struct clist tq; 5747502Sroot register c; 5757502Sroot 5769578Ssam tp->t_flags &= ~PENDIN; 5779578Ssam tp->t_state |= TS_TYPEN; 5787502Sroot tq = tp->t_rawq; 5797502Sroot tp->t_rawq.c_cc = 0; 5807502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5817502Sroot while ((c = getc(&tq)) >= 0) 5827502Sroot ttyinput(c, tp); 5839578Ssam tp->t_state &= ~TS_TYPEN; 5847502Sroot } 5857502Sroot 5867502Sroot /* 5879578Ssam * Place a character on raw TTY input queue, 5889578Ssam * putting in delimiters and waking up top 5899578Ssam * half as needed. Also echo if required. 5909578Ssam * The arguments are the character and the 5919578Ssam * appropriate tty structure. 5927502Sroot */ 5937502Sroot ttyinput(c, tp) 5947625Ssam register c; 5957625Ssam register struct tty *tp; 5967502Sroot { 5979578Ssam register int t_flags = tp->t_flags; 5987502Sroot int i; 5997502Sroot 6009578Ssam /* 6019578Ssam * If input is pending take it first. 6029578Ssam */ 6039578Ssam if (t_flags&PENDIN) 6047502Sroot ttypend(tp); 6057502Sroot tk_nin++; 6067502Sroot c &= 0377; 6079578Ssam 6089578Ssam /* 6099578Ssam * In tandem mode, check high water mark. 6109578Ssam */ 6117502Sroot if (t_flags&TANDEM) 6127502Sroot ttyblock(tp); 6139578Ssam 6149578Ssam if (t_flags&RAW) { 6159578Ssam /* 6169578Ssam * Raw mode, just put character 6179578Ssam * in input q w/o interpretation. 6189578Ssam */ 6199578Ssam if (tp->t_rawq.c_cc > TTYHOG) 62012752Ssam ttyflush(tp, FREAD|FWRITE); 6219578Ssam else { 6229578Ssam if (putc(c, &tp->t_rawq) >= 0) 6239578Ssam ttwakeup(tp); 6249578Ssam ttyecho(c, tp); 6257502Sroot } 6269578Ssam goto endcase; 6279578Ssam } 6289578Ssam 6299578Ssam /* 6309578Ssam * Ignore any high bit added during 6319578Ssam * previous ttyinput processing. 6329578Ssam */ 6339578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6349578Ssam c &= 0177; 6359578Ssam /* 6369578Ssam * Check for literal nexting very first 6379578Ssam */ 6389578Ssam if (tp->t_state&TS_LNCH) { 6399578Ssam c |= 0200; 6409578Ssam tp->t_state &= ~TS_LNCH; 6419578Ssam } 6429578Ssam 6439578Ssam /* 6449578Ssam * Scan for special characters. This code 6459578Ssam * is really just a big case statement with 6469578Ssam * non-constant cases. The bottom of the 6479578Ssam * case statement is labeled ``endcase'', so goto 6489578Ssam * it after a case match, or similar. 6499578Ssam */ 6509578Ssam if (tp->t_line == NTTYDISC) { 6519578Ssam if (c == tp->t_lnextc) { 6527502Sroot if (tp->t_flags&ECHO) 6537502Sroot ttyout("^\b", tp); 6549578Ssam tp->t_state |= TS_LNCH; 6559578Ssam goto endcase; 6569578Ssam } 6579578Ssam if (c == tp->t_flushc) { 6589578Ssam if (tp->t_flags&FLUSHO) 6599578Ssam tp->t_flags &= ~FLUSHO; 6607502Sroot else { 66112752Ssam ttyflush(tp, FWRITE); 6627502Sroot ttyecho(c, tp); 6639578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6647502Sroot ttyretype(tp); 6659578Ssam tp->t_flags |= FLUSHO; 6667502Sroot } 6679578Ssam goto startoutput; 6689578Ssam } 6699578Ssam if (c == tp->t_suspc) { 6709578Ssam if ((tp->t_flags&NOFLSH) == 0) 67112752Ssam ttyflush(tp, FREAD); 6729578Ssam ttyecho(c, tp); 6739578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6749578Ssam goto endcase; 6759578Ssam } 6769578Ssam } 6779578Ssam 6789578Ssam /* 6799578Ssam * Handle start/stop characters. 6809578Ssam */ 6819578Ssam if (c == tp->t_stopc) { 6829578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6839578Ssam tp->t_state |= TS_TTSTOP; 6849578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6857502Sroot return; 6869578Ssam } 6879578Ssam if (c != tp->t_startc) 6889578Ssam return; 6899578Ssam goto endcase; 6909578Ssam } 6919578Ssam if (c == tp->t_startc) 6929578Ssam goto restartoutput; 6939578Ssam 6949578Ssam /* 6959578Ssam * Look for interrupt/quit chars. 6969578Ssam */ 6979578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 6989578Ssam if ((tp->t_flags&NOFLSH) == 0) 69912752Ssam ttyflush(tp, FREAD|FWRITE); 7009578Ssam ttyecho(c, tp); 7019578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7029578Ssam goto endcase; 7039578Ssam } 7049578Ssam 7059578Ssam /* 7069578Ssam * Cbreak mode, don't process line editing 7079578Ssam * characters; check high water mark for wakeup. 7089578Ssam */ 7099578Ssam if (t_flags&CBREAK) { 7109578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7117502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7127502Sroot tp->t_line == NTTYDISC) 7137502Sroot (void) ttyoutput(CTRL(g), tp); 7147502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7157502Sroot ttwakeup(tp); 7167502Sroot ttyecho(c, tp); 7177502Sroot } 7189578Ssam goto endcase; 7199578Ssam } 7209578Ssam 7219578Ssam /* 7229578Ssam * From here on down cooked mode character 7239578Ssam * processing takes place. 7249578Ssam */ 7259578Ssam if ((tp->t_state&TS_QUOT) && 7269578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7279578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7289578Ssam c |= 0200; 7299578Ssam } 7309578Ssam if (c == tp->t_erase) { 7319578Ssam if (tp->t_rawq.c_cc) 7329578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7339578Ssam goto endcase; 7349578Ssam } 7359578Ssam if (c == tp->t_kill) { 7369578Ssam if (tp->t_flags&CRTKIL && 7379578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7389578Ssam while (tp->t_rawq.c_cc) 7399578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7409578Ssam } else { 7419578Ssam ttyecho(c, tp); 7429578Ssam ttyecho('\n', tp); 7439578Ssam while (getc(&tp->t_rawq) > 0) 7449578Ssam ; 7459578Ssam tp->t_rocount = 0; 7469578Ssam } 7479578Ssam tp->t_state &= ~TS_LOCAL; 7489578Ssam goto endcase; 7499578Ssam } 7509578Ssam 7519578Ssam /* 7529578Ssam * New line discipline, 7539578Ssam * check word erase/reprint line. 7549578Ssam */ 7559578Ssam if (tp->t_line == NTTYDISC) { 7569578Ssam if (c == tp->t_werasc) { 7579578Ssam if (tp->t_rawq.c_cc == 0) 7589578Ssam goto endcase; 7599578Ssam do { 7609578Ssam c = unputc(&tp->t_rawq); 7619578Ssam if (c != ' ' && c != '\t') 7629578Ssam goto erasenb; 7639578Ssam ttyrub(c, tp); 7649578Ssam } while (tp->t_rawq.c_cc); 7659578Ssam goto endcase; 7669578Ssam erasenb: 7679578Ssam do { 7689578Ssam ttyrub(c, tp); 7699578Ssam if (tp->t_rawq.c_cc == 0) 7709578Ssam goto endcase; 7719578Ssam c = unputc(&tp->t_rawq); 7729578Ssam } while (c != ' ' && c != '\t'); 7739578Ssam (void) putc(c, &tp->t_rawq); 7749578Ssam goto endcase; 7759578Ssam } 7769578Ssam if (c == tp->t_rprntc) { 7779578Ssam ttyretype(tp); 7789578Ssam goto endcase; 7799578Ssam } 7809578Ssam } 7819578Ssam 7829578Ssam /* 7839578Ssam * Check for input buffer overflow 7849578Ssam */ 78510391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 78610391Ssam if (tp->t_line == NTTYDISC) 78710391Ssam (void) ttyoutput(CTRL(g), tp); 7889578Ssam goto endcase; 78910391Ssam } 7909578Ssam 7919578Ssam /* 7929578Ssam * Put data char in q for user and 7939578Ssam * wakeup on seeing a line delimiter. 7949578Ssam */ 7959578Ssam if (putc(c, &tp->t_rawq) >= 0) { 7969578Ssam if (ttbreakc(c, tp)) { 7979578Ssam tp->t_rocount = 0; 7989578Ssam catq(&tp->t_rawq, &tp->t_canq); 7997502Sroot ttwakeup(tp); 8009578Ssam } else if (tp->t_rocount++ == 0) 8019578Ssam tp->t_rocol = tp->t_col; 8029578Ssam tp->t_state &= ~TS_QUOT; 8039578Ssam if (c == '\\') 8049578Ssam tp->t_state |= TS_QUOT; 8059578Ssam if (tp->t_state&TS_ERASE) { 8069578Ssam tp->t_state &= ~TS_ERASE; 8079578Ssam (void) ttyoutput('/', tp); 8089578Ssam } 8099578Ssam i = tp->t_col; 8107502Sroot ttyecho(c, tp); 8119578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8129578Ssam i = MIN(2, tp->t_col - i); 8139578Ssam while (i > 0) { 8149578Ssam (void) ttyoutput('\b', tp); 8159578Ssam i--; 8169578Ssam } 8179578Ssam } 8187502Sroot } 8199578Ssam 8209578Ssam endcase: 8219578Ssam /* 8229578Ssam * If DEC-style start/stop is enabled don't restart 8239578Ssam * output until seeing the start character. 8249578Ssam */ 8259578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8269578Ssam tp->t_startc != tp->t_stopc) 8277502Sroot return; 8289578Ssam 8299578Ssam restartoutput: 8307502Sroot tp->t_state &= ~TS_TTSTOP; 8319578Ssam tp->t_flags &= ~FLUSHO; 8329578Ssam 8339578Ssam startoutput: 8347502Sroot ttstart(tp); 8357502Sroot } 8367502Sroot 8377502Sroot /* 8389578Ssam * Put character on TTY output queue, adding delays, 8397502Sroot * expanding tabs, and handling the CR/NL bit. 8409578Ssam * This is called both from the top half for output, 8419578Ssam * and from interrupt level for echoing. 8427502Sroot * The arguments are the character and the tty structure. 8437502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8447502Sroot * Must be recursive. 8457502Sroot */ 8467502Sroot ttyoutput(c, tp) 8477502Sroot register c; 8487502Sroot register struct tty *tp; 8497502Sroot { 8507502Sroot register char *colp; 8517502Sroot register ctype; 8527502Sroot 8539578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8549578Ssam if (tp->t_flags&FLUSHO) 8557502Sroot return (-1); 8567502Sroot if (putc(c, &tp->t_outq)) 8577625Ssam return (c); 8587502Sroot tk_nout++; 8597502Sroot return (-1); 8607502Sroot } 8619578Ssam 8627502Sroot /* 8639578Ssam * Ignore EOT in normal mode to avoid 8649578Ssam * hanging up certain terminals. 8657502Sroot */ 8667502Sroot c &= 0177; 8679578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8687502Sroot return (-1); 8697502Sroot /* 8707502Sroot * Turn tabs to spaces as required 8717502Sroot */ 8729578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8737502Sroot register int s; 8747502Sroot 8757502Sroot c = 8 - (tp->t_col&7); 8769578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8777502Sroot s = spl5(); /* don't interrupt tabs */ 8787502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8797502Sroot tk_nout += c; 8807502Sroot splx(s); 8817502Sroot } 8827502Sroot tp->t_col += c; 8837502Sroot return (c ? -1 : '\t'); 8847502Sroot } 8857502Sroot tk_nout++; 8867502Sroot /* 8877502Sroot * for upper-case-only terminals, 8887502Sroot * generate escapes. 8897502Sroot */ 8907502Sroot if (tp->t_flags&LCASE) { 8917502Sroot colp = "({)}!|^~'`"; 8927625Ssam while (*colp++) 8937625Ssam if (c == *colp++) { 8947502Sroot if (ttyoutput('\\', tp) >= 0) 8957502Sroot return (c); 8967502Sroot c = colp[-2]; 8977502Sroot break; 8987502Sroot } 8999578Ssam if ('A' <= c && c <= 'Z') { 9007502Sroot if (ttyoutput('\\', tp) >= 0) 9017502Sroot return (c); 9029578Ssam } else if ('a' <= c && c <= 'z') 9037502Sroot c += 'A' - 'a'; 9047502Sroot } 9059578Ssam 9067502Sroot /* 9077502Sroot * turn <nl> to <cr><lf> if desired. 9087502Sroot */ 9099578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9107502Sroot if (ttyoutput('\r', tp) >= 0) 9117502Sroot return (c); 9129578Ssam if (c == '~' && tp->t_flags&TILDE) 9137502Sroot c = '`'; 9149578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9157502Sroot return (c); 9167502Sroot /* 9177502Sroot * Calculate delays. 9187502Sroot * The numbers here represent clock ticks 9197502Sroot * and are not necessarily optimal for all terminals. 9207502Sroot * The delays are indicated by characters above 0200. 9217502Sroot * In raw mode there are no delays and the 9227502Sroot * transmission path is 8 bits wide. 9239578Ssam * 9249578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9257502Sroot */ 9267502Sroot colp = &tp->t_col; 9277502Sroot ctype = partab[c]; 9287502Sroot c = 0; 9297502Sroot switch (ctype&077) { 9307502Sroot 9317502Sroot case ORDINARY: 9327502Sroot (*colp)++; 9337502Sroot 9347502Sroot case CONTROL: 9357502Sroot break; 9367502Sroot 9377502Sroot case BACKSPACE: 9387502Sroot if (*colp) 9397502Sroot (*colp)--; 9407502Sroot break; 9417502Sroot 9427502Sroot case NEWLINE: 9437502Sroot ctype = (tp->t_flags >> 8) & 03; 9447625Ssam if (ctype == 1) { /* tty 37 */ 94512752Ssam if (*colp > 0) 9467502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9479578Ssam } else if (ctype == 2) /* vt05 */ 9487502Sroot c = 6; 9497502Sroot *colp = 0; 9507502Sroot break; 9517502Sroot 9527502Sroot case TAB: 9537502Sroot ctype = (tp->t_flags >> 10) & 03; 9547625Ssam if (ctype == 1) { /* tty 37 */ 9557502Sroot c = 1 - (*colp | ~07); 9567625Ssam if (c < 5) 9577502Sroot c = 0; 9587502Sroot } 9597502Sroot *colp |= 07; 9607502Sroot (*colp)++; 9617502Sroot break; 9627502Sroot 9637502Sroot case VTAB: 9649578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9657502Sroot c = 0177; 9667502Sroot break; 9677502Sroot 9687502Sroot case RETURN: 9697502Sroot ctype = (tp->t_flags >> 12) & 03; 9709578Ssam if (ctype == 1) /* tn 300 */ 9717502Sroot c = 5; 9729578Ssam else if (ctype == 2) /* ti 700 */ 9737502Sroot c = 10; 9749578Ssam else if (ctype == 3) { /* concept 100 */ 9757502Sroot int i; 9769578Ssam 9777502Sroot if ((i = *colp) >= 0) 9789578Ssam for (; i < 9; i++) 9797502Sroot (void) putc(0177, &tp->t_outq); 9807502Sroot } 9817502Sroot *colp = 0; 9827502Sroot } 9839578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9847502Sroot (void) putc(c|0200, &tp->t_outq); 9857502Sroot return (-1); 9867502Sroot } 9877502Sroot 9887502Sroot /* 9897502Sroot * Called from device's read routine after it has 9907502Sroot * calculated the tty-structure given as argument. 9917502Sroot */ 9927722Swnj ttread(tp, uio) 9937625Ssam register struct tty *tp; 9947722Swnj struct uio *uio; 9957502Sroot { 9967502Sroot register struct clist *qp; 9979578Ssam register c, t_flags; 9989859Ssam int s, first, error = 0; 9997502Sroot 10007502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10018520Sroot return (EIO); 10027502Sroot loop: 10039578Ssam /* 10049578Ssam * Take any pending input first. 10059578Ssam */ 10069859Ssam s = spl5(); 10079578Ssam if (tp->t_flags&PENDIN) 10087502Sroot ttypend(tp); 10099859Ssam splx(s); 10109578Ssam 10119578Ssam /* 10129578Ssam * Hang process if it's in the background. 10139578Ssam */ 10147502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 10157502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 10167502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 10177502Sroot /* 10187502Sroot (u.u_procp->p_flag&SDETACH) || 10197502Sroot */ 10207502Sroot u.u_procp->p_flag&SVFORK) 10218520Sroot return (EIO); 10227502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10237502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10247502Sroot } 10259578Ssam t_flags = tp->t_flags; 10269578Ssam 10279578Ssam /* 10289578Ssam * In raw mode take characters directly from the 10299578Ssam * raw queue w/o processing. Interlock against 10309578Ssam * device interrupts when interrogating rawq. 10319578Ssam */ 10329578Ssam if (t_flags&RAW) { 10339859Ssam s = spl5(); 10347502Sroot if (tp->t_rawq.c_cc <= 0) { 10359578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10367502Sroot (tp->t_state&TS_NBIO)) { 10379859Ssam splx(s); 10389578Ssam return (0); 10397502Sroot } 10407502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10419859Ssam splx(s); 10427502Sroot goto loop; 10437502Sroot } 10449859Ssam splx(s); 10459859Ssam while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt) 10468520Sroot error = passuc(getc(&tp->t_rawq), uio); 10479859Ssam goto checktandem; 10489578Ssam } 10499578Ssam 10509578Ssam /* 10519578Ssam * In cbreak mode use the rawq, otherwise 10529578Ssam * take characters from the canonicalized q. 10539578Ssam */ 10549578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10559578Ssam 10569578Ssam /* 10579578Ssam * No input, sleep on rawq awaiting hardware 10589578Ssam * receipt and notification. 10599578Ssam */ 10609859Ssam s = spl5(); 10619578Ssam if (qp->c_cc <= 0) { 10629578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10639578Ssam (tp->t_state&TS_NBIO)) { 10649859Ssam splx(s); 10659578Ssam return (EWOULDBLOCK); 10667502Sroot } 10679578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10689859Ssam splx(s); 10699578Ssam goto loop; 10709578Ssam } 10719859Ssam splx(s); 10729578Ssam 10739578Ssam /* 10749578Ssam * Input present, perform input mapping 10759578Ssam * and processing (we're not in raw mode). 10769578Ssam */ 10779578Ssam first = 1; 10789578Ssam while ((c = getc(qp)) >= 0) { 10799578Ssam if (t_flags&CRMOD && c == '\r') 10809578Ssam c = '\n'; 10819578Ssam /* 10829578Ssam * Hack lower case simulation on 10839578Ssam * upper case only terminals. 10849578Ssam */ 10859578Ssam if (t_flags&LCASE && c <= 0177) 10869578Ssam if (tp->t_state&TS_BKSL) { 10879578Ssam if (maptab[c]) 10889578Ssam c = maptab[c]; 10899578Ssam tp->t_state &= ~TS_BKSL; 10909578Ssam } else if (c >= 'A' && c <= 'Z') 10919578Ssam c += 'a' - 'A'; 10929578Ssam else if (c == '\\') { 10939578Ssam tp->t_state |= TS_BKSL; 10949578Ssam continue; 10957502Sroot } 10969578Ssam /* 10979578Ssam * Check for delayed suspend character. 10989578Ssam */ 10999578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11009578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11019578Ssam if (first) { 11029578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11039578Ssam goto loop; 11049578Ssam } 11059578Ssam break; 11067502Sroot } 11079578Ssam /* 11089578Ssam * Interpret EOF only in cooked mode. 11099578Ssam */ 11109578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11119578Ssam break; 11129578Ssam /* 11139578Ssam * Give user character. 11149578Ssam */ 11159578Ssam error = passuc(c & 0177, uio); 11169578Ssam if (error) 11179578Ssam break; 11189578Ssam if (uio->uio_iovcnt == 0) 11199578Ssam break; 11209578Ssam /* 11219578Ssam * In cooked mode check for a "break character" 11229578Ssam * marking the end of a "line of input". 11239578Ssam */ 11249578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11259578Ssam break; 11269578Ssam first = 0; 11277502Sroot } 11289578Ssam tp->t_state &= ~TS_BKSL; 11299578Ssam 11309859Ssam checktandem: 11319578Ssam /* 11329578Ssam * Look to unblock output now that (presumably) 11339578Ssam * the input queue has gone down. 11349578Ssam */ 11359859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11369578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11377502Sroot tp->t_state &= ~TS_TBLOCK; 11387502Sroot ttstart(tp); 11397502Sroot } 11408520Sroot return (error); 11417502Sroot } 11427502Sroot 11437502Sroot /* 11447502Sroot * Called from the device's write routine after it has 11457502Sroot * calculated the tty-structure given as argument. 11467502Sroot */ 11477822Sroot ttwrite(tp, uio) 11487625Ssam register struct tty *tp; 11499578Ssam register struct uio *uio; 11507502Sroot { 11517502Sroot register char *cp; 11529578Ssam register int cc, ce, c; 11539578Ssam int i, hiwat, cnt, error, s; 11547502Sroot char obuf[OBUFSIZ]; 11557502Sroot 11569578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11578520Sroot return (EIO); 11589578Ssam hiwat = TTHIWAT(tp); 11599578Ssam cnt = uio->uio_resid; 11609578Ssam error = 0; 11617502Sroot loop: 11629578Ssam /* 11639578Ssam * Hang the process if it's in the background. 11649578Ssam */ 11657502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11669578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11677502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11687502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11697502Sroot /* 11707502Sroot && 11717502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11727502Sroot */ 11737502Sroot ) { 11747502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11757502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11767502Sroot } 11779578Ssam 11789578Ssam /* 11799578Ssam * Process the user's data in at most OBUFSIZ 11809578Ssam * chunks. Perform lower case simulation and 11819578Ssam * similar hacks. Keep track of high water 11829578Ssam * mark, sleep on overflow awaiting device aid 11839578Ssam * in acquiring new space. 11849578Ssam */ 11857822Sroot while (uio->uio_resid > 0) { 11869578Ssam /* 11879578Ssam * Grab a hunk of data from the user. 11889578Ssam */ 11897822Sroot cc = uio->uio_iov->iov_len; 11907822Sroot if (cc == 0) { 11917822Sroot uio->uio_iovcnt--; 11927822Sroot uio->uio_iov++; 11937822Sroot if (uio->uio_iovcnt < 0) 11947822Sroot panic("ttwrite"); 11957822Sroot continue; 11967822Sroot } 11977822Sroot if (cc > OBUFSIZ) 11987822Sroot cc = OBUFSIZ; 11997502Sroot cp = obuf; 120012752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12018520Sroot if (error) 12027502Sroot break; 12037502Sroot if (tp->t_outq.c_cc > hiwat) 12047502Sroot goto ovhiwat; 12059578Ssam if (tp->t_flags&FLUSHO) 12067502Sroot continue; 12079578Ssam /* 12089578Ssam * If we're mapping lower case or kludging tildes, 12099578Ssam * then we've got to look at each character, so 12109578Ssam * just feed the stuff to ttyoutput... 12119578Ssam */ 12129578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12139578Ssam while (cc > 0) { 12147502Sroot c = *cp++; 12157502Sroot tp->t_rocount = 0; 12167625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12177502Sroot /* out of clists, wait a bit */ 12187502Sroot ttstart(tp); 12197502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12207502Sroot tp->t_rocount = 0; 12217502Sroot } 12227502Sroot --cc; 12237502Sroot if (tp->t_outq.c_cc > hiwat) 12247502Sroot goto ovhiwat; 12257502Sroot } 12267502Sroot continue; 12277502Sroot } 12289578Ssam /* 12299578Ssam * If nothing fancy need be done, grab those characters we 12309578Ssam * can handle without any of ttyoutput's processing and 12319578Ssam * just transfer them to the output q. For those chars 12329578Ssam * which require special processing (as indicated by the 12339578Ssam * bits in partab), call ttyoutput. After processing 12349578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12359578Ssam * immediately. 12369578Ssam */ 12379578Ssam while (cc > 0) { 12389578Ssam if (tp->t_flags & (RAW|LITOUT)) 12397502Sroot ce = cc; 12407502Sroot else { 124112752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 124212752Ssam (caddr_t)partab, 077); 12439578Ssam /* 12449578Ssam * If ce is zero, then we're processing 12459578Ssam * a special character through ttyoutput. 12469578Ssam */ 12479578Ssam if (ce == 0) { 12487502Sroot tp->t_rocount = 0; 12497502Sroot if (ttyoutput(*cp, tp) >= 0) { 12509578Ssam /* no c-lists, wait a bit */ 12517502Sroot ttstart(tp); 12527502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12537502Sroot continue; 12547502Sroot } 12559578Ssam cp++, cc--; 12569578Ssam if (tp->t_flags&FLUSHO || 12579578Ssam tp->t_outq.c_cc > hiwat) 12587502Sroot goto ovhiwat; 12599578Ssam continue; 12607502Sroot } 12617502Sroot } 12629578Ssam /* 12639578Ssam * A bunch of normal characters have been found, 12649578Ssam * transfer them en masse to the output queue and 12659578Ssam * continue processing at the top of the loop. 12669578Ssam * If there are any further characters in this 12679578Ssam * <= OBUFSIZ chunk, the first should be a character 12689578Ssam * requiring special handling by ttyoutput. 12699578Ssam */ 12707502Sroot tp->t_rocount = 0; 12719578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12729578Ssam ce -= i; 12739578Ssam tp->t_col += ce; 12749578Ssam cp += ce, cc -= ce, tk_nout += ce; 12759578Ssam if (i > 0) { 12769578Ssam /* out of c-lists, wait a bit */ 12777502Sroot ttstart(tp); 12787502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12797502Sroot } 12809578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12817502Sroot goto ovhiwat; 12827502Sroot } 12837502Sroot } 12847502Sroot ttstart(tp); 12858520Sroot return (error); 12867502Sroot 12877502Sroot ovhiwat: 12889578Ssam s = spl5(); 12899578Ssam if (cc != 0) { 12909578Ssam uio->uio_iov->iov_base -= cc; 12919578Ssam uio->uio_iov->iov_len += cc; 12929578Ssam uio->uio_resid += cc; 12939578Ssam uio->uio_offset -= cc; 12949578Ssam } 12959578Ssam /* 12969578Ssam * This can only occur if FLUSHO 12979578Ssam * is also set in t_flags. 12989578Ssam */ 12997502Sroot if (tp->t_outq.c_cc <= hiwat) { 13009578Ssam splx(s); 13017502Sroot goto loop; 13027502Sroot } 13037502Sroot ttstart(tp); 13049578Ssam if (tp->t_state&TS_NBIO) { 13057822Sroot if (uio->uio_resid == cnt) 13068520Sroot return (EWOULDBLOCK); 13078520Sroot return (0); 13087502Sroot } 13097502Sroot tp->t_state |= TS_ASLEEP; 13107502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13119578Ssam splx(s); 13127502Sroot goto loop; 13137502Sroot } 13147502Sroot 13157502Sroot /* 13167502Sroot * Rubout one character from the rawq of tp 13177502Sroot * as cleanly as possible. 13187502Sroot */ 13197502Sroot ttyrub(c, tp) 13207625Ssam register c; 13217625Ssam register struct tty *tp; 13227502Sroot { 13237502Sroot register char *cp; 13247502Sroot register int savecol; 13257502Sroot int s; 13267502Sroot char *nextc(); 13277502Sroot 13289578Ssam if ((tp->t_flags&ECHO) == 0) 13297502Sroot return; 13309578Ssam tp->t_flags &= ~FLUSHO; 13317502Sroot c &= 0377; 13329578Ssam if (tp->t_flags&CRTBS) { 13337502Sroot if (tp->t_rocount == 0) { 13347502Sroot /* 13357502Sroot * Screwed by ttwrite; retype 13367502Sroot */ 13377502Sroot ttyretype(tp); 13387502Sroot return; 13397502Sroot } 13409578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13417502Sroot ttyrubo(tp, 2); 13429578Ssam else switch (partab[c&=0177]&0177) { 13437502Sroot 13447502Sroot case ORDINARY: 13457502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13467502Sroot ttyrubo(tp, 2); 13477502Sroot else 13487502Sroot ttyrubo(tp, 1); 13497502Sroot break; 13507502Sroot 13517502Sroot case VTAB: 13527502Sroot case BACKSPACE: 13537502Sroot case CONTROL: 13547502Sroot case RETURN: 13559578Ssam if (tp->t_flags&CTLECH) 13567502Sroot ttyrubo(tp, 2); 13577502Sroot break; 13587502Sroot 13597502Sroot case TAB: 13607502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13617502Sroot ttyretype(tp); 13627502Sroot return; 13637502Sroot } 13647502Sroot s = spl5(); 13657502Sroot savecol = tp->t_col; 13669578Ssam tp->t_state |= TS_CNTTB; 13679578Ssam tp->t_flags |= FLUSHO; 13687502Sroot tp->t_col = tp->t_rocol; 13699578Ssam cp = tp->t_rawq.c_cf; 13709578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13717502Sroot ttyecho(*cp, tp); 13729578Ssam tp->t_flags &= ~FLUSHO; 13739578Ssam tp->t_state &= ~TS_CNTTB; 13747502Sroot splx(s); 13757502Sroot /* 13767502Sroot * savecol will now be length of the tab 13777502Sroot */ 13787502Sroot savecol -= tp->t_col; 13797502Sroot tp->t_col += savecol; 13807502Sroot if (savecol > 8) 13817502Sroot savecol = 8; /* overflow screw */ 13827502Sroot while (--savecol >= 0) 13837502Sroot (void) ttyoutput('\b', tp); 13847502Sroot break; 13857502Sroot 13867502Sroot default: 13877502Sroot panic("ttyrub"); 13887502Sroot } 13899578Ssam } else if (tp->t_flags&PRTERA) { 13909578Ssam if ((tp->t_state&TS_ERASE) == 0) { 13917502Sroot (void) ttyoutput('\\', tp); 13929578Ssam tp->t_state |= TS_ERASE; 13937502Sroot } 13947502Sroot ttyecho(c, tp); 13957502Sroot } else 13967502Sroot ttyecho(tp->t_erase, tp); 13977502Sroot tp->t_rocount--; 13987502Sroot } 13997502Sroot 14007502Sroot /* 14017502Sroot * Crt back over cnt chars perhaps 14027502Sroot * erasing them. 14037502Sroot */ 14047502Sroot ttyrubo(tp, cnt) 14057625Ssam register struct tty *tp; 14067625Ssam int cnt; 14077502Sroot { 14089578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14097502Sroot 14107502Sroot while (--cnt >= 0) 14119578Ssam ttyout(rubostring, tp); 14127502Sroot } 14137502Sroot 14147502Sroot /* 14157502Sroot * Reprint the rawq line. 14167502Sroot * We assume c_cc has already been checked. 14177502Sroot */ 14187502Sroot ttyretype(tp) 14197625Ssam register struct tty *tp; 14207502Sroot { 14217502Sroot register char *cp; 14227502Sroot char *nextc(); 14237502Sroot int s; 14247502Sroot 14259578Ssam if (tp->t_rprntc != 0377) 14269578Ssam ttyecho(tp->t_rprntc, tp); 14277502Sroot (void) ttyoutput('\n', tp); 14287502Sroot s = spl5(); 14297502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14307502Sroot ttyecho(*cp, tp); 14317502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14327502Sroot ttyecho(*cp, tp); 14339578Ssam tp->t_state &= ~TS_ERASE; 14347502Sroot splx(s); 14357502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14367502Sroot tp->t_rocol = 0; 14377502Sroot } 14387502Sroot 14397502Sroot /* 14407502Sroot * Echo a typed character to the terminal 14417502Sroot */ 14427502Sroot ttyecho(c, tp) 14437625Ssam register c; 14447625Ssam register struct tty *tp; 14457502Sroot { 14467502Sroot 14479578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14489578Ssam tp->t_flags &= ~FLUSHO; 14497502Sroot if ((tp->t_flags&ECHO) == 0) 14507502Sroot return; 14517502Sroot c &= 0377; 14527502Sroot if (tp->t_flags&RAW) { 14537502Sroot (void) ttyoutput(c, tp); 14547502Sroot return; 14557502Sroot } 14567502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14577502Sroot c = '\n'; 14589578Ssam if (tp->t_flags&CTLECH) { 14597502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14607502Sroot (void) ttyoutput('^', tp); 14617502Sroot c &= 0177; 14627502Sroot if (c == 0177) 14637502Sroot c = '?'; 14647502Sroot else if (tp->t_flags&LCASE) 14657502Sroot c += 'a' - 1; 14667502Sroot else 14677502Sroot c += 'A' - 1; 14687502Sroot } 14697502Sroot } 14707502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14717502Sroot c += 'a' - 'A'; 14729578Ssam (void) ttyoutput(c&0177, tp); 14737502Sroot } 14747502Sroot 14757502Sroot /* 14767502Sroot * Is c a break char for tp? 14777502Sroot */ 14787502Sroot ttbreakc(c, tp) 14797625Ssam register c; 14807625Ssam register struct tty *tp; 14817502Sroot { 14829578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14837502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14847502Sroot } 14857502Sroot 14867502Sroot /* 14877502Sroot * send string cp to tp 14887502Sroot */ 14897502Sroot ttyout(cp, tp) 14907625Ssam register char *cp; 14917625Ssam register struct tty *tp; 14927502Sroot { 14937502Sroot register char c; 14947502Sroot 14957502Sroot while (c = *cp++) 14967502Sroot (void) ttyoutput(c, tp); 14977502Sroot } 14987502Sroot 14997502Sroot ttwakeup(tp) 15007502Sroot struct tty *tp; 15017502Sroot { 15027502Sroot 15037502Sroot if (tp->t_rsel) { 15047502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15057502Sroot tp->t_state &= ~TS_RCOLL; 15067502Sroot tp->t_rsel = 0; 15077502Sroot } 150812752Ssam if (tp->t_state & TS_ASYNC) 150912752Ssam gsignal(tp->t_pgrp, SIGIO); 15107502Sroot wakeup((caddr_t)&tp->t_rawq); 15117502Sroot } 15127502Sroot 151313533Ssam #if !defined(vax) 15149578Ssam scanc(size, cp, table, mask) 15159578Ssam register int size; 15169578Ssam register char *cp, table[]; 15179578Ssam register int mask; 15187502Sroot { 15199578Ssam register int i = 0; 15207502Sroot 15219578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15229578Ssam i++; 15239578Ssam return (i); 15247502Sroot } 15259578Ssam #endif 1526