1*10851Ssam /* tty.c 4.40 83/02/10 */ 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 { 1189859Ssam int s; 11939Sbill 1209859Ssam 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); 1289859Ssam 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 275*10851Ssam if (t >= nldisp) 276*10851Ssam return (ENXIO); 2778556Sroot s = spl5(); 27839Sbill if (tp->t_line) 27939Sbill (*linesw[tp->t_line].l_close)(tp); 28039Sbill if (t) 2818556Sroot error = (*linesw[t].l_open)(dev, tp); 2828556Sroot splx(s); 283*10851Ssam if (error) { 284*10851Ssam s = spl5(); 285*10851Ssam if (tp->t_line) 286*10851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 287*10851Ssam splx(s); 2888556Sroot return (error); 289*10851Ssam } 2908556Sroot tp->t_line = t; 29139Sbill break; 2927625Ssam } 29339Sbill 2948556Sroot /* prevent more opens on channel */ 2955614Swnj case TIOCEXCL: 2965614Swnj tp->t_state |= TS_XCLUDE; 2975614Swnj break; 2985614Swnj 2995614Swnj case TIOCNXCL: 3005614Swnj tp->t_state &= ~TS_XCLUDE; 3015614Swnj break; 3025614Swnj 3039624Ssam case TIOCSET: 3049624Ssam case TIOCBIS: { 3059624Ssam u_long newflags = *(u_long *)data; 3067625Ssam 3079624Ssam s = spl5(); 3089624Ssam if (tp->t_flags&RAW || newflags&RAW) 3094484Swnj wflushtty(tp); 3109624Ssam else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) 3119624Ssam if (newflags&CBREAK) { 3129624Ssam struct clist tq; 3139624Ssam 3144484Swnj catq(&tp->t_rawq, &tp->t_canq); 3154484Swnj tq = tp->t_rawq; 3164484Swnj tp->t_rawq = tp->t_canq; 3174484Swnj tp->t_canq = tq; 3184484Swnj } else { 3199578Ssam tp->t_flags |= PENDIN; 3204484Swnj ttwakeup(tp); 321174Sbill } 3229624Ssam if (com == TIOCSET) 3239624Ssam tp->t_flags = newflags; 3249624Ssam else 3259624Ssam tp->t_flags |= newflags; 3269578Ssam if (tp->t_flags&RAW) { 3275408Swnj tp->t_state &= ~TS_TTSTOP; 3283941Sbugs ttstart(tp); 3293941Sbugs } 3309624Ssam splx(s); 33139Sbill break; 3327625Ssam } 33339Sbill 3349624Ssam case TIOCBIC: { 3359624Ssam u_long newflags = *(long *)data; 3367625Ssam 3379624Ssam if (tp->t_flags&RAW) 3389624Ssam wflushtty(tp); 3399624Ssam else if ((tp->t_flags&CBREAK) != (CBREAK&~newflags)) 3409624Ssam if (newflags&CBREAK) { 3419624Ssam tp->t_flags |= PENDIN; 3429624Ssam ttwakeup(tp); 3439624Ssam } else { 3449624Ssam struct clist tq; 3459624Ssam 3469624Ssam catq(&tp->t_rawq, &tp->t_canq); 3479624Ssam tq = tp->t_rawq; 3489624Ssam tp->t_rawq = tp->t_canq; 3499624Ssam tp->t_canq = tq; 3509624Ssam } 3519624Ssam if (tp->t_flags&RAW) { 3529624Ssam tp->t_state &= ~TS_TTSTOP; 3539624Ssam ttstart(tp); 3549624Ssam } 3559624Ssam splx(s); 35639Sbill break; 3577625Ssam } 35839Sbill 3599624Ssam case TIOCGET: 3609624Ssam *(long *)data = tp->t_flags; 3619624Ssam break; 3629624Ssam 3639624Ssam case TIOCCGET: 3649624Ssam bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars)); 3659624Ssam break; 3669624Ssam 3679624Ssam case TIOCCSET: 3689624Ssam bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars)); 3699624Ssam break; 3709624Ssam 3718556Sroot /* hang up line on last close */ 37239Sbill case TIOCHPCL: 3735408Swnj tp->t_state |= TS_HUPCLS; 37439Sbill break; 37539Sbill 3763942Sbugs case TIOCFLUSH: { 3777625Ssam register int flags = *(int *)data; 3787625Ssam 3797625Ssam if (flags == 0) 3803942Sbugs flags = FREAD|FWRITE; 3817625Ssam else 3827625Ssam flags &= FREAD|FWRITE; 3833942Sbugs flushtty(tp, flags); 38439Sbill break; 3853944Sbugs } 38639Sbill 3878556Sroot /* return number of characters immediately available */ 3887625Ssam case FIONREAD: 3897625Ssam *(off_t *)data = ttnread(tp); 390174Sbill break; 391174Sbill 3928589Sroot case TIOCSTOP: 3938589Sroot s = spl5(); 3949578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3955573Swnj tp->t_state |= TS_TTSTOP; 3965573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3975573Swnj } 3987625Ssam splx(s); 3995573Swnj break; 4005573Swnj 4018589Sroot case TIOCSTART: 4028589Sroot s = spl5(); 4039578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 4045573Swnj tp->t_state &= ~TS_TTSTOP; 4059578Ssam tp->t_flags &= ~FLUSHO; 4065573Swnj ttstart(tp); 4075573Swnj } 4087625Ssam splx(s); 4095573Swnj break; 4105573Swnj 4119325Ssam /* 4129325Ssam * Simulate typing of a character at the terminal. 4139325Ssam */ 4149325Ssam case TIOCSTI: 4159325Ssam if (u.u_uid && u.u_ttyp != tp) 4169325Ssam return (EACCES); 4179578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4189325Ssam break; 4199325Ssam 42039Sbill default: 4219624Ssam #ifndef NOCOMPAT 4229624Ssam return (ottioctl(tp, com, data, flag)); 4239624Ssam #else 4248556Sroot return (-1); 4259624Ssam #endif 42639Sbill } 4278556Sroot return (0); 42839Sbill } 4294484Swnj 4304484Swnj ttnread(tp) 4314484Swnj struct tty *tp; 4324484Swnj { 4334484Swnj int nread = 0; 4344484Swnj 4359578Ssam if (tp->t_flags & PENDIN) 4364484Swnj ttypend(tp); 4374484Swnj nread = tp->t_canq.c_cc; 4384484Swnj if (tp->t_flags & (RAW|CBREAK)) 4394484Swnj nread += tp->t_rawq.c_cc; 4404484Swnj return (nread); 4414484Swnj } 4424484Swnj 4435408Swnj ttselect(dev, rw) 4444484Swnj dev_t dev; 4455408Swnj int rw; 4464484Swnj { 4474484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4484484Swnj int nread; 4495408Swnj int s = spl5(); 4504484Swnj 4515408Swnj switch (rw) { 4524484Swnj 4534484Swnj case FREAD: 4544484Swnj nread = ttnread(tp); 4554484Swnj if (nread > 0) 4565408Swnj goto win; 4574938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 4585408Swnj tp->t_state |= TS_RCOLL; 4594484Swnj else 4604484Swnj tp->t_rsel = u.u_procp; 4615408Swnj break; 4624484Swnj 4635408Swnj case FWRITE: 4645408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 4655408Swnj goto win; 4665408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 4675408Swnj tp->t_state |= TS_WCOLL; 4685408Swnj else 4695408Swnj tp->t_wsel = u.u_procp; 4705408Swnj break; 4714484Swnj } 4725408Swnj splx(s); 4735408Swnj return (0); 4745408Swnj win: 4755408Swnj splx(s); 4765408Swnj return (1); 4774484Swnj } 4787436Skre 4797502Sroot /* 4809578Ssam * Establish a process group for distribution of 4817502Sroot * quits and interrupts from the tty. 4827502Sroot */ 4837502Sroot ttyopen(dev, tp) 4847625Ssam dev_t dev; 4857625Ssam register struct tty *tp; 4867502Sroot { 4877502Sroot register struct proc *pp; 4887502Sroot 4897502Sroot pp = u.u_procp; 4907502Sroot tp->t_dev = dev; 4917625Ssam if (pp->p_pgrp == 0) { 4927502Sroot u.u_ttyp = tp; 4937502Sroot u.u_ttyd = dev; 4947502Sroot if (tp->t_pgrp == 0) 4957502Sroot tp->t_pgrp = pp->p_pid; 4967502Sroot pp->p_pgrp = tp->t_pgrp; 4977502Sroot } 4987502Sroot tp->t_state &= ~TS_WOPEN; 4997502Sroot tp->t_state |= TS_ISOPEN; 5007502Sroot if (tp->t_line != NTTYDISC) 5017502Sroot wflushtty(tp); 5028556Sroot return (0); 5037502Sroot } 5047502Sroot 5057502Sroot /* 5067502Sroot * clean tp on last close 5077502Sroot */ 5087502Sroot ttyclose(tp) 5097625Ssam register struct tty *tp; 5107502Sroot { 5117502Sroot 5127502Sroot if (tp->t_line) { 5137502Sroot wflushtty(tp); 5147502Sroot tp->t_line = 0; 5157502Sroot return; 5167502Sroot } 5177502Sroot tp->t_pgrp = 0; 5187502Sroot wflushtty(tp); 5197502Sroot tp->t_state = 0; 5207502Sroot } 5217502Sroot 5227502Sroot /* 5237502Sroot * reinput pending characters after state switch 5247502Sroot * call at spl5(). 5257502Sroot */ 5267502Sroot ttypend(tp) 5277625Ssam register struct tty *tp; 5287502Sroot { 5297502Sroot struct clist tq; 5307502Sroot register c; 5317502Sroot 5329578Ssam tp->t_flags &= ~PENDIN; 5339578Ssam tp->t_state |= TS_TYPEN; 5347502Sroot tq = tp->t_rawq; 5357502Sroot tp->t_rawq.c_cc = 0; 5367502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5377502Sroot while ((c = getc(&tq)) >= 0) 5387502Sroot ttyinput(c, tp); 5399578Ssam tp->t_state &= ~TS_TYPEN; 5407502Sroot } 5417502Sroot 5427502Sroot /* 5439578Ssam * Place a character on raw TTY input queue, 5449578Ssam * putting in delimiters and waking up top 5459578Ssam * half as needed. Also echo if required. 5469578Ssam * The arguments are the character and the 5479578Ssam * appropriate tty structure. 5487502Sroot */ 5497502Sroot ttyinput(c, tp) 5507625Ssam register c; 5517625Ssam register struct tty *tp; 5527502Sroot { 5539578Ssam register int t_flags = tp->t_flags; 5547502Sroot int i; 5557502Sroot 5569578Ssam /* 5579578Ssam * If input is pending take it first. 5589578Ssam */ 5599578Ssam if (t_flags&PENDIN) 5607502Sroot ttypend(tp); 5617502Sroot tk_nin++; 5627502Sroot c &= 0377; 5639578Ssam 5649578Ssam /* 5659578Ssam * In tandem mode, check high water mark. 5669578Ssam */ 5677502Sroot if (t_flags&TANDEM) 5687502Sroot ttyblock(tp); 5699578Ssam 5709578Ssam if (t_flags&RAW) { 5719578Ssam /* 5729578Ssam * Raw mode, just put character 5739578Ssam * in input q w/o interpretation. 5749578Ssam */ 5759578Ssam if (tp->t_rawq.c_cc > TTYHOG) 5769578Ssam flushtty(tp, FREAD|FWRITE); 5779578Ssam else { 5789578Ssam if (putc(c, &tp->t_rawq) >= 0) 5799578Ssam ttwakeup(tp); 5809578Ssam ttyecho(c, tp); 5817502Sroot } 5829578Ssam goto endcase; 5839578Ssam } 5849578Ssam 5859578Ssam /* 5869578Ssam * Ignore any high bit added during 5879578Ssam * previous ttyinput processing. 5889578Ssam */ 5899578Ssam if ((tp->t_state&TS_TYPEN) == 0) 5909578Ssam c &= 0177; 5919578Ssam /* 5929578Ssam * Check for literal nexting very first 5939578Ssam */ 5949578Ssam if (tp->t_state&TS_LNCH) { 5959578Ssam c |= 0200; 5969578Ssam tp->t_state &= ~TS_LNCH; 5979578Ssam } 5989578Ssam 5999578Ssam /* 6009578Ssam * Scan for special characters. This code 6019578Ssam * is really just a big case statement with 6029578Ssam * non-constant cases. The bottom of the 6039578Ssam * case statement is labeled ``endcase'', so goto 6049578Ssam * it after a case match, or similar. 6059578Ssam */ 6069578Ssam if (tp->t_line == NTTYDISC) { 6079578Ssam if (c == tp->t_lnextc) { 6087502Sroot if (tp->t_flags&ECHO) 6097502Sroot ttyout("^\b", tp); 6109578Ssam tp->t_state |= TS_LNCH; 6119578Ssam goto endcase; 6129578Ssam } 6139578Ssam if (c == tp->t_flushc) { 6149578Ssam if (tp->t_flags&FLUSHO) 6159578Ssam tp->t_flags &= ~FLUSHO; 6167502Sroot else { 6177502Sroot flushtty(tp, FWRITE); 6187502Sroot ttyecho(c, tp); 6199578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6207502Sroot ttyretype(tp); 6219578Ssam tp->t_flags |= FLUSHO; 6227502Sroot } 6239578Ssam goto startoutput; 6249578Ssam } 6259578Ssam if (c == tp->t_suspc) { 6269578Ssam if ((tp->t_flags&NOFLSH) == 0) 6279578Ssam flushtty(tp, FREAD); 6289578Ssam ttyecho(c, tp); 6299578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6309578Ssam goto endcase; 6319578Ssam } 6329578Ssam } 6339578Ssam 6349578Ssam /* 6359578Ssam * Handle start/stop characters. 6369578Ssam */ 6379578Ssam if (c == tp->t_stopc) { 6389578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6399578Ssam tp->t_state |= TS_TTSTOP; 6409578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6417502Sroot return; 6429578Ssam } 6439578Ssam if (c != tp->t_startc) 6449578Ssam return; 6459578Ssam goto endcase; 6469578Ssam } 6479578Ssam if (c == tp->t_startc) 6489578Ssam goto restartoutput; 6499578Ssam 6509578Ssam /* 6519578Ssam * Look for interrupt/quit chars. 6529578Ssam */ 6539578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 6549578Ssam if ((tp->t_flags&NOFLSH) == 0) 6559578Ssam flushtty(tp, FREAD|FWRITE); 6569578Ssam ttyecho(c, tp); 6579578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 6589578Ssam goto endcase; 6599578Ssam } 6609578Ssam 6619578Ssam /* 6629578Ssam * Cbreak mode, don't process line editing 6639578Ssam * characters; check high water mark for wakeup. 6649578Ssam */ 6659578Ssam if (t_flags&CBREAK) { 6669578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 6677502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 6687502Sroot tp->t_line == NTTYDISC) 6697502Sroot (void) ttyoutput(CTRL(g), tp); 6707502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 6717502Sroot ttwakeup(tp); 6727502Sroot ttyecho(c, tp); 6737502Sroot } 6749578Ssam goto endcase; 6759578Ssam } 6769578Ssam 6779578Ssam /* 6789578Ssam * From here on down cooked mode character 6799578Ssam * processing takes place. 6809578Ssam */ 6819578Ssam if ((tp->t_state&TS_QUOT) && 6829578Ssam (c == tp->t_erase || c == tp->t_kill)) { 6839578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6849578Ssam c |= 0200; 6859578Ssam } 6869578Ssam if (c == tp->t_erase) { 6879578Ssam if (tp->t_rawq.c_cc) 6889578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6899578Ssam goto endcase; 6909578Ssam } 6919578Ssam if (c == tp->t_kill) { 6929578Ssam if (tp->t_flags&CRTKIL && 6939578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 6949578Ssam while (tp->t_rawq.c_cc) 6959578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6969578Ssam } else { 6979578Ssam ttyecho(c, tp); 6989578Ssam ttyecho('\n', tp); 6999578Ssam while (getc(&tp->t_rawq) > 0) 7009578Ssam ; 7019578Ssam tp->t_rocount = 0; 7029578Ssam } 7039578Ssam tp->t_state &= ~TS_LOCAL; 7049578Ssam goto endcase; 7059578Ssam } 7069578Ssam 7079578Ssam /* 7089578Ssam * New line discipline, 7099578Ssam * check word erase/reprint line. 7109578Ssam */ 7119578Ssam if (tp->t_line == NTTYDISC) { 7129578Ssam if (c == tp->t_werasc) { 7139578Ssam if (tp->t_rawq.c_cc == 0) 7149578Ssam goto endcase; 7159578Ssam do { 7169578Ssam c = unputc(&tp->t_rawq); 7179578Ssam if (c != ' ' && c != '\t') 7189578Ssam goto erasenb; 7199578Ssam ttyrub(c, tp); 7209578Ssam } while (tp->t_rawq.c_cc); 7219578Ssam goto endcase; 7229578Ssam erasenb: 7239578Ssam do { 7249578Ssam ttyrub(c, tp); 7259578Ssam if (tp->t_rawq.c_cc == 0) 7269578Ssam goto endcase; 7279578Ssam c = unputc(&tp->t_rawq); 7289578Ssam } while (c != ' ' && c != '\t'); 7299578Ssam (void) putc(c, &tp->t_rawq); 7309578Ssam goto endcase; 7319578Ssam } 7329578Ssam if (c == tp->t_rprntc) { 7339578Ssam ttyretype(tp); 7349578Ssam goto endcase; 7359578Ssam } 7369578Ssam } 7379578Ssam 7389578Ssam /* 7399578Ssam * Check for input buffer overflow 7409578Ssam */ 74110391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 74210391Ssam if (tp->t_line == NTTYDISC) 74310391Ssam (void) ttyoutput(CTRL(g), tp); 7449578Ssam goto endcase; 74510391Ssam } 7469578Ssam 7479578Ssam /* 7489578Ssam * Put data char in q for user and 7499578Ssam * wakeup on seeing a line delimiter. 7509578Ssam */ 7519578Ssam if (putc(c, &tp->t_rawq) >= 0) { 7529578Ssam if (ttbreakc(c, tp)) { 7539578Ssam tp->t_rocount = 0; 7549578Ssam catq(&tp->t_rawq, &tp->t_canq); 7557502Sroot ttwakeup(tp); 7569578Ssam } else if (tp->t_rocount++ == 0) 7579578Ssam tp->t_rocol = tp->t_col; 7589578Ssam tp->t_state &= ~TS_QUOT; 7599578Ssam if (c == '\\') 7609578Ssam tp->t_state |= TS_QUOT; 7619578Ssam if (tp->t_state&TS_ERASE) { 7629578Ssam tp->t_state &= ~TS_ERASE; 7639578Ssam (void) ttyoutput('/', tp); 7649578Ssam } 7659578Ssam i = tp->t_col; 7667502Sroot ttyecho(c, tp); 7679578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 7689578Ssam i = MIN(2, tp->t_col - i); 7699578Ssam while (i > 0) { 7709578Ssam (void) ttyoutput('\b', tp); 7719578Ssam i--; 7729578Ssam } 7739578Ssam } 7747502Sroot } 7759578Ssam 7769578Ssam endcase: 7779578Ssam /* 7789578Ssam * If DEC-style start/stop is enabled don't restart 7799578Ssam * output until seeing the start character. 7809578Ssam */ 7819578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 7829578Ssam tp->t_startc != tp->t_stopc) 7837502Sroot return; 7849578Ssam 7859578Ssam restartoutput: 7867502Sroot tp->t_state &= ~TS_TTSTOP; 7879578Ssam tp->t_flags &= ~FLUSHO; 7889578Ssam 7899578Ssam startoutput: 7907502Sroot ttstart(tp); 7917502Sroot } 7927502Sroot 7937502Sroot /* 7949578Ssam * Put character on TTY output queue, adding delays, 7957502Sroot * expanding tabs, and handling the CR/NL bit. 7969578Ssam * This is called both from the top half for output, 7979578Ssam * and from interrupt level for echoing. 7987502Sroot * The arguments are the character and the tty structure. 7997502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8007502Sroot * Must be recursive. 8017502Sroot */ 8027502Sroot ttyoutput(c, tp) 8037502Sroot register c; 8047502Sroot register struct tty *tp; 8057502Sroot { 8067502Sroot register char *colp; 8077502Sroot register ctype; 8087502Sroot 8099578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8109578Ssam if (tp->t_flags&FLUSHO) 8117502Sroot return (-1); 8127502Sroot if (putc(c, &tp->t_outq)) 8137625Ssam return (c); 8147502Sroot tk_nout++; 8157502Sroot return (-1); 8167502Sroot } 8179578Ssam 8187502Sroot /* 8199578Ssam * Ignore EOT in normal mode to avoid 8209578Ssam * hanging up certain terminals. 8217502Sroot */ 8227502Sroot c &= 0177; 8239578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8247502Sroot return (-1); 8257502Sroot /* 8267502Sroot * Turn tabs to spaces as required 8277502Sroot */ 8289578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8297502Sroot register int s; 8307502Sroot 8317502Sroot c = 8 - (tp->t_col&7); 8329578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8337502Sroot s = spl5(); /* don't interrupt tabs */ 8347502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8357502Sroot tk_nout += c; 8367502Sroot splx(s); 8377502Sroot } 8387502Sroot tp->t_col += c; 8397502Sroot return (c ? -1 : '\t'); 8407502Sroot } 8417502Sroot tk_nout++; 8427502Sroot /* 8437502Sroot * for upper-case-only terminals, 8447502Sroot * generate escapes. 8457502Sroot */ 8467502Sroot if (tp->t_flags&LCASE) { 8477502Sroot colp = "({)}!|^~'`"; 8487625Ssam while (*colp++) 8497625Ssam if (c == *colp++) { 8507502Sroot if (ttyoutput('\\', tp) >= 0) 8517502Sroot return (c); 8527502Sroot c = colp[-2]; 8537502Sroot break; 8547502Sroot } 8559578Ssam if ('A' <= c && c <= 'Z') { 8567502Sroot if (ttyoutput('\\', tp) >= 0) 8577502Sroot return (c); 8589578Ssam } else if ('a' <= c && c <= 'z') 8597502Sroot c += 'A' - 'a'; 8607502Sroot } 8619578Ssam 8627502Sroot /* 8637502Sroot * turn <nl> to <cr><lf> if desired. 8647502Sroot */ 8659578Ssam if (c == '\n' && tp->t_flags&CRMOD) 8667502Sroot if (ttyoutput('\r', tp) >= 0) 8677502Sroot return (c); 8689578Ssam if (c == '~' && tp->t_flags&TILDE) 8697502Sroot c = '`'; 8709578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 8717502Sroot return (c); 8727502Sroot /* 8737502Sroot * Calculate delays. 8747502Sroot * The numbers here represent clock ticks 8757502Sroot * and are not necessarily optimal for all terminals. 8767502Sroot * The delays are indicated by characters above 0200. 8777502Sroot * In raw mode there are no delays and the 8787502Sroot * transmission path is 8 bits wide. 8799578Ssam * 8809578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 8817502Sroot */ 8827502Sroot colp = &tp->t_col; 8837502Sroot ctype = partab[c]; 8847502Sroot c = 0; 8857502Sroot switch (ctype&077) { 8867502Sroot 8877502Sroot case ORDINARY: 8887502Sroot (*colp)++; 8897502Sroot 8907502Sroot case CONTROL: 8917502Sroot break; 8927502Sroot 8937502Sroot case BACKSPACE: 8947502Sroot if (*colp) 8957502Sroot (*colp)--; 8967502Sroot break; 8977502Sroot 8987502Sroot case NEWLINE: 8997502Sroot ctype = (tp->t_flags >> 8) & 03; 9007625Ssam if (ctype == 1) { /* tty 37 */ 9017502Sroot if (*colp) 9027502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9039578Ssam } else if (ctype == 2) /* vt05 */ 9047502Sroot c = 6; 9057502Sroot *colp = 0; 9067502Sroot break; 9077502Sroot 9087502Sroot case TAB: 9097502Sroot ctype = (tp->t_flags >> 10) & 03; 9107625Ssam if (ctype == 1) { /* tty 37 */ 9117502Sroot c = 1 - (*colp | ~07); 9127625Ssam if (c < 5) 9137502Sroot c = 0; 9147502Sroot } 9157502Sroot *colp |= 07; 9167502Sroot (*colp)++; 9177502Sroot break; 9187502Sroot 9197502Sroot case VTAB: 9209578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9217502Sroot c = 0177; 9227502Sroot break; 9237502Sroot 9247502Sroot case RETURN: 9257502Sroot ctype = (tp->t_flags >> 12) & 03; 9269578Ssam if (ctype == 1) /* tn 300 */ 9277502Sroot c = 5; 9289578Ssam else if (ctype == 2) /* ti 700 */ 9297502Sroot c = 10; 9309578Ssam else if (ctype == 3) { /* concept 100 */ 9317502Sroot int i; 9329578Ssam 9337502Sroot if ((i = *colp) >= 0) 9349578Ssam for (; i < 9; i++) 9357502Sroot (void) putc(0177, &tp->t_outq); 9367502Sroot } 9377502Sroot *colp = 0; 9387502Sroot } 9399578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9407502Sroot (void) putc(c|0200, &tp->t_outq); 9417502Sroot return (-1); 9427502Sroot } 9437502Sroot 9447502Sroot /* 9457502Sroot * Called from device's read routine after it has 9467502Sroot * calculated the tty-structure given as argument. 9477502Sroot */ 9487722Swnj ttread(tp, uio) 9497625Ssam register struct tty *tp; 9507722Swnj struct uio *uio; 9517502Sroot { 9527502Sroot register struct clist *qp; 9539578Ssam register c, t_flags; 9549859Ssam int s, first, error = 0; 9557502Sroot 9567502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9578520Sroot return (EIO); 9587502Sroot loop: 9599578Ssam /* 9609578Ssam * Take any pending input first. 9619578Ssam */ 9629859Ssam s = spl5(); 9639578Ssam if (tp->t_flags&PENDIN) 9647502Sroot ttypend(tp); 9659859Ssam splx(s); 9669578Ssam 9679578Ssam /* 9689578Ssam * Hang process if it's in the background. 9699578Ssam */ 9707502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9717502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9727502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9737502Sroot /* 9747502Sroot (u.u_procp->p_flag&SDETACH) || 9757502Sroot */ 9767502Sroot u.u_procp->p_flag&SVFORK) 9778520Sroot return (EIO); 9787502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9797502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9807502Sroot } 9819578Ssam t_flags = tp->t_flags; 9829578Ssam 9839578Ssam /* 9849578Ssam * In raw mode take characters directly from the 9859578Ssam * raw queue w/o processing. Interlock against 9869578Ssam * device interrupts when interrogating rawq. 9879578Ssam */ 9889578Ssam if (t_flags&RAW) { 9899859Ssam s = spl5(); 9907502Sroot if (tp->t_rawq.c_cc <= 0) { 9919578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 9927502Sroot (tp->t_state&TS_NBIO)) { 9939859Ssam splx(s); 9949578Ssam return (0); 9957502Sroot } 9967502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9979859Ssam splx(s); 9987502Sroot goto loop; 9997502Sroot } 10009859Ssam splx(s); 10019859Ssam while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt) 10028520Sroot error = passuc(getc(&tp->t_rawq), uio); 10039859Ssam goto checktandem; 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 */ 10169859Ssam s = spl5(); 10179578Ssam if (qp->c_cc <= 0) { 10189578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10199578Ssam (tp->t_state&TS_NBIO)) { 10209859Ssam splx(s); 10219578Ssam return (EWOULDBLOCK); 10227502Sroot } 10239578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10249859Ssam splx(s); 10259578Ssam goto loop; 10269578Ssam } 10279859Ssam splx(s); 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 10869859Ssam checktandem: 10879578Ssam /* 10889578Ssam * Look to unblock output now that (presumably) 10899578Ssam * the input queue has gone down. 10909578Ssam */ 10919859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 10929578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 10937502Sroot tp->t_state &= ~TS_TBLOCK; 10947502Sroot ttstart(tp); 10957502Sroot } 10968520Sroot return (error); 10977502Sroot } 10987502Sroot 10997502Sroot /* 11007502Sroot * Called from the device's write routine after it has 11017502Sroot * calculated the tty-structure given as argument. 11027502Sroot */ 11037822Sroot ttwrite(tp, uio) 11047625Ssam register struct tty *tp; 11059578Ssam register struct uio *uio; 11067502Sroot { 11077502Sroot register char *cp; 11089578Ssam register int cc, ce, c; 11099578Ssam int i, hiwat, cnt, error, s; 11107502Sroot char obuf[OBUFSIZ]; 11117502Sroot 11129578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11138520Sroot return (EIO); 11149578Ssam hiwat = TTHIWAT(tp); 11159578Ssam cnt = uio->uio_resid; 11169578Ssam error = 0; 11177502Sroot loop: 11189578Ssam /* 11199578Ssam * Hang the process if it's in the background. 11209578Ssam */ 11217502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11229578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11237502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11247502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11257502Sroot /* 11267502Sroot && 11277502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11287502Sroot */ 11297502Sroot ) { 11307502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11317502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11327502Sroot } 11339578Ssam 11349578Ssam /* 11359578Ssam * Process the user's data in at most OBUFSIZ 11369578Ssam * chunks. Perform lower case simulation and 11379578Ssam * similar hacks. Keep track of high water 11389578Ssam * mark, sleep on overflow awaiting device aid 11399578Ssam * in acquiring new space. 11409578Ssam */ 11417822Sroot while (uio->uio_resid > 0) { 11429578Ssam /* 11439578Ssam * Grab a hunk of data from the user. 11449578Ssam */ 11457822Sroot cc = uio->uio_iov->iov_len; 11467822Sroot if (cc == 0) { 11477822Sroot uio->uio_iovcnt--; 11487822Sroot uio->uio_iov++; 11497822Sroot if (uio->uio_iovcnt < 0) 11507822Sroot panic("ttwrite"); 11517822Sroot continue; 11527822Sroot } 11537822Sroot if (cc > OBUFSIZ) 11547822Sroot cc = OBUFSIZ; 11557502Sroot cp = obuf; 11569578Ssam error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio); 11578520Sroot if (error) 11587502Sroot break; 11597502Sroot if (tp->t_outq.c_cc > hiwat) 11607502Sroot goto ovhiwat; 11619578Ssam if (tp->t_flags&FLUSHO) 11627502Sroot continue; 11639578Ssam /* 11649578Ssam * If we're mapping lower case or kludging tildes, 11659578Ssam * then we've got to look at each character, so 11669578Ssam * just feed the stuff to ttyoutput... 11679578Ssam */ 11689578Ssam if (tp->t_flags & (LCASE|TILDE)) { 11699578Ssam while (cc > 0) { 11707502Sroot c = *cp++; 11717502Sroot tp->t_rocount = 0; 11727625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 11737502Sroot /* out of clists, wait a bit */ 11747502Sroot ttstart(tp); 11757502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11767502Sroot tp->t_rocount = 0; 11777502Sroot } 11787502Sroot --cc; 11797502Sroot if (tp->t_outq.c_cc > hiwat) 11807502Sroot goto ovhiwat; 11817502Sroot } 11827502Sroot continue; 11837502Sroot } 11849578Ssam /* 11859578Ssam * If nothing fancy need be done, grab those characters we 11869578Ssam * can handle without any of ttyoutput's processing and 11879578Ssam * just transfer them to the output q. For those chars 11889578Ssam * which require special processing (as indicated by the 11899578Ssam * bits in partab), call ttyoutput. After processing 11909578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 11919578Ssam * immediately. 11929578Ssam */ 11939578Ssam while (cc > 0) { 11949578Ssam if (tp->t_flags & (RAW|LITOUT)) 11957502Sroot ce = cc; 11967502Sroot else { 11979578Ssam ce = cc - scanc(cc, cp, partab, 077); 11989578Ssam /* 11999578Ssam * If ce is zero, then we're processing 12009578Ssam * a special character through ttyoutput. 12019578Ssam */ 12029578Ssam if (ce == 0) { 12037502Sroot tp->t_rocount = 0; 12047502Sroot if (ttyoutput(*cp, tp) >= 0) { 12059578Ssam /* no c-lists, wait a bit */ 12067502Sroot ttstart(tp); 12077502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12087502Sroot continue; 12097502Sroot } 12109578Ssam cp++, cc--; 12119578Ssam if (tp->t_flags&FLUSHO || 12129578Ssam tp->t_outq.c_cc > hiwat) 12137502Sroot goto ovhiwat; 12149578Ssam continue; 12157502Sroot } 12167502Sroot } 12179578Ssam /* 12189578Ssam * A bunch of normal characters have been found, 12199578Ssam * transfer them en masse to the output queue and 12209578Ssam * continue processing at the top of the loop. 12219578Ssam * If there are any further characters in this 12229578Ssam * <= OBUFSIZ chunk, the first should be a character 12239578Ssam * requiring special handling by ttyoutput. 12249578Ssam */ 12257502Sroot tp->t_rocount = 0; 12269578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12279578Ssam ce -= i; 12289578Ssam tp->t_col += ce; 12299578Ssam cp += ce, cc -= ce, tk_nout += ce; 12309578Ssam if (i > 0) { 12319578Ssam /* out of c-lists, wait a bit */ 12327502Sroot ttstart(tp); 12337502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12347502Sroot } 12359578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12367502Sroot goto ovhiwat; 12377502Sroot } 12387502Sroot } 12397502Sroot ttstart(tp); 12408520Sroot return (error); 12417502Sroot 12427502Sroot ovhiwat: 12439578Ssam s = spl5(); 12449578Ssam if (cc != 0) { 12459578Ssam uio->uio_iov->iov_base -= cc; 12469578Ssam uio->uio_iov->iov_len += cc; 12479578Ssam uio->uio_resid += cc; 12489578Ssam uio->uio_offset -= cc; 12499578Ssam } 12509578Ssam /* 12519578Ssam * This can only occur if FLUSHO 12529578Ssam * is also set in t_flags. 12539578Ssam */ 12547502Sroot if (tp->t_outq.c_cc <= hiwat) { 12559578Ssam splx(s); 12567502Sroot goto loop; 12577502Sroot } 12587502Sroot ttstart(tp); 12599578Ssam if (tp->t_state&TS_NBIO) { 12607822Sroot if (uio->uio_resid == cnt) 12618520Sroot return (EWOULDBLOCK); 12628520Sroot return (0); 12637502Sroot } 12647502Sroot tp->t_state |= TS_ASLEEP; 12657502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 12669578Ssam splx(s); 12677502Sroot goto loop; 12687502Sroot } 12697502Sroot 12707502Sroot /* 12717502Sroot * Rubout one character from the rawq of tp 12727502Sroot * as cleanly as possible. 12737502Sroot */ 12747502Sroot ttyrub(c, tp) 12757625Ssam register c; 12767625Ssam register struct tty *tp; 12777502Sroot { 12787502Sroot register char *cp; 12797502Sroot register int savecol; 12807502Sroot int s; 12817502Sroot char *nextc(); 12827502Sroot 12839578Ssam if ((tp->t_flags&ECHO) == 0) 12847502Sroot return; 12859578Ssam tp->t_flags &= ~FLUSHO; 12867502Sroot c &= 0377; 12879578Ssam if (tp->t_flags&CRTBS) { 12887502Sroot if (tp->t_rocount == 0) { 12897502Sroot /* 12907502Sroot * Screwed by ttwrite; retype 12917502Sroot */ 12927502Sroot ttyretype(tp); 12937502Sroot return; 12947502Sroot } 12959578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 12967502Sroot ttyrubo(tp, 2); 12979578Ssam else switch (partab[c&=0177]&0177) { 12987502Sroot 12997502Sroot case ORDINARY: 13007502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13017502Sroot ttyrubo(tp, 2); 13027502Sroot else 13037502Sroot ttyrubo(tp, 1); 13047502Sroot break; 13057502Sroot 13067502Sroot case VTAB: 13077502Sroot case BACKSPACE: 13087502Sroot case CONTROL: 13097502Sroot case RETURN: 13109578Ssam if (tp->t_flags&CTLECH) 13117502Sroot ttyrubo(tp, 2); 13127502Sroot break; 13137502Sroot 13147502Sroot case TAB: 13157502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13167502Sroot ttyretype(tp); 13177502Sroot return; 13187502Sroot } 13197502Sroot s = spl5(); 13207502Sroot savecol = tp->t_col; 13219578Ssam tp->t_state |= TS_CNTTB; 13229578Ssam tp->t_flags |= FLUSHO; 13237502Sroot tp->t_col = tp->t_rocol; 13249578Ssam cp = tp->t_rawq.c_cf; 13259578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13267502Sroot ttyecho(*cp, tp); 13279578Ssam tp->t_flags &= ~FLUSHO; 13289578Ssam tp->t_state &= ~TS_CNTTB; 13297502Sroot splx(s); 13307502Sroot /* 13317502Sroot * savecol will now be length of the tab 13327502Sroot */ 13337502Sroot savecol -= tp->t_col; 13347502Sroot tp->t_col += savecol; 13357502Sroot if (savecol > 8) 13367502Sroot savecol = 8; /* overflow screw */ 13377502Sroot while (--savecol >= 0) 13387502Sroot (void) ttyoutput('\b', tp); 13397502Sroot break; 13407502Sroot 13417502Sroot default: 13427502Sroot panic("ttyrub"); 13437502Sroot } 13449578Ssam } else if (tp->t_flags&PRTERA) { 13459578Ssam if ((tp->t_state&TS_ERASE) == 0) { 13467502Sroot (void) ttyoutput('\\', tp); 13479578Ssam tp->t_state |= TS_ERASE; 13487502Sroot } 13497502Sroot ttyecho(c, tp); 13507502Sroot } else 13517502Sroot ttyecho(tp->t_erase, tp); 13527502Sroot tp->t_rocount--; 13537502Sroot } 13547502Sroot 13557502Sroot /* 13567502Sroot * Crt back over cnt chars perhaps 13577502Sroot * erasing them. 13587502Sroot */ 13597502Sroot ttyrubo(tp, cnt) 13607625Ssam register struct tty *tp; 13617625Ssam int cnt; 13627502Sroot { 13639578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 13647502Sroot 13657502Sroot while (--cnt >= 0) 13669578Ssam ttyout(rubostring, tp); 13677502Sroot } 13687502Sroot 13697502Sroot /* 13707502Sroot * Reprint the rawq line. 13717502Sroot * We assume c_cc has already been checked. 13727502Sroot */ 13737502Sroot ttyretype(tp) 13747625Ssam register struct tty *tp; 13757502Sroot { 13767502Sroot register char *cp; 13777502Sroot char *nextc(); 13787502Sroot int s; 13797502Sroot 13809578Ssam if (tp->t_rprntc != 0377) 13819578Ssam ttyecho(tp->t_rprntc, tp); 13827502Sroot (void) ttyoutput('\n', tp); 13837502Sroot s = spl5(); 13847502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 13857502Sroot ttyecho(*cp, tp); 13867502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 13877502Sroot ttyecho(*cp, tp); 13889578Ssam tp->t_state &= ~TS_ERASE; 13897502Sroot splx(s); 13907502Sroot tp->t_rocount = tp->t_rawq.c_cc; 13917502Sroot tp->t_rocol = 0; 13927502Sroot } 13937502Sroot 13947502Sroot /* 13957502Sroot * Echo a typed character to the terminal 13967502Sroot */ 13977502Sroot ttyecho(c, tp) 13987625Ssam register c; 13997625Ssam register struct tty *tp; 14007502Sroot { 14017502Sroot 14029578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14039578Ssam tp->t_flags &= ~FLUSHO; 14047502Sroot if ((tp->t_flags&ECHO) == 0) 14057502Sroot return; 14067502Sroot c &= 0377; 14077502Sroot if (tp->t_flags&RAW) { 14087502Sroot (void) ttyoutput(c, tp); 14097502Sroot return; 14107502Sroot } 14117502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14127502Sroot c = '\n'; 14139578Ssam if (tp->t_flags&CTLECH) { 14147502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14157502Sroot (void) ttyoutput('^', tp); 14167502Sroot c &= 0177; 14177502Sroot if (c == 0177) 14187502Sroot c = '?'; 14197502Sroot else if (tp->t_flags&LCASE) 14207502Sroot c += 'a' - 1; 14217502Sroot else 14227502Sroot c += 'A' - 1; 14237502Sroot } 14247502Sroot } 14257502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14267502Sroot c += 'a' - 'A'; 14279578Ssam (void) ttyoutput(c&0177, tp); 14287502Sroot } 14297502Sroot 14307502Sroot /* 14317502Sroot * Is c a break char for tp? 14327502Sroot */ 14337502Sroot ttbreakc(c, tp) 14347625Ssam register c; 14357625Ssam register struct tty *tp; 14367502Sroot { 14379578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14387502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14397502Sroot } 14407502Sroot 14417502Sroot /* 14427502Sroot * send string cp to tp 14437502Sroot */ 14447502Sroot ttyout(cp, tp) 14457625Ssam register char *cp; 14467625Ssam register struct tty *tp; 14477502Sroot { 14487502Sroot register char c; 14497502Sroot 14507502Sroot while (c = *cp++) 14517502Sroot (void) ttyoutput(c, tp); 14527502Sroot } 14537502Sroot 14547502Sroot ttwakeup(tp) 14557502Sroot struct tty *tp; 14567502Sroot { 14577502Sroot 14587502Sroot if (tp->t_rsel) { 14597502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 14607502Sroot tp->t_state &= ~TS_RCOLL; 14617502Sroot tp->t_rsel = 0; 14627502Sroot } 14637502Sroot wakeup((caddr_t)&tp->t_rawq); 14647502Sroot } 14657502Sroot 146610391Ssam #if !defined(vax) && !defined(sun) 14679578Ssam scanc(size, cp, table, mask) 14689578Ssam register int size; 14699578Ssam register char *cp, table[]; 14709578Ssam register int mask; 14717502Sroot { 14729578Ssam register int i = 0; 14737502Sroot 14749578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 14759578Ssam i++; 14769578Ssam return (i); 14777502Sroot } 14789578Ssam #endif 1479