1*13821Ssam /* tty.c 4.46 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 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 942*13821Ssam /* 943*13821Ssam * This macro is close enough to the correct thing; 944*13821Ssam * it should be replaced by real user settable delays 945*13821Ssam * in any event... 946*13821Ssam */ 947*13821Ssam #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) 9527502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9539578Ssam } else if (ctype == 2) /* vt05 */ 954*13821Ssam c = mstohz(100); 9557502Sroot *colp = 0; 9567502Sroot break; 9577502Sroot 9587502Sroot case TAB: 9597502Sroot ctype = (tp->t_flags >> 10) & 03; 9607625Ssam if (ctype == 1) { /* tty 37 */ 9617502Sroot c = 1 - (*colp | ~07); 9627625Ssam if (c < 5) 9637502Sroot c = 0; 9647502Sroot } 9657502Sroot *colp |= 07; 9667502Sroot (*colp)++; 9677502Sroot break; 9687502Sroot 9697502Sroot case VTAB: 9709578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9717502Sroot c = 0177; 9727502Sroot break; 9737502Sroot 9747502Sroot case RETURN: 9757502Sroot ctype = (tp->t_flags >> 12) & 03; 9769578Ssam if (ctype == 1) /* tn 300 */ 977*13821Ssam c = mstohz(83); 9789578Ssam else if (ctype == 2) /* ti 700 */ 979*13821Ssam c = mstohz(166); 9809578Ssam else if (ctype == 3) { /* concept 100 */ 9817502Sroot int i; 9829578Ssam 9837502Sroot if ((i = *colp) >= 0) 9849578Ssam for (; i < 9; i++) 9857502Sroot (void) putc(0177, &tp->t_outq); 9867502Sroot } 9877502Sroot *colp = 0; 9887502Sroot } 9899578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9907502Sroot (void) putc(c|0200, &tp->t_outq); 9917502Sroot return (-1); 9927502Sroot } 993*13821Ssam #undef mstohz 9947502Sroot 9957502Sroot /* 9967502Sroot * Called from device's read routine after it has 9977502Sroot * calculated the tty-structure given as argument. 9987502Sroot */ 9997722Swnj ttread(tp, uio) 10007625Ssam register struct tty *tp; 10017722Swnj struct uio *uio; 10027502Sroot { 10037502Sroot register struct clist *qp; 10049578Ssam register c, t_flags; 10059859Ssam int s, first, error = 0; 10067502Sroot 10077502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10088520Sroot return (EIO); 10097502Sroot loop: 10109578Ssam /* 10119578Ssam * Take any pending input first. 10129578Ssam */ 10139859Ssam s = spl5(); 10149578Ssam if (tp->t_flags&PENDIN) 10157502Sroot ttypend(tp); 10169859Ssam splx(s); 10179578Ssam 10189578Ssam /* 10199578Ssam * Hang process if it's in the background. 10209578Ssam */ 10217502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 10227502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 10237502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 10247502Sroot /* 10257502Sroot (u.u_procp->p_flag&SDETACH) || 10267502Sroot */ 10277502Sroot u.u_procp->p_flag&SVFORK) 10288520Sroot return (EIO); 10297502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10307502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10317502Sroot } 10329578Ssam t_flags = tp->t_flags; 10339578Ssam 10349578Ssam /* 10359578Ssam * In raw mode take characters directly from the 10369578Ssam * raw queue w/o processing. Interlock against 10379578Ssam * device interrupts when interrogating rawq. 10389578Ssam */ 10399578Ssam if (t_flags&RAW) { 10409859Ssam s = spl5(); 10417502Sroot if (tp->t_rawq.c_cc <= 0) { 10429578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10437502Sroot (tp->t_state&TS_NBIO)) { 10449859Ssam splx(s); 10459578Ssam return (0); 10467502Sroot } 10477502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10489859Ssam splx(s); 10497502Sroot goto loop; 10507502Sroot } 10519859Ssam splx(s); 10529859Ssam while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt) 10538520Sroot error = passuc(getc(&tp->t_rawq), uio); 10549859Ssam goto checktandem; 10559578Ssam } 10569578Ssam 10579578Ssam /* 10589578Ssam * In cbreak mode use the rawq, otherwise 10599578Ssam * take characters from the canonicalized q. 10609578Ssam */ 10619578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10629578Ssam 10639578Ssam /* 10649578Ssam * No input, sleep on rawq awaiting hardware 10659578Ssam * receipt and notification. 10669578Ssam */ 10679859Ssam s = spl5(); 10689578Ssam if (qp->c_cc <= 0) { 10699578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10709578Ssam (tp->t_state&TS_NBIO)) { 10719859Ssam splx(s); 10729578Ssam return (EWOULDBLOCK); 10737502Sroot } 10749578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10759859Ssam splx(s); 10769578Ssam goto loop; 10779578Ssam } 10789859Ssam splx(s); 10799578Ssam 10809578Ssam /* 10819578Ssam * Input present, perform input mapping 10829578Ssam * and processing (we're not in raw mode). 10839578Ssam */ 10849578Ssam first = 1; 10859578Ssam while ((c = getc(qp)) >= 0) { 10869578Ssam if (t_flags&CRMOD && c == '\r') 10879578Ssam c = '\n'; 10889578Ssam /* 10899578Ssam * Hack lower case simulation on 10909578Ssam * upper case only terminals. 10919578Ssam */ 10929578Ssam if (t_flags&LCASE && c <= 0177) 10939578Ssam if (tp->t_state&TS_BKSL) { 10949578Ssam if (maptab[c]) 10959578Ssam c = maptab[c]; 10969578Ssam tp->t_state &= ~TS_BKSL; 10979578Ssam } else if (c >= 'A' && c <= 'Z') 10989578Ssam c += 'a' - 'A'; 10999578Ssam else if (c == '\\') { 11009578Ssam tp->t_state |= TS_BKSL; 11019578Ssam continue; 11027502Sroot } 11039578Ssam /* 11049578Ssam * Check for delayed suspend character. 11059578Ssam */ 11069578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11079578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11089578Ssam if (first) { 11099578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11109578Ssam goto loop; 11119578Ssam } 11129578Ssam break; 11137502Sroot } 11149578Ssam /* 11159578Ssam * Interpret EOF only in cooked mode. 11169578Ssam */ 11179578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11189578Ssam break; 11199578Ssam /* 11209578Ssam * Give user character. 11219578Ssam */ 11229578Ssam error = passuc(c & 0177, uio); 11239578Ssam if (error) 11249578Ssam break; 11259578Ssam if (uio->uio_iovcnt == 0) 11269578Ssam break; 11279578Ssam /* 11289578Ssam * In cooked mode check for a "break character" 11299578Ssam * marking the end of a "line of input". 11309578Ssam */ 11319578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11329578Ssam break; 11339578Ssam first = 0; 11347502Sroot } 11359578Ssam tp->t_state &= ~TS_BKSL; 11369578Ssam 11379859Ssam checktandem: 11389578Ssam /* 11399578Ssam * Look to unblock output now that (presumably) 11409578Ssam * the input queue has gone down. 11419578Ssam */ 11429859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11439578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11447502Sroot tp->t_state &= ~TS_TBLOCK; 11457502Sroot ttstart(tp); 11467502Sroot } 11478520Sroot return (error); 11487502Sroot } 11497502Sroot 11507502Sroot /* 11517502Sroot * Called from the device's write routine after it has 11527502Sroot * calculated the tty-structure given as argument. 11537502Sroot */ 11547822Sroot ttwrite(tp, uio) 11557625Ssam register struct tty *tp; 11569578Ssam register struct uio *uio; 11577502Sroot { 11587502Sroot register char *cp; 11599578Ssam register int cc, ce, c; 11609578Ssam int i, hiwat, cnt, error, s; 11617502Sroot char obuf[OBUFSIZ]; 11627502Sroot 11639578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11648520Sroot return (EIO); 11659578Ssam hiwat = TTHIWAT(tp); 11669578Ssam cnt = uio->uio_resid; 11679578Ssam error = 0; 11687502Sroot loop: 11699578Ssam /* 11709578Ssam * Hang the process if it's in the background. 11719578Ssam */ 11727502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11739578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11747502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11757502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11767502Sroot /* 11777502Sroot && 11787502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11797502Sroot */ 11807502Sroot ) { 11817502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11827502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11837502Sroot } 11849578Ssam 11859578Ssam /* 11869578Ssam * Process the user's data in at most OBUFSIZ 11879578Ssam * chunks. Perform lower case simulation and 11889578Ssam * similar hacks. Keep track of high water 11899578Ssam * mark, sleep on overflow awaiting device aid 11909578Ssam * in acquiring new space. 11919578Ssam */ 11927822Sroot while (uio->uio_resid > 0) { 11939578Ssam /* 11949578Ssam * Grab a hunk of data from the user. 11959578Ssam */ 11967822Sroot cc = uio->uio_iov->iov_len; 11977822Sroot if (cc == 0) { 11987822Sroot uio->uio_iovcnt--; 11997822Sroot uio->uio_iov++; 12007822Sroot if (uio->uio_iovcnt < 0) 12017822Sroot panic("ttwrite"); 12027822Sroot continue; 12037822Sroot } 12047822Sroot if (cc > OBUFSIZ) 12057822Sroot cc = OBUFSIZ; 12067502Sroot cp = obuf; 120712752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12088520Sroot if (error) 12097502Sroot break; 12107502Sroot if (tp->t_outq.c_cc > hiwat) 12117502Sroot goto ovhiwat; 12129578Ssam if (tp->t_flags&FLUSHO) 12137502Sroot continue; 12149578Ssam /* 12159578Ssam * If we're mapping lower case or kludging tildes, 12169578Ssam * then we've got to look at each character, so 12179578Ssam * just feed the stuff to ttyoutput... 12189578Ssam */ 12199578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12209578Ssam while (cc > 0) { 12217502Sroot c = *cp++; 12227502Sroot tp->t_rocount = 0; 12237625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12247502Sroot /* out of clists, wait a bit */ 12257502Sroot ttstart(tp); 12267502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12277502Sroot tp->t_rocount = 0; 12287502Sroot } 12297502Sroot --cc; 12307502Sroot if (tp->t_outq.c_cc > hiwat) 12317502Sroot goto ovhiwat; 12327502Sroot } 12337502Sroot continue; 12347502Sroot } 12359578Ssam /* 12369578Ssam * If nothing fancy need be done, grab those characters we 12379578Ssam * can handle without any of ttyoutput's processing and 12389578Ssam * just transfer them to the output q. For those chars 12399578Ssam * which require special processing (as indicated by the 12409578Ssam * bits in partab), call ttyoutput. After processing 12419578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12429578Ssam * immediately. 12439578Ssam */ 12449578Ssam while (cc > 0) { 12459578Ssam if (tp->t_flags & (RAW|LITOUT)) 12467502Sroot ce = cc; 12477502Sroot else { 124812752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 124912752Ssam (caddr_t)partab, 077); 12509578Ssam /* 12519578Ssam * If ce is zero, then we're processing 12529578Ssam * a special character through ttyoutput. 12539578Ssam */ 12549578Ssam if (ce == 0) { 12557502Sroot tp->t_rocount = 0; 12567502Sroot if (ttyoutput(*cp, tp) >= 0) { 12579578Ssam /* no c-lists, wait a bit */ 12587502Sroot ttstart(tp); 12597502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12607502Sroot continue; 12617502Sroot } 12629578Ssam cp++, cc--; 12639578Ssam if (tp->t_flags&FLUSHO || 12649578Ssam tp->t_outq.c_cc > hiwat) 12657502Sroot goto ovhiwat; 12669578Ssam continue; 12677502Sroot } 12687502Sroot } 12699578Ssam /* 12709578Ssam * A bunch of normal characters have been found, 12719578Ssam * transfer them en masse to the output queue and 12729578Ssam * continue processing at the top of the loop. 12739578Ssam * If there are any further characters in this 12749578Ssam * <= OBUFSIZ chunk, the first should be a character 12759578Ssam * requiring special handling by ttyoutput. 12769578Ssam */ 12777502Sroot tp->t_rocount = 0; 12789578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12799578Ssam ce -= i; 12809578Ssam tp->t_col += ce; 12819578Ssam cp += ce, cc -= ce, tk_nout += ce; 12829578Ssam if (i > 0) { 12839578Ssam /* out of c-lists, wait a bit */ 12847502Sroot ttstart(tp); 12857502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12867502Sroot } 12879578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12887502Sroot goto ovhiwat; 12897502Sroot } 12907502Sroot } 12917502Sroot ttstart(tp); 12928520Sroot return (error); 12937502Sroot 12947502Sroot ovhiwat: 12959578Ssam s = spl5(); 12969578Ssam if (cc != 0) { 12979578Ssam uio->uio_iov->iov_base -= cc; 12989578Ssam uio->uio_iov->iov_len += cc; 12999578Ssam uio->uio_resid += cc; 13009578Ssam uio->uio_offset -= cc; 13019578Ssam } 13029578Ssam /* 13039578Ssam * This can only occur if FLUSHO 13049578Ssam * is also set in t_flags. 13059578Ssam */ 13067502Sroot if (tp->t_outq.c_cc <= hiwat) { 13079578Ssam splx(s); 13087502Sroot goto loop; 13097502Sroot } 13107502Sroot ttstart(tp); 13119578Ssam if (tp->t_state&TS_NBIO) { 13127822Sroot if (uio->uio_resid == cnt) 13138520Sroot return (EWOULDBLOCK); 13148520Sroot return (0); 13157502Sroot } 13167502Sroot tp->t_state |= TS_ASLEEP; 13177502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13189578Ssam splx(s); 13197502Sroot goto loop; 13207502Sroot } 13217502Sroot 13227502Sroot /* 13237502Sroot * Rubout one character from the rawq of tp 13247502Sroot * as cleanly as possible. 13257502Sroot */ 13267502Sroot ttyrub(c, tp) 13277625Ssam register c; 13287625Ssam register struct tty *tp; 13297502Sroot { 13307502Sroot register char *cp; 13317502Sroot register int savecol; 13327502Sroot int s; 13337502Sroot char *nextc(); 13347502Sroot 13359578Ssam if ((tp->t_flags&ECHO) == 0) 13367502Sroot return; 13379578Ssam tp->t_flags &= ~FLUSHO; 13387502Sroot c &= 0377; 13399578Ssam if (tp->t_flags&CRTBS) { 13407502Sroot if (tp->t_rocount == 0) { 13417502Sroot /* 13427502Sroot * Screwed by ttwrite; retype 13437502Sroot */ 13447502Sroot ttyretype(tp); 13457502Sroot return; 13467502Sroot } 13479578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13487502Sroot ttyrubo(tp, 2); 13499578Ssam else switch (partab[c&=0177]&0177) { 13507502Sroot 13517502Sroot case ORDINARY: 13527502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13537502Sroot ttyrubo(tp, 2); 13547502Sroot else 13557502Sroot ttyrubo(tp, 1); 13567502Sroot break; 13577502Sroot 13587502Sroot case VTAB: 13597502Sroot case BACKSPACE: 13607502Sroot case CONTROL: 13617502Sroot case RETURN: 13629578Ssam if (tp->t_flags&CTLECH) 13637502Sroot ttyrubo(tp, 2); 13647502Sroot break; 13657502Sroot 13667502Sroot case TAB: 13677502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13687502Sroot ttyretype(tp); 13697502Sroot return; 13707502Sroot } 13717502Sroot s = spl5(); 13727502Sroot savecol = tp->t_col; 13739578Ssam tp->t_state |= TS_CNTTB; 13749578Ssam tp->t_flags |= FLUSHO; 13757502Sroot tp->t_col = tp->t_rocol; 13769578Ssam cp = tp->t_rawq.c_cf; 13779578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13787502Sroot ttyecho(*cp, tp); 13799578Ssam tp->t_flags &= ~FLUSHO; 13809578Ssam tp->t_state &= ~TS_CNTTB; 13817502Sroot splx(s); 13827502Sroot /* 13837502Sroot * savecol will now be length of the tab 13847502Sroot */ 13857502Sroot savecol -= tp->t_col; 13867502Sroot tp->t_col += savecol; 13877502Sroot if (savecol > 8) 13887502Sroot savecol = 8; /* overflow screw */ 13897502Sroot while (--savecol >= 0) 13907502Sroot (void) ttyoutput('\b', tp); 13917502Sroot break; 13927502Sroot 13937502Sroot default: 13947502Sroot panic("ttyrub"); 13957502Sroot } 13969578Ssam } else if (tp->t_flags&PRTERA) { 13979578Ssam if ((tp->t_state&TS_ERASE) == 0) { 13987502Sroot (void) ttyoutput('\\', tp); 13999578Ssam tp->t_state |= TS_ERASE; 14007502Sroot } 14017502Sroot ttyecho(c, tp); 14027502Sroot } else 14037502Sroot ttyecho(tp->t_erase, tp); 14047502Sroot tp->t_rocount--; 14057502Sroot } 14067502Sroot 14077502Sroot /* 14087502Sroot * Crt back over cnt chars perhaps 14097502Sroot * erasing them. 14107502Sroot */ 14117502Sroot ttyrubo(tp, cnt) 14127625Ssam register struct tty *tp; 14137625Ssam int cnt; 14147502Sroot { 14159578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14167502Sroot 14177502Sroot while (--cnt >= 0) 14189578Ssam ttyout(rubostring, tp); 14197502Sroot } 14207502Sroot 14217502Sroot /* 14227502Sroot * Reprint the rawq line. 14237502Sroot * We assume c_cc has already been checked. 14247502Sroot */ 14257502Sroot ttyretype(tp) 14267625Ssam register struct tty *tp; 14277502Sroot { 14287502Sroot register char *cp; 14297502Sroot char *nextc(); 14307502Sroot int s; 14317502Sroot 14329578Ssam if (tp->t_rprntc != 0377) 14339578Ssam ttyecho(tp->t_rprntc, tp); 14347502Sroot (void) ttyoutput('\n', tp); 14357502Sroot s = spl5(); 14367502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14377502Sroot ttyecho(*cp, tp); 14387502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14397502Sroot ttyecho(*cp, tp); 14409578Ssam tp->t_state &= ~TS_ERASE; 14417502Sroot splx(s); 14427502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14437502Sroot tp->t_rocol = 0; 14447502Sroot } 14457502Sroot 14467502Sroot /* 14477502Sroot * Echo a typed character to the terminal 14487502Sroot */ 14497502Sroot ttyecho(c, tp) 14507625Ssam register c; 14517625Ssam register struct tty *tp; 14527502Sroot { 14537502Sroot 14549578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14559578Ssam tp->t_flags &= ~FLUSHO; 14567502Sroot if ((tp->t_flags&ECHO) == 0) 14577502Sroot return; 14587502Sroot c &= 0377; 14597502Sroot if (tp->t_flags&RAW) { 14607502Sroot (void) ttyoutput(c, tp); 14617502Sroot return; 14627502Sroot } 14637502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14647502Sroot c = '\n'; 14659578Ssam if (tp->t_flags&CTLECH) { 14667502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14677502Sroot (void) ttyoutput('^', tp); 14687502Sroot c &= 0177; 14697502Sroot if (c == 0177) 14707502Sroot c = '?'; 14717502Sroot else if (tp->t_flags&LCASE) 14727502Sroot c += 'a' - 1; 14737502Sroot else 14747502Sroot c += 'A' - 1; 14757502Sroot } 14767502Sroot } 14777502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14787502Sroot c += 'a' - 'A'; 14799578Ssam (void) ttyoutput(c&0177, tp); 14807502Sroot } 14817502Sroot 14827502Sroot /* 14837502Sroot * Is c a break char for tp? 14847502Sroot */ 14857502Sroot ttbreakc(c, tp) 14867625Ssam register c; 14877625Ssam register struct tty *tp; 14887502Sroot { 14899578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14907502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14917502Sroot } 14927502Sroot 14937502Sroot /* 14947502Sroot * send string cp to tp 14957502Sroot */ 14967502Sroot ttyout(cp, tp) 14977625Ssam register char *cp; 14987625Ssam register struct tty *tp; 14997502Sroot { 15007502Sroot register char c; 15017502Sroot 15027502Sroot while (c = *cp++) 15037502Sroot (void) ttyoutput(c, tp); 15047502Sroot } 15057502Sroot 15067502Sroot ttwakeup(tp) 15077502Sroot struct tty *tp; 15087502Sroot { 15097502Sroot 15107502Sroot if (tp->t_rsel) { 15117502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15127502Sroot tp->t_state &= ~TS_RCOLL; 15137502Sroot tp->t_rsel = 0; 15147502Sroot } 151512752Ssam if (tp->t_state & TS_ASYNC) 151612752Ssam gsignal(tp->t_pgrp, SIGIO); 15177502Sroot wakeup((caddr_t)&tp->t_rawq); 15187502Sroot } 15197502Sroot 152013533Ssam #if !defined(vax) 15219578Ssam scanc(size, cp, table, mask) 15229578Ssam register int size; 15239578Ssam register char *cp, table[]; 15249578Ssam register int mask; 15257502Sroot { 15269578Ssam register int i = 0; 15277502Sroot 15289578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15299578Ssam i++; 15309578Ssam return (i); 15317502Sroot } 15329578Ssam #endif 1533