1*13863Ssam /* tty.c 4.47 83/07/09 */ 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 12813809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 12913809Ssam 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 94213821Ssam /* 94313821Ssam * This macro is close enough to the correct thing; 94413821Ssam * it should be replaced by real user settable delays 94513821Ssam * in any event... 94613821Ssam */ 94713821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9487502Sroot case NEWLINE: 9497502Sroot ctype = (tp->t_flags >> 8) & 03; 9507625Ssam if (ctype == 1) { /* tty 37 */ 95112752Ssam if (*colp > 0) 952*13863Ssam c = max((((unsigned)*colp) >> 4) + 3, 953*13863Ssam (unsigned)6); 9549578Ssam } else if (ctype == 2) /* vt05 */ 95513821Ssam c = mstohz(100); 9567502Sroot *colp = 0; 9577502Sroot break; 9587502Sroot 9597502Sroot case TAB: 9607502Sroot ctype = (tp->t_flags >> 10) & 03; 9617625Ssam if (ctype == 1) { /* tty 37 */ 9627502Sroot c = 1 - (*colp | ~07); 9637625Ssam if (c < 5) 9647502Sroot c = 0; 9657502Sroot } 9667502Sroot *colp |= 07; 9677502Sroot (*colp)++; 9687502Sroot break; 9697502Sroot 9707502Sroot case VTAB: 9719578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9727502Sroot c = 0177; 9737502Sroot break; 9747502Sroot 9757502Sroot case RETURN: 9767502Sroot ctype = (tp->t_flags >> 12) & 03; 9779578Ssam if (ctype == 1) /* tn 300 */ 97813821Ssam c = mstohz(83); 9799578Ssam else if (ctype == 2) /* ti 700 */ 98013821Ssam c = mstohz(166); 9819578Ssam else if (ctype == 3) { /* concept 100 */ 9827502Sroot int i; 9839578Ssam 9847502Sroot if ((i = *colp) >= 0) 9859578Ssam for (; i < 9; i++) 9867502Sroot (void) putc(0177, &tp->t_outq); 9877502Sroot } 9887502Sroot *colp = 0; 9897502Sroot } 9909578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9917502Sroot (void) putc(c|0200, &tp->t_outq); 9927502Sroot return (-1); 9937502Sroot } 99413821Ssam #undef mstohz 9957502Sroot 9967502Sroot /* 9977502Sroot * Called from device's read routine after it has 9987502Sroot * calculated the tty-structure given as argument. 9997502Sroot */ 10007722Swnj ttread(tp, uio) 10017625Ssam register struct tty *tp; 10027722Swnj struct uio *uio; 10037502Sroot { 10047502Sroot register struct clist *qp; 10059578Ssam register c, t_flags; 10069859Ssam int s, first, error = 0; 10077502Sroot 10087502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10098520Sroot return (EIO); 10107502Sroot loop: 10119578Ssam /* 10129578Ssam * Take any pending input first. 10139578Ssam */ 10149859Ssam s = spl5(); 10159578Ssam if (tp->t_flags&PENDIN) 10167502Sroot ttypend(tp); 10179859Ssam splx(s); 10189578Ssam 10199578Ssam /* 10209578Ssam * Hang process if it's in the background. 10219578Ssam */ 10227502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 10237502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 10247502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 10257502Sroot /* 10267502Sroot (u.u_procp->p_flag&SDETACH) || 10277502Sroot */ 10287502Sroot u.u_procp->p_flag&SVFORK) 10298520Sroot return (EIO); 10307502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10317502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10327502Sroot } 10339578Ssam t_flags = tp->t_flags; 10349578Ssam 10359578Ssam /* 10369578Ssam * In raw mode take characters directly from the 10379578Ssam * raw queue w/o processing. Interlock against 10389578Ssam * device interrupts when interrogating rawq. 10399578Ssam */ 10409578Ssam if (t_flags&RAW) { 10419859Ssam s = spl5(); 10427502Sroot if (tp->t_rawq.c_cc <= 0) { 10439578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10447502Sroot (tp->t_state&TS_NBIO)) { 10459859Ssam splx(s); 10469578Ssam return (0); 10477502Sroot } 10487502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10499859Ssam splx(s); 10507502Sroot goto loop; 10517502Sroot } 10529859Ssam splx(s); 10539859Ssam while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt) 10548520Sroot error = passuc(getc(&tp->t_rawq), uio); 10559859Ssam goto checktandem; 10569578Ssam } 10579578Ssam 10589578Ssam /* 10599578Ssam * In cbreak mode use the rawq, otherwise 10609578Ssam * take characters from the canonicalized q. 10619578Ssam */ 10629578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10639578Ssam 10649578Ssam /* 10659578Ssam * No input, sleep on rawq awaiting hardware 10669578Ssam * receipt and notification. 10679578Ssam */ 10689859Ssam s = spl5(); 10699578Ssam if (qp->c_cc <= 0) { 10709578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10719578Ssam (tp->t_state&TS_NBIO)) { 10729859Ssam splx(s); 10739578Ssam return (EWOULDBLOCK); 10747502Sroot } 10759578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10769859Ssam splx(s); 10779578Ssam goto loop; 10789578Ssam } 10799859Ssam splx(s); 10809578Ssam 10819578Ssam /* 10829578Ssam * Input present, perform input mapping 10839578Ssam * and processing (we're not in raw mode). 10849578Ssam */ 10859578Ssam first = 1; 10869578Ssam while ((c = getc(qp)) >= 0) { 10879578Ssam if (t_flags&CRMOD && c == '\r') 10889578Ssam c = '\n'; 10899578Ssam /* 10909578Ssam * Hack lower case simulation on 10919578Ssam * upper case only terminals. 10929578Ssam */ 10939578Ssam if (t_flags&LCASE && c <= 0177) 10949578Ssam if (tp->t_state&TS_BKSL) { 10959578Ssam if (maptab[c]) 10969578Ssam c = maptab[c]; 10979578Ssam tp->t_state &= ~TS_BKSL; 10989578Ssam } else if (c >= 'A' && c <= 'Z') 10999578Ssam c += 'a' - 'A'; 11009578Ssam else if (c == '\\') { 11019578Ssam tp->t_state |= TS_BKSL; 11029578Ssam continue; 11037502Sroot } 11049578Ssam /* 11059578Ssam * Check for delayed suspend character. 11069578Ssam */ 11079578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11089578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11099578Ssam if (first) { 11109578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11119578Ssam goto loop; 11129578Ssam } 11139578Ssam break; 11147502Sroot } 11159578Ssam /* 11169578Ssam * Interpret EOF only in cooked mode. 11179578Ssam */ 11189578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11199578Ssam break; 11209578Ssam /* 11219578Ssam * Give user character. 11229578Ssam */ 11239578Ssam error = passuc(c & 0177, uio); 11249578Ssam if (error) 11259578Ssam break; 11269578Ssam if (uio->uio_iovcnt == 0) 11279578Ssam break; 11289578Ssam /* 11299578Ssam * In cooked mode check for a "break character" 11309578Ssam * marking the end of a "line of input". 11319578Ssam */ 11329578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11339578Ssam break; 11349578Ssam first = 0; 11357502Sroot } 11369578Ssam tp->t_state &= ~TS_BKSL; 11379578Ssam 11389859Ssam checktandem: 11399578Ssam /* 11409578Ssam * Look to unblock output now that (presumably) 11419578Ssam * the input queue has gone down. 11429578Ssam */ 11439859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11449578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11457502Sroot tp->t_state &= ~TS_TBLOCK; 11467502Sroot ttstart(tp); 11477502Sroot } 11488520Sroot return (error); 11497502Sroot } 11507502Sroot 11517502Sroot /* 11527502Sroot * Called from the device's write routine after it has 11537502Sroot * calculated the tty-structure given as argument. 11547502Sroot */ 11557822Sroot ttwrite(tp, uio) 11567625Ssam register struct tty *tp; 11579578Ssam register struct uio *uio; 11587502Sroot { 11597502Sroot register char *cp; 11609578Ssam register int cc, ce, c; 11619578Ssam int i, hiwat, cnt, error, s; 11627502Sroot char obuf[OBUFSIZ]; 11637502Sroot 11649578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11658520Sroot return (EIO); 11669578Ssam hiwat = TTHIWAT(tp); 11679578Ssam cnt = uio->uio_resid; 11689578Ssam error = 0; 11697502Sroot loop: 11709578Ssam /* 11719578Ssam * Hang the process if it's in the background. 11729578Ssam */ 11737502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11749578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11757502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11767502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11777502Sroot /* 11787502Sroot && 11797502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11807502Sroot */ 11817502Sroot ) { 11827502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11837502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11847502Sroot } 11859578Ssam 11869578Ssam /* 11879578Ssam * Process the user's data in at most OBUFSIZ 11889578Ssam * chunks. Perform lower case simulation and 11899578Ssam * similar hacks. Keep track of high water 11909578Ssam * mark, sleep on overflow awaiting device aid 11919578Ssam * in acquiring new space. 11929578Ssam */ 11937822Sroot while (uio->uio_resid > 0) { 11949578Ssam /* 11959578Ssam * Grab a hunk of data from the user. 11969578Ssam */ 11977822Sroot cc = uio->uio_iov->iov_len; 11987822Sroot if (cc == 0) { 11997822Sroot uio->uio_iovcnt--; 12007822Sroot uio->uio_iov++; 12017822Sroot if (uio->uio_iovcnt < 0) 12027822Sroot panic("ttwrite"); 12037822Sroot continue; 12047822Sroot } 12057822Sroot if (cc > OBUFSIZ) 12067822Sroot cc = OBUFSIZ; 12077502Sroot cp = obuf; 120812752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12098520Sroot if (error) 12107502Sroot break; 12117502Sroot if (tp->t_outq.c_cc > hiwat) 12127502Sroot goto ovhiwat; 12139578Ssam if (tp->t_flags&FLUSHO) 12147502Sroot continue; 12159578Ssam /* 12169578Ssam * If we're mapping lower case or kludging tildes, 12179578Ssam * then we've got to look at each character, so 12189578Ssam * just feed the stuff to ttyoutput... 12199578Ssam */ 12209578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12219578Ssam while (cc > 0) { 12227502Sroot c = *cp++; 12237502Sroot tp->t_rocount = 0; 12247625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12257502Sroot /* out of clists, wait a bit */ 12267502Sroot ttstart(tp); 12277502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12287502Sroot tp->t_rocount = 0; 12297502Sroot } 12307502Sroot --cc; 12317502Sroot if (tp->t_outq.c_cc > hiwat) 12327502Sroot goto ovhiwat; 12337502Sroot } 12347502Sroot continue; 12357502Sroot } 12369578Ssam /* 12379578Ssam * If nothing fancy need be done, grab those characters we 12389578Ssam * can handle without any of ttyoutput's processing and 12399578Ssam * just transfer them to the output q. For those chars 12409578Ssam * which require special processing (as indicated by the 12419578Ssam * bits in partab), call ttyoutput. After processing 12429578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12439578Ssam * immediately. 12449578Ssam */ 12459578Ssam while (cc > 0) { 12469578Ssam if (tp->t_flags & (RAW|LITOUT)) 12477502Sroot ce = cc; 12487502Sroot else { 124912752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 125012752Ssam (caddr_t)partab, 077); 12519578Ssam /* 12529578Ssam * If ce is zero, then we're processing 12539578Ssam * a special character through ttyoutput. 12549578Ssam */ 12559578Ssam if (ce == 0) { 12567502Sroot tp->t_rocount = 0; 12577502Sroot if (ttyoutput(*cp, tp) >= 0) { 12589578Ssam /* no c-lists, wait a bit */ 12597502Sroot ttstart(tp); 12607502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12617502Sroot continue; 12627502Sroot } 12639578Ssam cp++, cc--; 12649578Ssam if (tp->t_flags&FLUSHO || 12659578Ssam tp->t_outq.c_cc > hiwat) 12667502Sroot goto ovhiwat; 12679578Ssam continue; 12687502Sroot } 12697502Sroot } 12709578Ssam /* 12719578Ssam * A bunch of normal characters have been found, 12729578Ssam * transfer them en masse to the output queue and 12739578Ssam * continue processing at the top of the loop. 12749578Ssam * If there are any further characters in this 12759578Ssam * <= OBUFSIZ chunk, the first should be a character 12769578Ssam * requiring special handling by ttyoutput. 12779578Ssam */ 12787502Sroot tp->t_rocount = 0; 12799578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12809578Ssam ce -= i; 12819578Ssam tp->t_col += ce; 12829578Ssam cp += ce, cc -= ce, tk_nout += ce; 12839578Ssam if (i > 0) { 12849578Ssam /* out of c-lists, wait a bit */ 12857502Sroot ttstart(tp); 12867502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12877502Sroot } 12889578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12897502Sroot goto ovhiwat; 12907502Sroot } 12917502Sroot } 12927502Sroot ttstart(tp); 12938520Sroot return (error); 12947502Sroot 12957502Sroot ovhiwat: 12969578Ssam s = spl5(); 12979578Ssam if (cc != 0) { 12989578Ssam uio->uio_iov->iov_base -= cc; 12999578Ssam uio->uio_iov->iov_len += cc; 13009578Ssam uio->uio_resid += cc; 13019578Ssam uio->uio_offset -= cc; 13029578Ssam } 13039578Ssam /* 13049578Ssam * This can only occur if FLUSHO 13059578Ssam * is also set in t_flags. 13069578Ssam */ 13077502Sroot if (tp->t_outq.c_cc <= hiwat) { 13089578Ssam splx(s); 13097502Sroot goto loop; 13107502Sroot } 13117502Sroot ttstart(tp); 13129578Ssam if (tp->t_state&TS_NBIO) { 13137822Sroot if (uio->uio_resid == cnt) 13148520Sroot return (EWOULDBLOCK); 13158520Sroot return (0); 13167502Sroot } 13177502Sroot tp->t_state |= TS_ASLEEP; 13187502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13199578Ssam splx(s); 13207502Sroot goto loop; 13217502Sroot } 13227502Sroot 13237502Sroot /* 13247502Sroot * Rubout one character from the rawq of tp 13257502Sroot * as cleanly as possible. 13267502Sroot */ 13277502Sroot ttyrub(c, tp) 13287625Ssam register c; 13297625Ssam register struct tty *tp; 13307502Sroot { 13317502Sroot register char *cp; 13327502Sroot register int savecol; 13337502Sroot int s; 13347502Sroot char *nextc(); 13357502Sroot 13369578Ssam if ((tp->t_flags&ECHO) == 0) 13377502Sroot return; 13389578Ssam tp->t_flags &= ~FLUSHO; 13397502Sroot c &= 0377; 13409578Ssam if (tp->t_flags&CRTBS) { 13417502Sroot if (tp->t_rocount == 0) { 13427502Sroot /* 13437502Sroot * Screwed by ttwrite; retype 13447502Sroot */ 13457502Sroot ttyretype(tp); 13467502Sroot return; 13477502Sroot } 13489578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13497502Sroot ttyrubo(tp, 2); 13509578Ssam else switch (partab[c&=0177]&0177) { 13517502Sroot 13527502Sroot case ORDINARY: 13537502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13547502Sroot ttyrubo(tp, 2); 13557502Sroot else 13567502Sroot ttyrubo(tp, 1); 13577502Sroot break; 13587502Sroot 13597502Sroot case VTAB: 13607502Sroot case BACKSPACE: 13617502Sroot case CONTROL: 13627502Sroot case RETURN: 13639578Ssam if (tp->t_flags&CTLECH) 13647502Sroot ttyrubo(tp, 2); 13657502Sroot break; 13667502Sroot 13677502Sroot case TAB: 13687502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13697502Sroot ttyretype(tp); 13707502Sroot return; 13717502Sroot } 13727502Sroot s = spl5(); 13737502Sroot savecol = tp->t_col; 13749578Ssam tp->t_state |= TS_CNTTB; 13759578Ssam tp->t_flags |= FLUSHO; 13767502Sroot tp->t_col = tp->t_rocol; 13779578Ssam cp = tp->t_rawq.c_cf; 13789578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13797502Sroot ttyecho(*cp, tp); 13809578Ssam tp->t_flags &= ~FLUSHO; 13819578Ssam tp->t_state &= ~TS_CNTTB; 13827502Sroot splx(s); 13837502Sroot /* 13847502Sroot * savecol will now be length of the tab 13857502Sroot */ 13867502Sroot savecol -= tp->t_col; 13877502Sroot tp->t_col += savecol; 13887502Sroot if (savecol > 8) 13897502Sroot savecol = 8; /* overflow screw */ 13907502Sroot while (--savecol >= 0) 13917502Sroot (void) ttyoutput('\b', tp); 13927502Sroot break; 13937502Sroot 13947502Sroot default: 13957502Sroot panic("ttyrub"); 13967502Sroot } 13979578Ssam } else if (tp->t_flags&PRTERA) { 13989578Ssam if ((tp->t_state&TS_ERASE) == 0) { 13997502Sroot (void) ttyoutput('\\', tp); 14009578Ssam tp->t_state |= TS_ERASE; 14017502Sroot } 14027502Sroot ttyecho(c, tp); 14037502Sroot } else 14047502Sroot ttyecho(tp->t_erase, tp); 14057502Sroot tp->t_rocount--; 14067502Sroot } 14077502Sroot 14087502Sroot /* 14097502Sroot * Crt back over cnt chars perhaps 14107502Sroot * erasing them. 14117502Sroot */ 14127502Sroot ttyrubo(tp, cnt) 14137625Ssam register struct tty *tp; 14147625Ssam int cnt; 14157502Sroot { 14169578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14177502Sroot 14187502Sroot while (--cnt >= 0) 14199578Ssam ttyout(rubostring, tp); 14207502Sroot } 14217502Sroot 14227502Sroot /* 14237502Sroot * Reprint the rawq line. 14247502Sroot * We assume c_cc has already been checked. 14257502Sroot */ 14267502Sroot ttyretype(tp) 14277625Ssam register struct tty *tp; 14287502Sroot { 14297502Sroot register char *cp; 14307502Sroot char *nextc(); 14317502Sroot int s; 14327502Sroot 14339578Ssam if (tp->t_rprntc != 0377) 14349578Ssam ttyecho(tp->t_rprntc, tp); 14357502Sroot (void) ttyoutput('\n', tp); 14367502Sroot s = spl5(); 14377502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14387502Sroot ttyecho(*cp, tp); 14397502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14407502Sroot ttyecho(*cp, tp); 14419578Ssam tp->t_state &= ~TS_ERASE; 14427502Sroot splx(s); 14437502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14447502Sroot tp->t_rocol = 0; 14457502Sroot } 14467502Sroot 14477502Sroot /* 14487502Sroot * Echo a typed character to the terminal 14497502Sroot */ 14507502Sroot ttyecho(c, tp) 14517625Ssam register c; 14527625Ssam register struct tty *tp; 14537502Sroot { 14547502Sroot 14559578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14569578Ssam tp->t_flags &= ~FLUSHO; 14577502Sroot if ((tp->t_flags&ECHO) == 0) 14587502Sroot return; 14597502Sroot c &= 0377; 14607502Sroot if (tp->t_flags&RAW) { 14617502Sroot (void) ttyoutput(c, tp); 14627502Sroot return; 14637502Sroot } 14647502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14657502Sroot c = '\n'; 14669578Ssam if (tp->t_flags&CTLECH) { 14677502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14687502Sroot (void) ttyoutput('^', tp); 14697502Sroot c &= 0177; 14707502Sroot if (c == 0177) 14717502Sroot c = '?'; 14727502Sroot else if (tp->t_flags&LCASE) 14737502Sroot c += 'a' - 1; 14747502Sroot else 14757502Sroot c += 'A' - 1; 14767502Sroot } 14777502Sroot } 14787502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14797502Sroot c += 'a' - 'A'; 14809578Ssam (void) ttyoutput(c&0177, tp); 14817502Sroot } 14827502Sroot 14837502Sroot /* 14847502Sroot * Is c a break char for tp? 14857502Sroot */ 14867502Sroot ttbreakc(c, tp) 14877625Ssam register c; 14887625Ssam register struct tty *tp; 14897502Sroot { 14909578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14917502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14927502Sroot } 14937502Sroot 14947502Sroot /* 14957502Sroot * send string cp to tp 14967502Sroot */ 14977502Sroot ttyout(cp, tp) 14987625Ssam register char *cp; 14997625Ssam register struct tty *tp; 15007502Sroot { 15017502Sroot register char c; 15027502Sroot 15037502Sroot while (c = *cp++) 15047502Sroot (void) ttyoutput(c, tp); 15057502Sroot } 15067502Sroot 15077502Sroot ttwakeup(tp) 15087502Sroot struct tty *tp; 15097502Sroot { 15107502Sroot 15117502Sroot if (tp->t_rsel) { 15127502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15137502Sroot tp->t_state &= ~TS_RCOLL; 15147502Sroot tp->t_rsel = 0; 15157502Sroot } 151612752Ssam if (tp->t_state & TS_ASYNC) 151712752Ssam gsignal(tp->t_pgrp, SIGIO); 15187502Sroot wakeup((caddr_t)&tp->t_rawq); 15197502Sroot } 15207502Sroot 152113533Ssam #if !defined(vax) 15229578Ssam scanc(size, cp, table, mask) 15239578Ssam register int size; 15249578Ssam register char *cp, table[]; 15259578Ssam register int mask; 15267502Sroot { 15279578Ssam register int i = 0; 15287502Sroot 15299578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15309578Ssam i++; 15319578Ssam return (i); 15327502Sroot } 15339578Ssam #endif 1534