1*9760Ssam /* tty.c 4.37 82/12/17 */ 239Sbill 3*9760Ssam #include "../machine/reg.h" 4*9760Ssam 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 */ 115903Sbill wflushtty(tp) 1165408Swnj register struct tty *tp; 11739Sbill { 11839Sbill 119903Sbill (void) spl5(); 1205622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1215622Swnj && tp->t_oproc) { /* kludge for pty */ 122903Sbill (*tp->t_oproc)(tp); 1235408Swnj tp->t_state |= TS_ASLEEP; 124903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 125903Sbill } 1265426Swnj flushtty(tp, FREAD); 127903Sbill (void) spl0(); 12839Sbill } 12939Sbill 13039Sbill /* 1319578Ssam * Flush all TTY queues 13239Sbill */ 133903Sbill flushtty(tp, rw) 1347625Ssam register struct tty *tp; 13539Sbill { 136903Sbill register s; 137903Sbill 138903Sbill s = spl6(); 139903Sbill if (rw & FREAD) { 140903Sbill while (getc(&tp->t_canq) >= 0) 141903Sbill ; 142903Sbill wakeup((caddr_t)&tp->t_rawq); 143903Sbill } 144903Sbill if (rw & FWRITE) { 145903Sbill wakeup((caddr_t)&tp->t_outq); 1465408Swnj tp->t_state &= ~TS_TTSTOP; 1475426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 148903Sbill while (getc(&tp->t_outq) >= 0) 149903Sbill ; 150903Sbill } 151903Sbill if (rw & FREAD) { 152903Sbill while (getc(&tp->t_rawq) >= 0) 153903Sbill ; 154903Sbill tp->t_delct = 0; 1559578Ssam tp->t_rocount = 0; 156903Sbill tp->t_rocol = 0; 1579578Ssam tp->t_state &= ~TS_LOCAL; 158903Sbill } 159903Sbill splx(s); 16039Sbill } 16139Sbill 162903Sbill /* 163903Sbill * Send stop character on input overflow. 164903Sbill */ 165903Sbill ttyblock(tp) 1667625Ssam register struct tty *tp; 16739Sbill { 168903Sbill register x; 1699578Ssam 170903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 171903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 172903Sbill flushtty(tp, FREAD|FWRITE); 1735408Swnj tp->t_state &= ~TS_TBLOCK; 174903Sbill } 1759578Ssam if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) { 1769578Ssam tp->t_state |= TS_TBLOCK; 1779578Ssam tp->t_char++; 1789578Ssam ttstart(tp); 179903Sbill } 18039Sbill } 18139Sbill 18239Sbill /* 183903Sbill * Restart typewriter output following a delay 184903Sbill * timeout. 185903Sbill * The name of the routine is passed to the timeout 186903Sbill * subroutine and it is called during a clock interrupt. 187121Sbill */ 188903Sbill ttrstrt(tp) 1897625Ssam register struct tty *tp; 190121Sbill { 191121Sbill 1929578Ssam if (tp == 0) 1939578Ssam panic("ttrstrt"); 1945408Swnj tp->t_state &= ~TS_TIMEOUT; 195903Sbill ttstart(tp); 196121Sbill } 197121Sbill 198121Sbill /* 199903Sbill * Start output on the typewriter. It is used from the top half 200903Sbill * after some characters have been put on the output queue, 201903Sbill * from the interrupt routine to transmit the next 202903Sbill * character, and after a timeout has finished. 20339Sbill */ 204903Sbill ttstart(tp) 2057625Ssam register struct tty *tp; 20639Sbill { 207903Sbill register s; 20839Sbill 209903Sbill s = spl5(); 2109578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2115622Swnj tp->t_oproc) /* kludge for pty */ 212903Sbill (*tp->t_oproc)(tp); 213903Sbill splx(s); 21439Sbill } 21539Sbill 21639Sbill /* 217903Sbill * Common code for tty ioctls. 21839Sbill */ 2191780Sbill /*ARGSUSED*/ 2207625Ssam ttioctl(tp, com, data, flag) 2217625Ssam register struct tty *tp; 2227625Ssam caddr_t data; 22339Sbill { 2248520Sroot int dev = tp->t_dev; 22539Sbill extern int nldisp; 2268556Sroot int s; 22739Sbill 228903Sbill /* 229903Sbill * If the ioctl involves modification, 230903Sbill * insist on being able to write the device, 231903Sbill * and hang if in the background. 232903Sbill */ 2337625Ssam switch (com) { 23439Sbill 235915Sbill case TIOCSETD: 236915Sbill case TIOCSETP: 237915Sbill case TIOCSETN: 238903Sbill case TIOCFLUSH: 239903Sbill case TIOCSETC: 240903Sbill case TIOCSLTC: 241903Sbill case TIOCSPGRP: 242903Sbill case TIOCLBIS: 243903Sbill case TIOCLBIC: 244903Sbill case TIOCLSET: 2459624Ssam case TIOCBIS: 2469624Ssam case TIOCBIC: 2479624Ssam case TIOCSET: 2489325Ssam case TIOCSTI: 249903Sbill while (tp->t_line == NTTYDISC && 250903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 251903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 252903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2538556Sroot u.u_signal[SIGTTOU] != SIG_HOLD) { 254903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 255903Sbill sleep((caddr_t)&lbolt, TTOPRI); 256903Sbill } 257903Sbill break; 258903Sbill } 259903Sbill 2609578Ssam /* 2619578Ssam * Process the ioctl. 2629578Ssam */ 2637625Ssam switch (com) { 264903Sbill 2658556Sroot /* get discipline number */ 26639Sbill case TIOCGETD: 2677625Ssam *(int *)data = tp->t_line; 26839Sbill break; 26939Sbill 2708556Sroot /* set line discipline */ 2717625Ssam case TIOCSETD: { 2727625Ssam register int t = *(int *)data; 2739578Ssam int error = 0; 2747625Ssam 2759578Ssam if (t >= nldisp) { 2769578Ssam u.u_error = ENXIO; 2779578Ssam break; 2789578Ssam } 2798556Sroot s = spl5(); 28039Sbill if (tp->t_line) 28139Sbill (*linesw[tp->t_line].l_close)(tp); 28239Sbill if (t) 2838556Sroot error = (*linesw[t].l_open)(dev, tp); 2848556Sroot splx(s); 2858556Sroot if (error) 2868556Sroot return (error); 2878556Sroot tp->t_line = t; 28839Sbill break; 2897625Ssam } 29039Sbill 2918556Sroot /* prevent more opens on channel */ 2925614Swnj case TIOCEXCL: 2935614Swnj tp->t_state |= TS_XCLUDE; 2945614Swnj break; 2955614Swnj 2965614Swnj case TIOCNXCL: 2975614Swnj tp->t_state &= ~TS_XCLUDE; 2985614Swnj break; 2995614Swnj 3009624Ssam case TIOCSET: 3019624Ssam case TIOCBIS: { 3029624Ssam u_long newflags = *(u_long *)data; 3037625Ssam 3049624Ssam s = spl5(); 3059624Ssam if (tp->t_flags&RAW || newflags&RAW) 3064484Swnj wflushtty(tp); 3079624Ssam else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) 3089624Ssam if (newflags&CBREAK) { 3099624Ssam struct clist tq; 3109624Ssam 3114484Swnj catq(&tp->t_rawq, &tp->t_canq); 3124484Swnj tq = tp->t_rawq; 3134484Swnj tp->t_rawq = tp->t_canq; 3144484Swnj tp->t_canq = tq; 3154484Swnj } else { 3169578Ssam tp->t_flags |= PENDIN; 3174484Swnj ttwakeup(tp); 318174Sbill } 3199624Ssam if (com == TIOCSET) 3209624Ssam tp->t_flags = newflags; 3219624Ssam else 3229624Ssam tp->t_flags |= newflags; 3239578Ssam if (tp->t_flags&RAW) { 3245408Swnj tp->t_state &= ~TS_TTSTOP; 3253941Sbugs ttstart(tp); 3263941Sbugs } 3279624Ssam splx(s); 32839Sbill break; 3297625Ssam } 33039Sbill 3319624Ssam case TIOCBIC: { 3329624Ssam u_long newflags = *(long *)data; 3337625Ssam 3349624Ssam if (tp->t_flags&RAW) 3359624Ssam wflushtty(tp); 3369624Ssam else if ((tp->t_flags&CBREAK) != (CBREAK&~newflags)) 3379624Ssam if (newflags&CBREAK) { 3389624Ssam tp->t_flags |= PENDIN; 3399624Ssam ttwakeup(tp); 3409624Ssam } else { 3419624Ssam struct clist tq; 3429624Ssam 3439624Ssam catq(&tp->t_rawq, &tp->t_canq); 3449624Ssam tq = tp->t_rawq; 3459624Ssam tp->t_rawq = tp->t_canq; 3469624Ssam tp->t_canq = tq; 3479624Ssam } 3489624Ssam if (tp->t_flags&RAW) { 3499624Ssam tp->t_state &= ~TS_TTSTOP; 3509624Ssam ttstart(tp); 3519624Ssam } 3529624Ssam splx(s); 35339Sbill break; 3547625Ssam } 35539Sbill 3569624Ssam case TIOCGET: 3579624Ssam *(long *)data = tp->t_flags; 3589624Ssam break; 3599624Ssam 3609624Ssam case TIOCCGET: 3619624Ssam bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars)); 3629624Ssam break; 3639624Ssam 3649624Ssam case TIOCCSET: 3659624Ssam bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars)); 3669624Ssam break; 3679624Ssam 3688556Sroot /* hang up line on last close */ 36939Sbill case TIOCHPCL: 3705408Swnj tp->t_state |= TS_HUPCLS; 37139Sbill break; 37239Sbill 3733942Sbugs case TIOCFLUSH: { 3747625Ssam register int flags = *(int *)data; 3757625Ssam 3767625Ssam if (flags == 0) 3773942Sbugs flags = FREAD|FWRITE; 3787625Ssam else 3797625Ssam flags &= FREAD|FWRITE; 3803942Sbugs flushtty(tp, flags); 38139Sbill break; 3823944Sbugs } 38339Sbill 3848556Sroot /* return number of characters immediately available */ 3857625Ssam case FIONREAD: 3867625Ssam *(off_t *)data = ttnread(tp); 387174Sbill break; 388174Sbill 3898589Sroot case TIOCSTOP: 3908589Sroot s = spl5(); 3919578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3925573Swnj tp->t_state |= TS_TTSTOP; 3935573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3945573Swnj } 3957625Ssam splx(s); 3965573Swnj break; 3975573Swnj 3988589Sroot case TIOCSTART: 3998589Sroot s = spl5(); 4009578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 4015573Swnj tp->t_state &= ~TS_TTSTOP; 4029578Ssam tp->t_flags &= ~FLUSHO; 4035573Swnj ttstart(tp); 4045573Swnj } 4057625Ssam splx(s); 4065573Swnj break; 4075573Swnj 4089325Ssam /* 4099325Ssam * Simulate typing of a character at the terminal. 4109325Ssam */ 4119325Ssam case TIOCSTI: 4129325Ssam if (u.u_uid && u.u_ttyp != tp) 4139325Ssam return (EACCES); 4149578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4159325Ssam break; 4169325Ssam 41739Sbill default: 4189624Ssam #ifndef NOCOMPAT 4199624Ssam return (ottioctl(tp, com, data, flag)); 4209624Ssam #else 4218556Sroot return (-1); 4229624Ssam #endif 42339Sbill } 4248556Sroot return (0); 42539Sbill } 4264484Swnj 4274484Swnj ttnread(tp) 4284484Swnj struct tty *tp; 4294484Swnj { 4304484Swnj int nread = 0; 4314484Swnj 4329578Ssam if (tp->t_flags & PENDIN) 4334484Swnj ttypend(tp); 4344484Swnj nread = tp->t_canq.c_cc; 4354484Swnj if (tp->t_flags & (RAW|CBREAK)) 4364484Swnj nread += tp->t_rawq.c_cc; 4374484Swnj return (nread); 4384484Swnj } 4394484Swnj 4405408Swnj ttselect(dev, rw) 4414484Swnj dev_t dev; 4425408Swnj int rw; 4434484Swnj { 4444484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4454484Swnj int nread; 4465408Swnj int s = spl5(); 4474484Swnj 4485408Swnj switch (rw) { 4494484Swnj 4504484Swnj case FREAD: 4514484Swnj nread = ttnread(tp); 4524484Swnj if (nread > 0) 4535408Swnj goto win; 4544938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 4555408Swnj tp->t_state |= TS_RCOLL; 4564484Swnj else 4574484Swnj tp->t_rsel = u.u_procp; 4585408Swnj break; 4594484Swnj 4605408Swnj case FWRITE: 4615408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 4625408Swnj goto win; 4635408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 4645408Swnj tp->t_state |= TS_WCOLL; 4655408Swnj else 4665408Swnj tp->t_wsel = u.u_procp; 4675408Swnj break; 4684484Swnj } 4695408Swnj splx(s); 4705408Swnj return (0); 4715408Swnj win: 4725408Swnj splx(s); 4735408Swnj return (1); 4744484Swnj } 4757436Skre 4767502Sroot /* 4779578Ssam * Establish a process group for distribution of 4787502Sroot * quits and interrupts from the tty. 4797502Sroot */ 4807502Sroot ttyopen(dev, tp) 4817625Ssam dev_t dev; 4827625Ssam register struct tty *tp; 4837502Sroot { 4847502Sroot register struct proc *pp; 4857502Sroot 4867502Sroot pp = u.u_procp; 4877502Sroot tp->t_dev = dev; 4887625Ssam if (pp->p_pgrp == 0) { 4897502Sroot u.u_ttyp = tp; 4907502Sroot u.u_ttyd = dev; 4917502Sroot if (tp->t_pgrp == 0) 4927502Sroot tp->t_pgrp = pp->p_pid; 4937502Sroot pp->p_pgrp = tp->t_pgrp; 4947502Sroot } 4957502Sroot tp->t_state &= ~TS_WOPEN; 4967502Sroot tp->t_state |= TS_ISOPEN; 4977502Sroot if (tp->t_line != NTTYDISC) 4987502Sroot wflushtty(tp); 4998556Sroot return (0); 5007502Sroot } 5017502Sroot 5027502Sroot /* 5037502Sroot * clean tp on last close 5047502Sroot */ 5057502Sroot ttyclose(tp) 5067625Ssam register struct tty *tp; 5077502Sroot { 5087502Sroot 5097502Sroot if (tp->t_line) { 5107502Sroot wflushtty(tp); 5117502Sroot tp->t_line = 0; 5127502Sroot return; 5137502Sroot } 5147502Sroot tp->t_pgrp = 0; 5157502Sroot wflushtty(tp); 5167502Sroot tp->t_state = 0; 5177502Sroot } 5187502Sroot 5197502Sroot /* 5207502Sroot * reinput pending characters after state switch 5217502Sroot * call at spl5(). 5227502Sroot */ 5237502Sroot ttypend(tp) 5247625Ssam register struct tty *tp; 5257502Sroot { 5267502Sroot struct clist tq; 5277502Sroot register c; 5287502Sroot 5299578Ssam tp->t_flags &= ~PENDIN; 5309578Ssam tp->t_state |= TS_TYPEN; 5317502Sroot tq = tp->t_rawq; 5327502Sroot tp->t_rawq.c_cc = 0; 5337502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5347502Sroot while ((c = getc(&tq)) >= 0) 5357502Sroot ttyinput(c, tp); 5369578Ssam tp->t_state &= ~TS_TYPEN; 5377502Sroot } 5387502Sroot 5397502Sroot /* 5409578Ssam * Place a character on raw TTY input queue, 5419578Ssam * putting in delimiters and waking up top 5429578Ssam * half as needed. Also echo if required. 5439578Ssam * The arguments are the character and the 5449578Ssam * appropriate tty structure. 5457502Sroot */ 5467502Sroot ttyinput(c, tp) 5477625Ssam register c; 5487625Ssam register struct tty *tp; 5497502Sroot { 5509578Ssam register int t_flags = tp->t_flags; 5517502Sroot int i; 5527502Sroot 5539578Ssam /* 5549578Ssam * If input is pending take it first. 5559578Ssam */ 5569578Ssam if (t_flags&PENDIN) 5577502Sroot ttypend(tp); 5587502Sroot tk_nin++; 5597502Sroot c &= 0377; 5609578Ssam 5619578Ssam /* 5629578Ssam * In tandem mode, check high water mark. 5639578Ssam */ 5647502Sroot if (t_flags&TANDEM) 5657502Sroot ttyblock(tp); 5669578Ssam 5679578Ssam if (t_flags&RAW) { 5689578Ssam /* 5699578Ssam * Raw mode, just put character 5709578Ssam * in input q w/o interpretation. 5719578Ssam */ 5729578Ssam if (tp->t_rawq.c_cc > TTYHOG) 5739578Ssam flushtty(tp, FREAD|FWRITE); 5749578Ssam else { 5759578Ssam if (putc(c, &tp->t_rawq) >= 0) 5769578Ssam ttwakeup(tp); 5779578Ssam ttyecho(c, tp); 5787502Sroot } 5799578Ssam goto endcase; 5809578Ssam } 5819578Ssam 5829578Ssam /* 5839578Ssam * Ignore any high bit added during 5849578Ssam * previous ttyinput processing. 5859578Ssam */ 5869578Ssam if ((tp->t_state&TS_TYPEN) == 0) 5879578Ssam c &= 0177; 5889578Ssam /* 5899578Ssam * Check for literal nexting very first 5909578Ssam */ 5919578Ssam if (tp->t_state&TS_LNCH) { 5929578Ssam c |= 0200; 5939578Ssam tp->t_state &= ~TS_LNCH; 5949578Ssam } 5959578Ssam 5969578Ssam /* 5979578Ssam * Scan for special characters. This code 5989578Ssam * is really just a big case statement with 5999578Ssam * non-constant cases. The bottom of the 6009578Ssam * case statement is labeled ``endcase'', so goto 6019578Ssam * it after a case match, or similar. 6029578Ssam */ 6039578Ssam if (tp->t_line == NTTYDISC) { 6049578Ssam if (c == tp->t_lnextc) { 6057502Sroot if (tp->t_flags&ECHO) 6067502Sroot ttyout("^\b", tp); 6079578Ssam tp->t_state |= TS_LNCH; 6089578Ssam goto endcase; 6099578Ssam } 6109578Ssam if (c == tp->t_flushc) { 6119578Ssam if (tp->t_flags&FLUSHO) 6129578Ssam tp->t_flags &= ~FLUSHO; 6137502Sroot else { 6147502Sroot flushtty(tp, FWRITE); 6157502Sroot ttyecho(c, tp); 6169578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6177502Sroot ttyretype(tp); 6189578Ssam tp->t_flags |= FLUSHO; 6197502Sroot } 6209578Ssam goto startoutput; 6219578Ssam } 6229578Ssam if (c == tp->t_suspc) { 6239578Ssam if ((tp->t_flags&NOFLSH) == 0) 6249578Ssam flushtty(tp, FREAD); 6259578Ssam ttyecho(c, tp); 6269578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6279578Ssam goto endcase; 6289578Ssam } 6299578Ssam } 6309578Ssam 6319578Ssam /* 6329578Ssam * Handle start/stop characters. 6339578Ssam */ 6349578Ssam if (c == tp->t_stopc) { 6359578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6369578Ssam tp->t_state |= TS_TTSTOP; 6379578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6387502Sroot return; 6399578Ssam } 6409578Ssam if (c != tp->t_startc) 6419578Ssam return; 6429578Ssam goto endcase; 6439578Ssam } 6449578Ssam if (c == tp->t_startc) 6459578Ssam goto restartoutput; 6469578Ssam 6479578Ssam /* 6489578Ssam * Look for interrupt/quit chars. 6499578Ssam */ 6509578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 6519578Ssam if ((tp->t_flags&NOFLSH) == 0) 6529578Ssam flushtty(tp, FREAD|FWRITE); 6539578Ssam ttyecho(c, tp); 6549578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 6559578Ssam goto endcase; 6569578Ssam } 6579578Ssam 6589578Ssam /* 6599578Ssam * Cbreak mode, don't process line editing 6609578Ssam * characters; check high water mark for wakeup. 6619578Ssam */ 6629578Ssam if (t_flags&CBREAK) { 6639578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 6647502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 6657502Sroot tp->t_line == NTTYDISC) 6667502Sroot (void) ttyoutput(CTRL(g), tp); 6677502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 6687502Sroot ttwakeup(tp); 6697502Sroot ttyecho(c, tp); 6707502Sroot } 6719578Ssam goto endcase; 6729578Ssam } 6739578Ssam 6749578Ssam /* 6759578Ssam * From here on down cooked mode character 6769578Ssam * processing takes place. 6779578Ssam */ 6789578Ssam if ((tp->t_state&TS_QUOT) && 6799578Ssam (c == tp->t_erase || c == tp->t_kill)) { 6809578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6819578Ssam c |= 0200; 6829578Ssam } 6839578Ssam if (c == tp->t_erase) { 6849578Ssam if (tp->t_rawq.c_cc) 6859578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6869578Ssam goto endcase; 6879578Ssam } 6889578Ssam if (c == tp->t_kill) { 6899578Ssam if (tp->t_flags&CRTKIL && 6909578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 6919578Ssam while (tp->t_rawq.c_cc) 6929578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6939578Ssam } else { 6949578Ssam ttyecho(c, tp); 6959578Ssam ttyecho('\n', tp); 6969578Ssam while (getc(&tp->t_rawq) > 0) 6979578Ssam ; 6989578Ssam tp->t_rocount = 0; 6999578Ssam } 7009578Ssam tp->t_state &= ~TS_LOCAL; 7019578Ssam goto endcase; 7029578Ssam } 7039578Ssam 7049578Ssam /* 7059578Ssam * New line discipline, 7069578Ssam * check word erase/reprint line. 7079578Ssam */ 7089578Ssam if (tp->t_line == NTTYDISC) { 7099578Ssam if (c == tp->t_werasc) { 7109578Ssam if (tp->t_rawq.c_cc == 0) 7119578Ssam goto endcase; 7129578Ssam do { 7139578Ssam c = unputc(&tp->t_rawq); 7149578Ssam if (c != ' ' && c != '\t') 7159578Ssam goto erasenb; 7169578Ssam ttyrub(c, tp); 7179578Ssam } while (tp->t_rawq.c_cc); 7189578Ssam goto endcase; 7199578Ssam erasenb: 7209578Ssam do { 7219578Ssam ttyrub(c, tp); 7229578Ssam if (tp->t_rawq.c_cc == 0) 7239578Ssam goto endcase; 7249578Ssam c = unputc(&tp->t_rawq); 7259578Ssam } while (c != ' ' && c != '\t'); 7269578Ssam (void) putc(c, &tp->t_rawq); 7279578Ssam goto endcase; 7289578Ssam } 7299578Ssam if (c == tp->t_rprntc) { 7309578Ssam ttyretype(tp); 7319578Ssam goto endcase; 7329578Ssam } 7339578Ssam } 7349578Ssam 7359578Ssam /* 7369578Ssam * Check for input buffer overflow 7379578Ssam */ 7389578Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) 7399578Ssam goto endcase; 7409578Ssam 7419578Ssam /* 7429578Ssam * Put data char in q for user and 7439578Ssam * wakeup on seeing a line delimiter. 7449578Ssam */ 7459578Ssam if (putc(c, &tp->t_rawq) >= 0) { 7469578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc == TTYHOG 7479578Ssam && tp->t_line == NTTYDISC) 7489578Ssam (void) ttyoutput(CTRL(g), tp); 7499578Ssam if (ttbreakc(c, tp)) { 7509578Ssam tp->t_rocount = 0; 7519578Ssam catq(&tp->t_rawq, &tp->t_canq); 7527502Sroot ttwakeup(tp); 7539578Ssam } else if (tp->t_rocount++ == 0) 7549578Ssam tp->t_rocol = tp->t_col; 7559578Ssam tp->t_state &= ~TS_QUOT; 7569578Ssam if (c == '\\') 7579578Ssam tp->t_state |= TS_QUOT; 7589578Ssam if (tp->t_state&TS_ERASE) { 7599578Ssam tp->t_state &= ~TS_ERASE; 7609578Ssam (void) ttyoutput('/', tp); 7619578Ssam } 7629578Ssam i = tp->t_col; 7637502Sroot ttyecho(c, tp); 7649578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 7659578Ssam i = MIN(2, tp->t_col - i); 7669578Ssam while (i > 0) { 7679578Ssam (void) ttyoutput('\b', tp); 7689578Ssam i--; 7699578Ssam } 7709578Ssam } 7717502Sroot } 7729578Ssam 7739578Ssam endcase: 7749578Ssam /* 7759578Ssam * If DEC-style start/stop is enabled don't restart 7769578Ssam * output until seeing the start character. 7779578Ssam */ 7789578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 7799578Ssam tp->t_startc != tp->t_stopc) 7807502Sroot return; 7819578Ssam 7829578Ssam restartoutput: 7837502Sroot tp->t_state &= ~TS_TTSTOP; 7849578Ssam tp->t_flags &= ~FLUSHO; 7859578Ssam 7869578Ssam startoutput: 7877502Sroot ttstart(tp); 7887502Sroot } 7897502Sroot 7907502Sroot /* 7919578Ssam * Put character on TTY output queue, adding delays, 7927502Sroot * expanding tabs, and handling the CR/NL bit. 7939578Ssam * This is called both from the top half for output, 7949578Ssam * and from interrupt level for echoing. 7957502Sroot * The arguments are the character and the tty structure. 7967502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 7977502Sroot * Must be recursive. 7987502Sroot */ 7997502Sroot ttyoutput(c, tp) 8007502Sroot register c; 8017502Sroot register struct tty *tp; 8027502Sroot { 8037502Sroot register char *colp; 8047502Sroot register ctype; 8057502Sroot 8069578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8079578Ssam if (tp->t_flags&FLUSHO) 8087502Sroot return (-1); 8097502Sroot if (putc(c, &tp->t_outq)) 8107625Ssam return (c); 8117502Sroot tk_nout++; 8127502Sroot return (-1); 8137502Sroot } 8149578Ssam 8157502Sroot /* 8169578Ssam * Ignore EOT in normal mode to avoid 8179578Ssam * hanging up certain terminals. 8187502Sroot */ 8197502Sroot c &= 0177; 8209578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8217502Sroot return (-1); 8227502Sroot /* 8237502Sroot * Turn tabs to spaces as required 8247502Sroot */ 8259578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8267502Sroot register int s; 8277502Sroot 8287502Sroot c = 8 - (tp->t_col&7); 8299578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8307502Sroot s = spl5(); /* don't interrupt tabs */ 8317502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8327502Sroot tk_nout += c; 8337502Sroot splx(s); 8347502Sroot } 8357502Sroot tp->t_col += c; 8367502Sroot return (c ? -1 : '\t'); 8377502Sroot } 8387502Sroot tk_nout++; 8397502Sroot /* 8407502Sroot * for upper-case-only terminals, 8417502Sroot * generate escapes. 8427502Sroot */ 8437502Sroot if (tp->t_flags&LCASE) { 8447502Sroot colp = "({)}!|^~'`"; 8457625Ssam while (*colp++) 8467625Ssam if (c == *colp++) { 8477502Sroot if (ttyoutput('\\', tp) >= 0) 8487502Sroot return (c); 8497502Sroot c = colp[-2]; 8507502Sroot break; 8517502Sroot } 8529578Ssam if ('A' <= c && c <= 'Z') { 8537502Sroot if (ttyoutput('\\', tp) >= 0) 8547502Sroot return (c); 8559578Ssam } else if ('a' <= c && c <= 'z') 8567502Sroot c += 'A' - 'a'; 8577502Sroot } 8589578Ssam 8597502Sroot /* 8607502Sroot * turn <nl> to <cr><lf> if desired. 8617502Sroot */ 8629578Ssam if (c == '\n' && tp->t_flags&CRMOD) 8637502Sroot if (ttyoutput('\r', tp) >= 0) 8647502Sroot return (c); 8659578Ssam if (c == '~' && tp->t_flags&TILDE) 8667502Sroot c = '`'; 8679578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 8687502Sroot return (c); 8697502Sroot /* 8707502Sroot * Calculate delays. 8717502Sroot * The numbers here represent clock ticks 8727502Sroot * and are not necessarily optimal for all terminals. 8737502Sroot * The delays are indicated by characters above 0200. 8747502Sroot * In raw mode there are no delays and the 8757502Sroot * transmission path is 8 bits wide. 8769578Ssam * 8779578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 8787502Sroot */ 8797502Sroot colp = &tp->t_col; 8807502Sroot ctype = partab[c]; 8817502Sroot c = 0; 8827502Sroot switch (ctype&077) { 8837502Sroot 8847502Sroot case ORDINARY: 8857502Sroot (*colp)++; 8867502Sroot 8877502Sroot case CONTROL: 8887502Sroot break; 8897502Sroot 8907502Sroot case BACKSPACE: 8917502Sroot if (*colp) 8927502Sroot (*colp)--; 8937502Sroot break; 8947502Sroot 8957502Sroot case NEWLINE: 8967502Sroot ctype = (tp->t_flags >> 8) & 03; 8977625Ssam if (ctype == 1) { /* tty 37 */ 8987502Sroot if (*colp) 8997502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9009578Ssam } else if (ctype == 2) /* vt05 */ 9017502Sroot c = 6; 9027502Sroot *colp = 0; 9037502Sroot break; 9047502Sroot 9057502Sroot case TAB: 9067502Sroot ctype = (tp->t_flags >> 10) & 03; 9077625Ssam if (ctype == 1) { /* tty 37 */ 9087502Sroot c = 1 - (*colp | ~07); 9097625Ssam if (c < 5) 9107502Sroot c = 0; 9117502Sroot } 9127502Sroot *colp |= 07; 9137502Sroot (*colp)++; 9147502Sroot break; 9157502Sroot 9167502Sroot case VTAB: 9179578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9187502Sroot c = 0177; 9197502Sroot break; 9207502Sroot 9217502Sroot case RETURN: 9227502Sroot ctype = (tp->t_flags >> 12) & 03; 9239578Ssam if (ctype == 1) /* tn 300 */ 9247502Sroot c = 5; 9259578Ssam else if (ctype == 2) /* ti 700 */ 9267502Sroot c = 10; 9279578Ssam else if (ctype == 3) { /* concept 100 */ 9287502Sroot int i; 9299578Ssam 9307502Sroot if ((i = *colp) >= 0) 9319578Ssam for (; i < 9; i++) 9327502Sroot (void) putc(0177, &tp->t_outq); 9337502Sroot } 9347502Sroot *colp = 0; 9357502Sroot } 9369578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9377502Sroot (void) putc(c|0200, &tp->t_outq); 9387502Sroot return (-1); 9397502Sroot } 9407502Sroot 9417502Sroot /* 9427502Sroot * Called from device's read routine after it has 9437502Sroot * calculated the tty-structure given as argument. 9447502Sroot */ 9457722Swnj ttread(tp, uio) 9467625Ssam register struct tty *tp; 9477722Swnj struct uio *uio; 9487502Sroot { 9497502Sroot register struct clist *qp; 9509578Ssam register c, t_flags; 9519578Ssam int first, error = 0; 9527502Sroot 9537502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9548520Sroot return (EIO); 9557502Sroot loop: 9569578Ssam /* 9579578Ssam * Take any pending input first. 9589578Ssam */ 9597502Sroot (void) spl5(); 9609578Ssam if (tp->t_flags&PENDIN) 9617502Sroot ttypend(tp); 9627502Sroot (void) spl0(); 9639578Ssam 9649578Ssam /* 9659578Ssam * Hang process if it's in the background. 9669578Ssam */ 9677502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9687502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9697502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9707502Sroot /* 9717502Sroot (u.u_procp->p_flag&SDETACH) || 9727502Sroot */ 9737502Sroot u.u_procp->p_flag&SVFORK) 9748520Sroot return (EIO); 9757502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9767502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9777502Sroot } 9789578Ssam t_flags = tp->t_flags; 9799578Ssam 9809578Ssam /* 9819578Ssam * In raw mode take characters directly from the 9829578Ssam * raw queue w/o processing. Interlock against 9839578Ssam * device interrupts when interrogating rawq. 9849578Ssam */ 9859578Ssam if (t_flags&RAW) { 9867502Sroot (void) spl5(); 9877502Sroot if (tp->t_rawq.c_cc <= 0) { 9889578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 9897502Sroot (tp->t_state&TS_NBIO)) { 9907502Sroot (void) spl0(); 9919578Ssam return (0); 9927502Sroot } 9937502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9947502Sroot (void) spl0(); 9957502Sroot goto loop; 9967502Sroot } 9977502Sroot (void) spl0(); 9987722Swnj while (tp->t_rawq.c_cc && uio->uio_iovcnt) { 9998520Sroot error = passuc(getc(&tp->t_rawq), uio); 10008520Sroot if (error) 10017722Swnj break; 10027722Swnj } 10038520Sroot return (error); 10049578Ssam } 10059578Ssam 10069578Ssam /* 10079578Ssam * In cbreak mode use the rawq, otherwise 10089578Ssam * take characters from the canonicalized q. 10099578Ssam */ 10109578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10119578Ssam 10129578Ssam /* 10139578Ssam * No input, sleep on rawq awaiting hardware 10149578Ssam * receipt and notification. 10159578Ssam */ 10169578Ssam (void) spl5(); 10179578Ssam if (qp->c_cc <= 0) { 10189578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10199578Ssam (tp->t_state&TS_NBIO)) { 10207502Sroot (void) spl0(); 10219578Ssam return (EWOULDBLOCK); 10227502Sroot } 10239578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10247502Sroot (void) spl0(); 10259578Ssam goto loop; 10269578Ssam } 10279578Ssam (void) spl0(); 10289578Ssam 10299578Ssam /* 10309578Ssam * Input present, perform input mapping 10319578Ssam * and processing (we're not in raw mode). 10329578Ssam */ 10339578Ssam first = 1; 10349578Ssam while ((c = getc(qp)) >= 0) { 10359578Ssam if (t_flags&CRMOD && c == '\r') 10369578Ssam c = '\n'; 10379578Ssam /* 10389578Ssam * Hack lower case simulation on 10399578Ssam * upper case only terminals. 10409578Ssam */ 10419578Ssam if (t_flags&LCASE && c <= 0177) 10429578Ssam if (tp->t_state&TS_BKSL) { 10439578Ssam if (maptab[c]) 10449578Ssam c = maptab[c]; 10459578Ssam tp->t_state &= ~TS_BKSL; 10469578Ssam } else if (c >= 'A' && c <= 'Z') 10479578Ssam c += 'a' - 'A'; 10489578Ssam else if (c == '\\') { 10499578Ssam tp->t_state |= TS_BKSL; 10509578Ssam continue; 10517502Sroot } 10529578Ssam /* 10539578Ssam * Check for delayed suspend character. 10549578Ssam */ 10559578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 10569578Ssam gsignal(tp->t_pgrp, SIGTSTP); 10579578Ssam if (first) { 10589578Ssam sleep((caddr_t)&lbolt, TTIPRI); 10599578Ssam goto loop; 10609578Ssam } 10619578Ssam break; 10627502Sroot } 10639578Ssam /* 10649578Ssam * Interpret EOF only in cooked mode. 10659578Ssam */ 10669578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 10679578Ssam break; 10689578Ssam /* 10699578Ssam * Give user character. 10709578Ssam */ 10719578Ssam error = passuc(c & 0177, uio); 10729578Ssam if (error) 10739578Ssam break; 10749578Ssam if (uio->uio_iovcnt == 0) 10759578Ssam break; 10769578Ssam /* 10779578Ssam * In cooked mode check for a "break character" 10789578Ssam * marking the end of a "line of input". 10799578Ssam */ 10809578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 10819578Ssam break; 10829578Ssam first = 0; 10837502Sroot } 10849578Ssam tp->t_state &= ~TS_BKSL; 10859578Ssam 10869578Ssam /* 10879578Ssam * Look to unblock output now that (presumably) 10889578Ssam * the input queue has gone down. 10899578Ssam */ 10907502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 10919578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 10927502Sroot tp->t_state &= ~TS_TBLOCK; 10937502Sroot ttstart(tp); 10947502Sroot } 10957502Sroot tp->t_char = 0; 10967502Sroot } 10978520Sroot return (error); 10987502Sroot } 10997502Sroot 11007502Sroot /* 11017502Sroot * Called from the device's write routine after it has 11027502Sroot * calculated the tty-structure given as argument. 11037502Sroot */ 11047822Sroot ttwrite(tp, uio) 11057625Ssam register struct tty *tp; 11069578Ssam register struct uio *uio; 11077502Sroot { 11087502Sroot register char *cp; 11099578Ssam register int cc, ce, c; 11109578Ssam int i, hiwat, cnt, error, s; 11117502Sroot char obuf[OBUFSIZ]; 11127502Sroot 11139578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11148520Sroot return (EIO); 11159578Ssam hiwat = TTHIWAT(tp); 11169578Ssam cnt = uio->uio_resid; 11179578Ssam error = 0; 11187502Sroot loop: 11199578Ssam /* 11209578Ssam * Hang the process if it's in the background. 11219578Ssam */ 11227502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11239578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11247502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11257502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11267502Sroot /* 11277502Sroot && 11287502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11297502Sroot */ 11307502Sroot ) { 11317502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11327502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11337502Sroot } 11349578Ssam 11359578Ssam /* 11369578Ssam * Process the user's data in at most OBUFSIZ 11379578Ssam * chunks. Perform lower case simulation and 11389578Ssam * similar hacks. Keep track of high water 11399578Ssam * mark, sleep on overflow awaiting device aid 11409578Ssam * in acquiring new space. 11419578Ssam */ 11427822Sroot while (uio->uio_resid > 0) { 11439578Ssam /* 11449578Ssam * Grab a hunk of data from the user. 11459578Ssam */ 11467822Sroot cc = uio->uio_iov->iov_len; 11477822Sroot if (cc == 0) { 11487822Sroot uio->uio_iovcnt--; 11497822Sroot uio->uio_iov++; 11507822Sroot if (uio->uio_iovcnt < 0) 11517822Sroot panic("ttwrite"); 11527822Sroot continue; 11537822Sroot } 11547822Sroot if (cc > OBUFSIZ) 11557822Sroot cc = OBUFSIZ; 11567502Sroot cp = obuf; 11579578Ssam error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio); 11588520Sroot if (error) 11597502Sroot break; 11607502Sroot if (tp->t_outq.c_cc > hiwat) 11617502Sroot goto ovhiwat; 11629578Ssam if (tp->t_flags&FLUSHO) 11637502Sroot continue; 11649578Ssam /* 11659578Ssam * If we're mapping lower case or kludging tildes, 11669578Ssam * then we've got to look at each character, so 11679578Ssam * just feed the stuff to ttyoutput... 11689578Ssam */ 11699578Ssam if (tp->t_flags & (LCASE|TILDE)) { 11709578Ssam while (cc > 0) { 11717502Sroot c = *cp++; 11727502Sroot tp->t_rocount = 0; 11737625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 11747502Sroot /* out of clists, wait a bit */ 11757502Sroot ttstart(tp); 11767502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11777502Sroot tp->t_rocount = 0; 11787502Sroot } 11797502Sroot --cc; 11807502Sroot if (tp->t_outq.c_cc > hiwat) 11817502Sroot goto ovhiwat; 11827502Sroot } 11837502Sroot continue; 11847502Sroot } 11859578Ssam /* 11869578Ssam * If nothing fancy need be done, grab those characters we 11879578Ssam * can handle without any of ttyoutput's processing and 11889578Ssam * just transfer them to the output q. For those chars 11899578Ssam * which require special processing (as indicated by the 11909578Ssam * bits in partab), call ttyoutput. After processing 11919578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 11929578Ssam * immediately. 11939578Ssam */ 11949578Ssam while (cc > 0) { 11959578Ssam if (tp->t_flags & (RAW|LITOUT)) 11967502Sroot ce = cc; 11977502Sroot else { 11989578Ssam ce = cc - scanc(cc, cp, partab, 077); 11999578Ssam /* 12009578Ssam * If ce is zero, then we're processing 12019578Ssam * a special character through ttyoutput. 12029578Ssam */ 12039578Ssam if (ce == 0) { 12047502Sroot tp->t_rocount = 0; 12057502Sroot if (ttyoutput(*cp, tp) >= 0) { 12069578Ssam /* no c-lists, wait a bit */ 12077502Sroot ttstart(tp); 12087502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12097502Sroot continue; 12107502Sroot } 12119578Ssam cp++, cc--; 12129578Ssam if (tp->t_flags&FLUSHO || 12139578Ssam tp->t_outq.c_cc > hiwat) 12147502Sroot goto ovhiwat; 12159578Ssam continue; 12167502Sroot } 12177502Sroot } 12189578Ssam /* 12199578Ssam * A bunch of normal characters have been found, 12209578Ssam * transfer them en masse to the output queue and 12219578Ssam * continue processing at the top of the loop. 12229578Ssam * If there are any further characters in this 12239578Ssam * <= OBUFSIZ chunk, the first should be a character 12249578Ssam * requiring special handling by ttyoutput. 12259578Ssam */ 12267502Sroot tp->t_rocount = 0; 12279578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12289578Ssam ce -= i; 12299578Ssam tp->t_col += ce; 12309578Ssam cp += ce, cc -= ce, tk_nout += ce; 12319578Ssam if (i > 0) { 12329578Ssam /* out of c-lists, wait a bit */ 12337502Sroot ttstart(tp); 12347502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12357502Sroot } 12369578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12377502Sroot goto ovhiwat; 12387502Sroot } 12397502Sroot } 12407502Sroot ttstart(tp); 12418520Sroot return (error); 12427502Sroot 12437502Sroot ovhiwat: 12449578Ssam s = spl5(); 12459578Ssam if (cc != 0) { 12469578Ssam uio->uio_iov->iov_base -= cc; 12479578Ssam uio->uio_iov->iov_len += cc; 12489578Ssam uio->uio_resid += cc; 12499578Ssam uio->uio_offset -= cc; 12509578Ssam } 12519578Ssam /* 12529578Ssam * This can only occur if FLUSHO 12539578Ssam * is also set in t_flags. 12549578Ssam */ 12557502Sroot if (tp->t_outq.c_cc <= hiwat) { 12569578Ssam splx(s); 12577502Sroot goto loop; 12587502Sroot } 12597502Sroot ttstart(tp); 12609578Ssam if (tp->t_state&TS_NBIO) { 12617822Sroot if (uio->uio_resid == cnt) 12628520Sroot return (EWOULDBLOCK); 12638520Sroot return (0); 12647502Sroot } 12657502Sroot tp->t_state |= TS_ASLEEP; 12667502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 12679578Ssam splx(s); 12687502Sroot goto loop; 12697502Sroot } 12707502Sroot 12717502Sroot /* 12727502Sroot * Rubout one character from the rawq of tp 12737502Sroot * as cleanly as possible. 12747502Sroot */ 12757502Sroot ttyrub(c, tp) 12767625Ssam register c; 12777625Ssam register struct tty *tp; 12787502Sroot { 12797502Sroot register char *cp; 12807502Sroot register int savecol; 12817502Sroot int s; 12827502Sroot char *nextc(); 12837502Sroot 12849578Ssam if ((tp->t_flags&ECHO) == 0) 12857502Sroot return; 12869578Ssam tp->t_flags &= ~FLUSHO; 12877502Sroot c &= 0377; 12889578Ssam if (tp->t_flags&CRTBS) { 12897502Sroot if (tp->t_rocount == 0) { 12907502Sroot /* 12917502Sroot * Screwed by ttwrite; retype 12927502Sroot */ 12937502Sroot ttyretype(tp); 12947502Sroot return; 12957502Sroot } 12969578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 12977502Sroot ttyrubo(tp, 2); 12989578Ssam else switch (partab[c&=0177]&0177) { 12997502Sroot 13007502Sroot case ORDINARY: 13017502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13027502Sroot ttyrubo(tp, 2); 13037502Sroot else 13047502Sroot ttyrubo(tp, 1); 13057502Sroot break; 13067502Sroot 13077502Sroot case VTAB: 13087502Sroot case BACKSPACE: 13097502Sroot case CONTROL: 13107502Sroot case RETURN: 13119578Ssam if (tp->t_flags&CTLECH) 13127502Sroot ttyrubo(tp, 2); 13137502Sroot break; 13147502Sroot 13157502Sroot case TAB: 13167502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13177502Sroot ttyretype(tp); 13187502Sroot return; 13197502Sroot } 13207502Sroot s = spl5(); 13217502Sroot savecol = tp->t_col; 13229578Ssam tp->t_state |= TS_CNTTB; 13239578Ssam tp->t_flags |= FLUSHO; 13247502Sroot tp->t_col = tp->t_rocol; 13259578Ssam cp = tp->t_rawq.c_cf; 13269578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13277502Sroot ttyecho(*cp, tp); 13289578Ssam tp->t_flags &= ~FLUSHO; 13299578Ssam tp->t_state &= ~TS_CNTTB; 13307502Sroot splx(s); 13317502Sroot /* 13327502Sroot * savecol will now be length of the tab 13337502Sroot */ 13347502Sroot savecol -= tp->t_col; 13357502Sroot tp->t_col += savecol; 13367502Sroot if (savecol > 8) 13377502Sroot savecol = 8; /* overflow screw */ 13387502Sroot while (--savecol >= 0) 13397502Sroot (void) ttyoutput('\b', tp); 13407502Sroot break; 13417502Sroot 13427502Sroot default: 13437502Sroot panic("ttyrub"); 13447502Sroot } 13459578Ssam } else if (tp->t_flags&PRTERA) { 13469578Ssam if ((tp->t_state&TS_ERASE) == 0) { 13477502Sroot (void) ttyoutput('\\', tp); 13489578Ssam tp->t_state |= TS_ERASE; 13497502Sroot } 13507502Sroot ttyecho(c, tp); 13517502Sroot } else 13527502Sroot ttyecho(tp->t_erase, tp); 13537502Sroot tp->t_rocount--; 13547502Sroot } 13557502Sroot 13567502Sroot /* 13577502Sroot * Crt back over cnt chars perhaps 13587502Sroot * erasing them. 13597502Sroot */ 13607502Sroot ttyrubo(tp, cnt) 13617625Ssam register struct tty *tp; 13627625Ssam int cnt; 13637502Sroot { 13649578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 13657502Sroot 13667502Sroot while (--cnt >= 0) 13679578Ssam ttyout(rubostring, tp); 13687502Sroot } 13697502Sroot 13707502Sroot /* 13717502Sroot * Reprint the rawq line. 13727502Sroot * We assume c_cc has already been checked. 13737502Sroot */ 13747502Sroot ttyretype(tp) 13757625Ssam register struct tty *tp; 13767502Sroot { 13777502Sroot register char *cp; 13787502Sroot char *nextc(); 13797502Sroot int s; 13807502Sroot 13819578Ssam if (tp->t_rprntc != 0377) 13829578Ssam ttyecho(tp->t_rprntc, tp); 13837502Sroot (void) ttyoutput('\n', tp); 13847502Sroot s = spl5(); 13857502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 13867502Sroot ttyecho(*cp, tp); 13877502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 13887502Sroot ttyecho(*cp, tp); 13899578Ssam tp->t_state &= ~TS_ERASE; 13907502Sroot splx(s); 13917502Sroot tp->t_rocount = tp->t_rawq.c_cc; 13927502Sroot tp->t_rocol = 0; 13937502Sroot } 13947502Sroot 13957502Sroot /* 13967502Sroot * Echo a typed character to the terminal 13977502Sroot */ 13987502Sroot ttyecho(c, tp) 13997625Ssam register c; 14007625Ssam register struct tty *tp; 14017502Sroot { 14027502Sroot 14039578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14049578Ssam tp->t_flags &= ~FLUSHO; 14057502Sroot if ((tp->t_flags&ECHO) == 0) 14067502Sroot return; 14077502Sroot c &= 0377; 14087502Sroot if (tp->t_flags&RAW) { 14097502Sroot (void) ttyoutput(c, tp); 14107502Sroot return; 14117502Sroot } 14127502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14137502Sroot c = '\n'; 14149578Ssam if (tp->t_flags&CTLECH) { 14157502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14167502Sroot (void) ttyoutput('^', tp); 14177502Sroot c &= 0177; 14187502Sroot if (c == 0177) 14197502Sroot c = '?'; 14207502Sroot else if (tp->t_flags&LCASE) 14217502Sroot c += 'a' - 1; 14227502Sroot else 14237502Sroot c += 'A' - 1; 14247502Sroot } 14257502Sroot } 14267502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14277502Sroot c += 'a' - 'A'; 14289578Ssam (void) ttyoutput(c&0177, tp); 14297502Sroot } 14307502Sroot 14317502Sroot /* 14327502Sroot * Is c a break char for tp? 14337502Sroot */ 14347502Sroot ttbreakc(c, tp) 14357625Ssam register c; 14367625Ssam register struct tty *tp; 14377502Sroot { 14389578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14397502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14407502Sroot } 14417502Sroot 14427502Sroot /* 14437502Sroot * send string cp to tp 14447502Sroot */ 14457502Sroot ttyout(cp, tp) 14467625Ssam register char *cp; 14477625Ssam register struct tty *tp; 14487502Sroot { 14497502Sroot register char c; 14507502Sroot 14517502Sroot while (c = *cp++) 14527502Sroot (void) ttyoutput(c, tp); 14537502Sroot } 14547502Sroot 14557502Sroot ttwakeup(tp) 14567502Sroot struct tty *tp; 14577502Sroot { 14587502Sroot 14597502Sroot if (tp->t_rsel) { 14607502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 14617502Sroot tp->t_state &= ~TS_RCOLL; 14627502Sroot tp->t_rsel = 0; 14637502Sroot } 14647502Sroot wakeup((caddr_t)&tp->t_rawq); 14657502Sroot } 14667502Sroot 14679578Ssam #ifndef vax 14689578Ssam scanc(size, cp, table, mask) 14699578Ssam register int size; 14709578Ssam register char *cp, table[]; 14719578Ssam register int mask; 14727502Sroot { 14739578Ssam register int i = 0; 14747502Sroot 14759578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 14769578Ssam i++; 14779578Ssam return (i); 14787502Sroot } 14799578Ssam #endif 1480