1*9859Ssam /* tty.c 4.38 82/12/19 */ 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 */ 115903Sbill wflushtty(tp) 1165408Swnj register struct tty *tp; 11739Sbill { 118*9859Ssam int s; 11939Sbill 120*9859Ssam s = spl5(); 1215622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1225622Swnj && tp->t_oproc) { /* kludge for pty */ 123903Sbill (*tp->t_oproc)(tp); 1245408Swnj tp->t_state |= TS_ASLEEP; 125903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 126903Sbill } 1275426Swnj flushtty(tp, FREAD); 128*9859Ssam splx(s); 12939Sbill } 13039Sbill 13139Sbill /* 1329578Ssam * Flush all TTY queues 13339Sbill */ 134903Sbill flushtty(tp, rw) 1357625Ssam register struct tty *tp; 13639Sbill { 137903Sbill register s; 138903Sbill 139903Sbill s = spl6(); 140903Sbill if (rw & FREAD) { 141903Sbill while (getc(&tp->t_canq) >= 0) 142903Sbill ; 143903Sbill wakeup((caddr_t)&tp->t_rawq); 144903Sbill } 145903Sbill if (rw & FWRITE) { 146903Sbill wakeup((caddr_t)&tp->t_outq); 1475408Swnj tp->t_state &= ~TS_TTSTOP; 1485426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 149903Sbill while (getc(&tp->t_outq) >= 0) 150903Sbill ; 151903Sbill } 152903Sbill if (rw & FREAD) { 153903Sbill while (getc(&tp->t_rawq) >= 0) 154903Sbill ; 155903Sbill tp->t_delct = 0; 1569578Ssam tp->t_rocount = 0; 157903Sbill tp->t_rocol = 0; 1589578Ssam tp->t_state &= ~TS_LOCAL; 159903Sbill } 160903Sbill splx(s); 16139Sbill } 16239Sbill 163903Sbill /* 164903Sbill * Send stop character on input overflow. 165903Sbill */ 166903Sbill ttyblock(tp) 1677625Ssam register struct tty *tp; 16839Sbill { 169903Sbill register x; 1709578Ssam 171903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 172903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 173903Sbill flushtty(tp, FREAD|FWRITE); 1745408Swnj tp->t_state &= ~TS_TBLOCK; 175903Sbill } 1769578Ssam if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) { 1779578Ssam tp->t_state |= TS_TBLOCK; 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; 951*9859Ssam int s, 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 */ 959*9859Ssam s = spl5(); 9609578Ssam if (tp->t_flags&PENDIN) 9617502Sroot ttypend(tp); 962*9859Ssam splx(s); 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) { 986*9859Ssam s = spl5(); 9877502Sroot if (tp->t_rawq.c_cc <= 0) { 9889578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 9897502Sroot (tp->t_state&TS_NBIO)) { 990*9859Ssam splx(s); 9919578Ssam return (0); 9927502Sroot } 9937502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 994*9859Ssam splx(s); 9957502Sroot goto loop; 9967502Sroot } 997*9859Ssam splx(s); 998*9859Ssam while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt) 9998520Sroot error = passuc(getc(&tp->t_rawq), uio); 1000*9859Ssam goto checktandem; 10019578Ssam } 10029578Ssam 10039578Ssam /* 10049578Ssam * In cbreak mode use the rawq, otherwise 10059578Ssam * take characters from the canonicalized q. 10069578Ssam */ 10079578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10089578Ssam 10099578Ssam /* 10109578Ssam * No input, sleep on rawq awaiting hardware 10119578Ssam * receipt and notification. 10129578Ssam */ 1013*9859Ssam s = spl5(); 10149578Ssam if (qp->c_cc <= 0) { 10159578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10169578Ssam (tp->t_state&TS_NBIO)) { 1017*9859Ssam splx(s); 10189578Ssam return (EWOULDBLOCK); 10197502Sroot } 10209578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 1021*9859Ssam splx(s); 10229578Ssam goto loop; 10239578Ssam } 1024*9859Ssam splx(s); 10259578Ssam 10269578Ssam /* 10279578Ssam * Input present, perform input mapping 10289578Ssam * and processing (we're not in raw mode). 10299578Ssam */ 10309578Ssam first = 1; 10319578Ssam while ((c = getc(qp)) >= 0) { 10329578Ssam if (t_flags&CRMOD && c == '\r') 10339578Ssam c = '\n'; 10349578Ssam /* 10359578Ssam * Hack lower case simulation on 10369578Ssam * upper case only terminals. 10379578Ssam */ 10389578Ssam if (t_flags&LCASE && c <= 0177) 10399578Ssam if (tp->t_state&TS_BKSL) { 10409578Ssam if (maptab[c]) 10419578Ssam c = maptab[c]; 10429578Ssam tp->t_state &= ~TS_BKSL; 10439578Ssam } else if (c >= 'A' && c <= 'Z') 10449578Ssam c += 'a' - 'A'; 10459578Ssam else if (c == '\\') { 10469578Ssam tp->t_state |= TS_BKSL; 10479578Ssam continue; 10487502Sroot } 10499578Ssam /* 10509578Ssam * Check for delayed suspend character. 10519578Ssam */ 10529578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 10539578Ssam gsignal(tp->t_pgrp, SIGTSTP); 10549578Ssam if (first) { 10559578Ssam sleep((caddr_t)&lbolt, TTIPRI); 10569578Ssam goto loop; 10579578Ssam } 10589578Ssam break; 10597502Sroot } 10609578Ssam /* 10619578Ssam * Interpret EOF only in cooked mode. 10629578Ssam */ 10639578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 10649578Ssam break; 10659578Ssam /* 10669578Ssam * Give user character. 10679578Ssam */ 10689578Ssam error = passuc(c & 0177, uio); 10699578Ssam if (error) 10709578Ssam break; 10719578Ssam if (uio->uio_iovcnt == 0) 10729578Ssam break; 10739578Ssam /* 10749578Ssam * In cooked mode check for a "break character" 10759578Ssam * marking the end of a "line of input". 10769578Ssam */ 10779578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 10789578Ssam break; 10799578Ssam first = 0; 10807502Sroot } 10819578Ssam tp->t_state &= ~TS_BKSL; 10829578Ssam 1083*9859Ssam checktandem: 10849578Ssam /* 10859578Ssam * Look to unblock output now that (presumably) 10869578Ssam * the input queue has gone down. 10879578Ssam */ 1088*9859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 10899578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 10907502Sroot tp->t_state &= ~TS_TBLOCK; 10917502Sroot ttstart(tp); 10927502Sroot } 10938520Sroot return (error); 10947502Sroot } 10957502Sroot 10967502Sroot /* 10977502Sroot * Called from the device's write routine after it has 10987502Sroot * calculated the tty-structure given as argument. 10997502Sroot */ 11007822Sroot ttwrite(tp, uio) 11017625Ssam register struct tty *tp; 11029578Ssam register struct uio *uio; 11037502Sroot { 11047502Sroot register char *cp; 11059578Ssam register int cc, ce, c; 11069578Ssam int i, hiwat, cnt, error, s; 11077502Sroot char obuf[OBUFSIZ]; 11087502Sroot 11099578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11108520Sroot return (EIO); 11119578Ssam hiwat = TTHIWAT(tp); 11129578Ssam cnt = uio->uio_resid; 11139578Ssam error = 0; 11147502Sroot loop: 11159578Ssam /* 11169578Ssam * Hang the process if it's in the background. 11179578Ssam */ 11187502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11199578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11207502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11217502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11227502Sroot /* 11237502Sroot && 11247502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11257502Sroot */ 11267502Sroot ) { 11277502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11287502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11297502Sroot } 11309578Ssam 11319578Ssam /* 11329578Ssam * Process the user's data in at most OBUFSIZ 11339578Ssam * chunks. Perform lower case simulation and 11349578Ssam * similar hacks. Keep track of high water 11359578Ssam * mark, sleep on overflow awaiting device aid 11369578Ssam * in acquiring new space. 11379578Ssam */ 11387822Sroot while (uio->uio_resid > 0) { 11399578Ssam /* 11409578Ssam * Grab a hunk of data from the user. 11419578Ssam */ 11427822Sroot cc = uio->uio_iov->iov_len; 11437822Sroot if (cc == 0) { 11447822Sroot uio->uio_iovcnt--; 11457822Sroot uio->uio_iov++; 11467822Sroot if (uio->uio_iovcnt < 0) 11477822Sroot panic("ttwrite"); 11487822Sroot continue; 11497822Sroot } 11507822Sroot if (cc > OBUFSIZ) 11517822Sroot cc = OBUFSIZ; 11527502Sroot cp = obuf; 11539578Ssam error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio); 11548520Sroot if (error) 11557502Sroot break; 11567502Sroot if (tp->t_outq.c_cc > hiwat) 11577502Sroot goto ovhiwat; 11589578Ssam if (tp->t_flags&FLUSHO) 11597502Sroot continue; 11609578Ssam /* 11619578Ssam * If we're mapping lower case or kludging tildes, 11629578Ssam * then we've got to look at each character, so 11639578Ssam * just feed the stuff to ttyoutput... 11649578Ssam */ 11659578Ssam if (tp->t_flags & (LCASE|TILDE)) { 11669578Ssam while (cc > 0) { 11677502Sroot c = *cp++; 11687502Sroot tp->t_rocount = 0; 11697625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 11707502Sroot /* out of clists, wait a bit */ 11717502Sroot ttstart(tp); 11727502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11737502Sroot tp->t_rocount = 0; 11747502Sroot } 11757502Sroot --cc; 11767502Sroot if (tp->t_outq.c_cc > hiwat) 11777502Sroot goto ovhiwat; 11787502Sroot } 11797502Sroot continue; 11807502Sroot } 11819578Ssam /* 11829578Ssam * If nothing fancy need be done, grab those characters we 11839578Ssam * can handle without any of ttyoutput's processing and 11849578Ssam * just transfer them to the output q. For those chars 11859578Ssam * which require special processing (as indicated by the 11869578Ssam * bits in partab), call ttyoutput. After processing 11879578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 11889578Ssam * immediately. 11899578Ssam */ 11909578Ssam while (cc > 0) { 11919578Ssam if (tp->t_flags & (RAW|LITOUT)) 11927502Sroot ce = cc; 11937502Sroot else { 11949578Ssam ce = cc - scanc(cc, cp, partab, 077); 11959578Ssam /* 11969578Ssam * If ce is zero, then we're processing 11979578Ssam * a special character through ttyoutput. 11989578Ssam */ 11999578Ssam if (ce == 0) { 12007502Sroot tp->t_rocount = 0; 12017502Sroot if (ttyoutput(*cp, tp) >= 0) { 12029578Ssam /* no c-lists, wait a bit */ 12037502Sroot ttstart(tp); 12047502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12057502Sroot continue; 12067502Sroot } 12079578Ssam cp++, cc--; 12089578Ssam if (tp->t_flags&FLUSHO || 12099578Ssam tp->t_outq.c_cc > hiwat) 12107502Sroot goto ovhiwat; 12119578Ssam continue; 12127502Sroot } 12137502Sroot } 12149578Ssam /* 12159578Ssam * A bunch of normal characters have been found, 12169578Ssam * transfer them en masse to the output queue and 12179578Ssam * continue processing at the top of the loop. 12189578Ssam * If there are any further characters in this 12199578Ssam * <= OBUFSIZ chunk, the first should be a character 12209578Ssam * requiring special handling by ttyoutput. 12219578Ssam */ 12227502Sroot tp->t_rocount = 0; 12239578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12249578Ssam ce -= i; 12259578Ssam tp->t_col += ce; 12269578Ssam cp += ce, cc -= ce, tk_nout += ce; 12279578Ssam if (i > 0) { 12289578Ssam /* out of c-lists, wait a bit */ 12297502Sroot ttstart(tp); 12307502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12317502Sroot } 12329578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12337502Sroot goto ovhiwat; 12347502Sroot } 12357502Sroot } 12367502Sroot ttstart(tp); 12378520Sroot return (error); 12387502Sroot 12397502Sroot ovhiwat: 12409578Ssam s = spl5(); 12419578Ssam if (cc != 0) { 12429578Ssam uio->uio_iov->iov_base -= cc; 12439578Ssam uio->uio_iov->iov_len += cc; 12449578Ssam uio->uio_resid += cc; 12459578Ssam uio->uio_offset -= cc; 12469578Ssam } 12479578Ssam /* 12489578Ssam * This can only occur if FLUSHO 12499578Ssam * is also set in t_flags. 12509578Ssam */ 12517502Sroot if (tp->t_outq.c_cc <= hiwat) { 12529578Ssam splx(s); 12537502Sroot goto loop; 12547502Sroot } 12557502Sroot ttstart(tp); 12569578Ssam if (tp->t_state&TS_NBIO) { 12577822Sroot if (uio->uio_resid == cnt) 12588520Sroot return (EWOULDBLOCK); 12598520Sroot return (0); 12607502Sroot } 12617502Sroot tp->t_state |= TS_ASLEEP; 12627502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 12639578Ssam splx(s); 12647502Sroot goto loop; 12657502Sroot } 12667502Sroot 12677502Sroot /* 12687502Sroot * Rubout one character from the rawq of tp 12697502Sroot * as cleanly as possible. 12707502Sroot */ 12717502Sroot ttyrub(c, tp) 12727625Ssam register c; 12737625Ssam register struct tty *tp; 12747502Sroot { 12757502Sroot register char *cp; 12767502Sroot register int savecol; 12777502Sroot int s; 12787502Sroot char *nextc(); 12797502Sroot 12809578Ssam if ((tp->t_flags&ECHO) == 0) 12817502Sroot return; 12829578Ssam tp->t_flags &= ~FLUSHO; 12837502Sroot c &= 0377; 12849578Ssam if (tp->t_flags&CRTBS) { 12857502Sroot if (tp->t_rocount == 0) { 12867502Sroot /* 12877502Sroot * Screwed by ttwrite; retype 12887502Sroot */ 12897502Sroot ttyretype(tp); 12907502Sroot return; 12917502Sroot } 12929578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 12937502Sroot ttyrubo(tp, 2); 12949578Ssam else switch (partab[c&=0177]&0177) { 12957502Sroot 12967502Sroot case ORDINARY: 12977502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 12987502Sroot ttyrubo(tp, 2); 12997502Sroot else 13007502Sroot ttyrubo(tp, 1); 13017502Sroot break; 13027502Sroot 13037502Sroot case VTAB: 13047502Sroot case BACKSPACE: 13057502Sroot case CONTROL: 13067502Sroot case RETURN: 13079578Ssam if (tp->t_flags&CTLECH) 13087502Sroot ttyrubo(tp, 2); 13097502Sroot break; 13107502Sroot 13117502Sroot case TAB: 13127502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13137502Sroot ttyretype(tp); 13147502Sroot return; 13157502Sroot } 13167502Sroot s = spl5(); 13177502Sroot savecol = tp->t_col; 13189578Ssam tp->t_state |= TS_CNTTB; 13199578Ssam tp->t_flags |= FLUSHO; 13207502Sroot tp->t_col = tp->t_rocol; 13219578Ssam cp = tp->t_rawq.c_cf; 13229578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13237502Sroot ttyecho(*cp, tp); 13249578Ssam tp->t_flags &= ~FLUSHO; 13259578Ssam tp->t_state &= ~TS_CNTTB; 13267502Sroot splx(s); 13277502Sroot /* 13287502Sroot * savecol will now be length of the tab 13297502Sroot */ 13307502Sroot savecol -= tp->t_col; 13317502Sroot tp->t_col += savecol; 13327502Sroot if (savecol > 8) 13337502Sroot savecol = 8; /* overflow screw */ 13347502Sroot while (--savecol >= 0) 13357502Sroot (void) ttyoutput('\b', tp); 13367502Sroot break; 13377502Sroot 13387502Sroot default: 13397502Sroot panic("ttyrub"); 13407502Sroot } 13419578Ssam } else if (tp->t_flags&PRTERA) { 13429578Ssam if ((tp->t_state&TS_ERASE) == 0) { 13437502Sroot (void) ttyoutput('\\', tp); 13449578Ssam tp->t_state |= TS_ERASE; 13457502Sroot } 13467502Sroot ttyecho(c, tp); 13477502Sroot } else 13487502Sroot ttyecho(tp->t_erase, tp); 13497502Sroot tp->t_rocount--; 13507502Sroot } 13517502Sroot 13527502Sroot /* 13537502Sroot * Crt back over cnt chars perhaps 13547502Sroot * erasing them. 13557502Sroot */ 13567502Sroot ttyrubo(tp, cnt) 13577625Ssam register struct tty *tp; 13587625Ssam int cnt; 13597502Sroot { 13609578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 13617502Sroot 13627502Sroot while (--cnt >= 0) 13639578Ssam ttyout(rubostring, tp); 13647502Sroot } 13657502Sroot 13667502Sroot /* 13677502Sroot * Reprint the rawq line. 13687502Sroot * We assume c_cc has already been checked. 13697502Sroot */ 13707502Sroot ttyretype(tp) 13717625Ssam register struct tty *tp; 13727502Sroot { 13737502Sroot register char *cp; 13747502Sroot char *nextc(); 13757502Sroot int s; 13767502Sroot 13779578Ssam if (tp->t_rprntc != 0377) 13789578Ssam ttyecho(tp->t_rprntc, tp); 13797502Sroot (void) ttyoutput('\n', tp); 13807502Sroot s = spl5(); 13817502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 13827502Sroot ttyecho(*cp, tp); 13837502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 13847502Sroot ttyecho(*cp, tp); 13859578Ssam tp->t_state &= ~TS_ERASE; 13867502Sroot splx(s); 13877502Sroot tp->t_rocount = tp->t_rawq.c_cc; 13887502Sroot tp->t_rocol = 0; 13897502Sroot } 13907502Sroot 13917502Sroot /* 13927502Sroot * Echo a typed character to the terminal 13937502Sroot */ 13947502Sroot ttyecho(c, tp) 13957625Ssam register c; 13967625Ssam register struct tty *tp; 13977502Sroot { 13987502Sroot 13999578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14009578Ssam tp->t_flags &= ~FLUSHO; 14017502Sroot if ((tp->t_flags&ECHO) == 0) 14027502Sroot return; 14037502Sroot c &= 0377; 14047502Sroot if (tp->t_flags&RAW) { 14057502Sroot (void) ttyoutput(c, tp); 14067502Sroot return; 14077502Sroot } 14087502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14097502Sroot c = '\n'; 14109578Ssam if (tp->t_flags&CTLECH) { 14117502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14127502Sroot (void) ttyoutput('^', tp); 14137502Sroot c &= 0177; 14147502Sroot if (c == 0177) 14157502Sroot c = '?'; 14167502Sroot else if (tp->t_flags&LCASE) 14177502Sroot c += 'a' - 1; 14187502Sroot else 14197502Sroot c += 'A' - 1; 14207502Sroot } 14217502Sroot } 14227502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14237502Sroot c += 'a' - 'A'; 14249578Ssam (void) ttyoutput(c&0177, tp); 14257502Sroot } 14267502Sroot 14277502Sroot /* 14287502Sroot * Is c a break char for tp? 14297502Sroot */ 14307502Sroot ttbreakc(c, tp) 14317625Ssam register c; 14327625Ssam register struct tty *tp; 14337502Sroot { 14349578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14357502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14367502Sroot } 14377502Sroot 14387502Sroot /* 14397502Sroot * send string cp to tp 14407502Sroot */ 14417502Sroot ttyout(cp, tp) 14427625Ssam register char *cp; 14437625Ssam register struct tty *tp; 14447502Sroot { 14457502Sroot register char c; 14467502Sroot 14477502Sroot while (c = *cp++) 14487502Sroot (void) ttyoutput(c, tp); 14497502Sroot } 14507502Sroot 14517502Sroot ttwakeup(tp) 14527502Sroot struct tty *tp; 14537502Sroot { 14547502Sroot 14557502Sroot if (tp->t_rsel) { 14567502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 14577502Sroot tp->t_state &= ~TS_RCOLL; 14587502Sroot tp->t_rsel = 0; 14597502Sroot } 14607502Sroot wakeup((caddr_t)&tp->t_rawq); 14617502Sroot } 14627502Sroot 14639578Ssam #ifndef vax 14649578Ssam scanc(size, cp, table, mask) 14659578Ssam register int size; 14669578Ssam register char *cp, table[]; 14679578Ssam register int mask; 14687502Sroot { 14699578Ssam register int i = 0; 14707502Sroot 14719578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 14729578Ssam i++; 14739578Ssam return (i); 14747502Sroot } 14759578Ssam #endif 1476