1*9624Ssam /* tty.c 4.36 82/12/13 */ 239Sbill 339Sbill #include "../h/param.h" 439Sbill #include "../h/systm.h" 539Sbill #include "../h/dir.h" 639Sbill #include "../h/user.h" 79578Ssam #include "../h/ioctl.h" 839Sbill #include "../h/tty.h" 939Sbill #include "../h/proc.h" 1039Sbill #include "../h/inode.h" 1139Sbill #include "../h/file.h" 1239Sbill #include "../h/reg.h" 1339Sbill #include "../h/conf.h" 1439Sbill #include "../h/buf.h" 15340Sbill #include "../h/dk.h" 167722Swnj #include "../h/uio.h" 178154Sroot #include "../h/kernel.h" 1839Sbill 197436Skre /* 207436Skre * Table giving parity for characters and indicating 217436Skre * character classes to tty driver. In particular, 227436Skre * if the low 6 bits are 0, then the character needs 237436Skre * no special processing on output. 247436Skre */ 2539Sbill 267436Skre char partab[] = { 277436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 287436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 297436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 307436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 317436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 327436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 337436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 347436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 357436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 367436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 377436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 387436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 397436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 407436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 417436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 427436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 437436Skre 447436Skre /* 457436Skre * 7 bit ascii ends with the last character above, 467436Skre * but we contine through all 256 codes for the sake 477436Skre * of the tty output routines which use special vax 487436Skre * instructions which need a 256 character trt table. 497436Skre */ 507436Skre 517436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 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 }; 687436Skre 69146Sbill /* 7039Sbill * Input mapping table-- if an entry is non-zero, when the 7139Sbill * corresponding character is typed preceded by "\" the escape 7239Sbill * sequence is replaced by the table value. Mostly used for 7339Sbill * upper-case only terminals. 7439Sbill */ 7539Sbill char maptab[] ={ 7639Sbill 000,000,000,000,000,000,000,000, 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,'`', 8139Sbill '{','}',000,000,000,000,000,000, 8239Sbill 000,000,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, 8839Sbill 000,'A','B','C','D','E','F','G', 8939Sbill 'H','I','J','K','L','M','N','O', 9039Sbill 'P','Q','R','S','T','U','V','W', 9139Sbill 'X','Y','Z',000,000,000,000,000, 9239Sbill }; 9339Sbill 94925Sbill short tthiwat[16] = 958954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 96925Sbill short ttlowat[16] = 97925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 98925Sbill 999578Ssam struct ttychars ttydefaults = { 1009578Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 1019578Ssam CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 1029578Ssam }; 10339Sbill 10439Sbill ttychars(tp) 1059578Ssam struct tty *tp; 10639Sbill { 107174Sbill 1089578Ssam tp->t_chars = ttydefaults; 10939Sbill } 11039Sbill 11139Sbill /* 112903Sbill * Wait for output to drain, then flush input waiting. 11339Sbill */ 114903Sbill wflushtty(tp) 1155408Swnj register struct tty *tp; 11639Sbill { 11739Sbill 118903Sbill (void) spl5(); 1195622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1205622Swnj && tp->t_oproc) { /* kludge for pty */ 121903Sbill (*tp->t_oproc)(tp); 1225408Swnj tp->t_state |= TS_ASLEEP; 123903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 124903Sbill } 1255426Swnj flushtty(tp, FREAD); 126903Sbill (void) spl0(); 12739Sbill } 12839Sbill 12939Sbill /* 1309578Ssam * Flush all TTY queues 13139Sbill */ 132903Sbill flushtty(tp, rw) 1337625Ssam register struct tty *tp; 13439Sbill { 135903Sbill register s; 136903Sbill 137903Sbill s = spl6(); 138903Sbill if (rw & FREAD) { 139903Sbill while (getc(&tp->t_canq) >= 0) 140903Sbill ; 141903Sbill wakeup((caddr_t)&tp->t_rawq); 142903Sbill } 143903Sbill if (rw & FWRITE) { 144903Sbill wakeup((caddr_t)&tp->t_outq); 1455408Swnj tp->t_state &= ~TS_TTSTOP; 1465426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 147903Sbill while (getc(&tp->t_outq) >= 0) 148903Sbill ; 149903Sbill } 150903Sbill if (rw & FREAD) { 151903Sbill while (getc(&tp->t_rawq) >= 0) 152903Sbill ; 153903Sbill tp->t_delct = 0; 1549578Ssam tp->t_rocount = 0; 155903Sbill tp->t_rocol = 0; 1569578Ssam tp->t_state &= ~TS_LOCAL; 157903Sbill } 158903Sbill splx(s); 15939Sbill } 16039Sbill 161903Sbill /* 162903Sbill * Send stop character on input overflow. 163903Sbill */ 164903Sbill ttyblock(tp) 1657625Ssam register struct tty *tp; 16639Sbill { 167903Sbill register x; 1689578Ssam 169903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 170903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 171903Sbill flushtty(tp, FREAD|FWRITE); 1725408Swnj tp->t_state &= ~TS_TBLOCK; 173903Sbill } 1749578Ssam if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) { 1759578Ssam tp->t_state |= TS_TBLOCK; 1769578Ssam tp->t_char++; 1779578Ssam ttstart(tp); 178903Sbill } 17939Sbill } 18039Sbill 18139Sbill /* 182903Sbill * Restart typewriter output following a delay 183903Sbill * timeout. 184903Sbill * The name of the routine is passed to the timeout 185903Sbill * subroutine and it is called during a clock interrupt. 186121Sbill */ 187903Sbill ttrstrt(tp) 1887625Ssam register struct tty *tp; 189121Sbill { 190121Sbill 1919578Ssam if (tp == 0) 1929578Ssam panic("ttrstrt"); 1935408Swnj tp->t_state &= ~TS_TIMEOUT; 194903Sbill ttstart(tp); 195121Sbill } 196121Sbill 197121Sbill /* 198903Sbill * Start output on the typewriter. It is used from the top half 199903Sbill * after some characters have been put on the output queue, 200903Sbill * from the interrupt routine to transmit the next 201903Sbill * character, and after a timeout has finished. 20239Sbill */ 203903Sbill ttstart(tp) 2047625Ssam register struct tty *tp; 20539Sbill { 206903Sbill register s; 20739Sbill 208903Sbill s = spl5(); 2099578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2105622Swnj tp->t_oproc) /* kludge for pty */ 211903Sbill (*tp->t_oproc)(tp); 212903Sbill splx(s); 21339Sbill } 21439Sbill 21539Sbill /* 216903Sbill * Common code for tty ioctls. 21739Sbill */ 2181780Sbill /*ARGSUSED*/ 2197625Ssam ttioctl(tp, com, data, flag) 2207625Ssam register struct tty *tp; 2217625Ssam caddr_t data; 22239Sbill { 2238520Sroot int dev = tp->t_dev; 22439Sbill extern int nldisp; 2258556Sroot int s; 22639Sbill 227903Sbill /* 228903Sbill * If the ioctl involves modification, 229903Sbill * insist on being able to write the device, 230903Sbill * and hang if in the background. 231903Sbill */ 2327625Ssam switch (com) { 23339Sbill 234915Sbill case TIOCSETD: 235915Sbill case TIOCSETP: 236915Sbill case TIOCSETN: 237903Sbill case TIOCFLUSH: 238903Sbill case TIOCSETC: 239903Sbill case TIOCSLTC: 240903Sbill case TIOCSPGRP: 241903Sbill case TIOCLBIS: 242903Sbill case TIOCLBIC: 243903Sbill case TIOCLSET: 244*9624Ssam case TIOCBIS: 245*9624Ssam case TIOCBIC: 246*9624Ssam case TIOCSET: 2479325Ssam case TIOCSTI: 248903Sbill while (tp->t_line == NTTYDISC && 249903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 250903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 251903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2528556Sroot u.u_signal[SIGTTOU] != SIG_HOLD) { 253903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 254903Sbill sleep((caddr_t)&lbolt, TTOPRI); 255903Sbill } 256903Sbill break; 257903Sbill } 258903Sbill 2599578Ssam /* 2609578Ssam * Process the ioctl. 2619578Ssam */ 2627625Ssam switch (com) { 263903Sbill 2648556Sroot /* get discipline number */ 26539Sbill case TIOCGETD: 2667625Ssam *(int *)data = tp->t_line; 26739Sbill break; 26839Sbill 2698556Sroot /* set line discipline */ 2707625Ssam case TIOCSETD: { 2717625Ssam register int t = *(int *)data; 2729578Ssam int error = 0; 2737625Ssam 2749578Ssam if (t >= nldisp) { 2759578Ssam u.u_error = ENXIO; 2769578Ssam break; 2779578Ssam } 2788556Sroot s = spl5(); 27939Sbill if (tp->t_line) 28039Sbill (*linesw[tp->t_line].l_close)(tp); 28139Sbill if (t) 2828556Sroot error = (*linesw[t].l_open)(dev, tp); 2838556Sroot splx(s); 2848556Sroot if (error) 2858556Sroot return (error); 2868556Sroot tp->t_line = t; 28739Sbill break; 2887625Ssam } 28939Sbill 2908556Sroot /* prevent more opens on channel */ 2915614Swnj case TIOCEXCL: 2925614Swnj tp->t_state |= TS_XCLUDE; 2935614Swnj break; 2945614Swnj 2955614Swnj case TIOCNXCL: 2965614Swnj tp->t_state &= ~TS_XCLUDE; 2975614Swnj break; 2985614Swnj 299*9624Ssam case TIOCSET: 300*9624Ssam case TIOCBIS: { 301*9624Ssam u_long newflags = *(u_long *)data; 3027625Ssam 303*9624Ssam s = spl5(); 304*9624Ssam if (tp->t_flags&RAW || newflags&RAW) 3054484Swnj wflushtty(tp); 306*9624Ssam else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) 307*9624Ssam if (newflags&CBREAK) { 308*9624Ssam struct clist tq; 309*9624Ssam 3104484Swnj catq(&tp->t_rawq, &tp->t_canq); 3114484Swnj tq = tp->t_rawq; 3124484Swnj tp->t_rawq = tp->t_canq; 3134484Swnj tp->t_canq = tq; 3144484Swnj } else { 3159578Ssam tp->t_flags |= PENDIN; 3164484Swnj ttwakeup(tp); 317174Sbill } 318*9624Ssam if (com == TIOCSET) 319*9624Ssam tp->t_flags = newflags; 320*9624Ssam else 321*9624Ssam tp->t_flags |= newflags; 3229578Ssam if (tp->t_flags&RAW) { 3235408Swnj tp->t_state &= ~TS_TTSTOP; 3243941Sbugs ttstart(tp); 3253941Sbugs } 326*9624Ssam splx(s); 32739Sbill break; 3287625Ssam } 32939Sbill 330*9624Ssam case TIOCBIC: { 331*9624Ssam u_long newflags = *(long *)data; 3327625Ssam 333*9624Ssam if (tp->t_flags&RAW) 334*9624Ssam wflushtty(tp); 335*9624Ssam else if ((tp->t_flags&CBREAK) != (CBREAK&~newflags)) 336*9624Ssam if (newflags&CBREAK) { 337*9624Ssam tp->t_flags |= PENDIN; 338*9624Ssam ttwakeup(tp); 339*9624Ssam } else { 340*9624Ssam struct clist tq; 341*9624Ssam 342*9624Ssam catq(&tp->t_rawq, &tp->t_canq); 343*9624Ssam tq = tp->t_rawq; 344*9624Ssam tp->t_rawq = tp->t_canq; 345*9624Ssam tp->t_canq = tq; 346*9624Ssam } 347*9624Ssam if (tp->t_flags&RAW) { 348*9624Ssam tp->t_state &= ~TS_TTSTOP; 349*9624Ssam ttstart(tp); 350*9624Ssam } 351*9624Ssam splx(s); 35239Sbill break; 3537625Ssam } 35439Sbill 355*9624Ssam case TIOCGET: 356*9624Ssam *(long *)data = tp->t_flags; 357*9624Ssam break; 358*9624Ssam 359*9624Ssam case TIOCCGET: 360*9624Ssam bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars)); 361*9624Ssam break; 362*9624Ssam 363*9624Ssam case TIOCCSET: 364*9624Ssam bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars)); 365*9624Ssam break; 366*9624Ssam 3678556Sroot /* hang up line on last close */ 36839Sbill case TIOCHPCL: 3695408Swnj tp->t_state |= TS_HUPCLS; 37039Sbill break; 37139Sbill 3723942Sbugs case TIOCFLUSH: { 3737625Ssam register int flags = *(int *)data; 3747625Ssam 3757625Ssam if (flags == 0) 3763942Sbugs flags = FREAD|FWRITE; 3777625Ssam else 3787625Ssam flags &= FREAD|FWRITE; 3793942Sbugs flushtty(tp, flags); 38039Sbill break; 3813944Sbugs } 38239Sbill 3838556Sroot /* return number of characters immediately available */ 3847625Ssam case FIONREAD: 3857625Ssam *(off_t *)data = ttnread(tp); 386174Sbill break; 387174Sbill 3888589Sroot case TIOCSTOP: 3898589Sroot s = spl5(); 3909578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3915573Swnj tp->t_state |= TS_TTSTOP; 3925573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3935573Swnj } 3947625Ssam splx(s); 3955573Swnj break; 3965573Swnj 3978589Sroot case TIOCSTART: 3988589Sroot s = spl5(); 3999578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 4005573Swnj tp->t_state &= ~TS_TTSTOP; 4019578Ssam tp->t_flags &= ~FLUSHO; 4025573Swnj ttstart(tp); 4035573Swnj } 4047625Ssam splx(s); 4055573Swnj break; 4065573Swnj 4079325Ssam /* 4089325Ssam * Simulate typing of a character at the terminal. 4099325Ssam */ 4109325Ssam case TIOCSTI: 4119325Ssam if (u.u_uid && u.u_ttyp != tp) 4129325Ssam return (EACCES); 4139578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4149325Ssam break; 4159325Ssam 41639Sbill default: 417*9624Ssam #ifndef NOCOMPAT 418*9624Ssam return (ottioctl(tp, com, data, flag)); 419*9624Ssam #else 4208556Sroot return (-1); 421*9624Ssam #endif 42239Sbill } 4238556Sroot return (0); 42439Sbill } 4254484Swnj 4264484Swnj ttnread(tp) 4274484Swnj struct tty *tp; 4284484Swnj { 4294484Swnj int nread = 0; 4304484Swnj 4319578Ssam if (tp->t_flags & PENDIN) 4324484Swnj ttypend(tp); 4334484Swnj nread = tp->t_canq.c_cc; 4344484Swnj if (tp->t_flags & (RAW|CBREAK)) 4354484Swnj nread += tp->t_rawq.c_cc; 4364484Swnj return (nread); 4374484Swnj } 4384484Swnj 4395408Swnj ttselect(dev, rw) 4404484Swnj dev_t dev; 4415408Swnj int rw; 4424484Swnj { 4434484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4444484Swnj int nread; 4455408Swnj int s = spl5(); 4464484Swnj 4475408Swnj switch (rw) { 4484484Swnj 4494484Swnj case FREAD: 4504484Swnj nread = ttnread(tp); 4514484Swnj if (nread > 0) 4525408Swnj goto win; 4534938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 4545408Swnj tp->t_state |= TS_RCOLL; 4554484Swnj else 4564484Swnj tp->t_rsel = u.u_procp; 4575408Swnj break; 4584484Swnj 4595408Swnj case FWRITE: 4605408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 4615408Swnj goto win; 4625408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 4635408Swnj tp->t_state |= TS_WCOLL; 4645408Swnj else 4655408Swnj tp->t_wsel = u.u_procp; 4665408Swnj break; 4674484Swnj } 4685408Swnj splx(s); 4695408Swnj return (0); 4705408Swnj win: 4715408Swnj splx(s); 4725408Swnj return (1); 4734484Swnj } 4747436Skre 4757502Sroot /* 4769578Ssam * Establish a process group for distribution of 4777502Sroot * quits and interrupts from the tty. 4787502Sroot */ 4797502Sroot ttyopen(dev, tp) 4807625Ssam dev_t dev; 4817625Ssam register struct tty *tp; 4827502Sroot { 4837502Sroot register struct proc *pp; 4847502Sroot 4857502Sroot pp = u.u_procp; 4867502Sroot tp->t_dev = dev; 4877625Ssam if (pp->p_pgrp == 0) { 4887502Sroot u.u_ttyp = tp; 4897502Sroot u.u_ttyd = dev; 4907502Sroot if (tp->t_pgrp == 0) 4917502Sroot tp->t_pgrp = pp->p_pid; 4927502Sroot pp->p_pgrp = tp->t_pgrp; 4937502Sroot } 4947502Sroot tp->t_state &= ~TS_WOPEN; 4957502Sroot tp->t_state |= TS_ISOPEN; 4967502Sroot if (tp->t_line != NTTYDISC) 4977502Sroot wflushtty(tp); 4988556Sroot return (0); 4997502Sroot } 5007502Sroot 5017502Sroot /* 5027502Sroot * clean tp on last close 5037502Sroot */ 5047502Sroot ttyclose(tp) 5057625Ssam register struct tty *tp; 5067502Sroot { 5077502Sroot 5087502Sroot if (tp->t_line) { 5097502Sroot wflushtty(tp); 5107502Sroot tp->t_line = 0; 5117502Sroot return; 5127502Sroot } 5137502Sroot tp->t_pgrp = 0; 5147502Sroot wflushtty(tp); 5157502Sroot tp->t_state = 0; 5167502Sroot } 5177502Sroot 5187502Sroot /* 5197502Sroot * reinput pending characters after state switch 5207502Sroot * call at spl5(). 5217502Sroot */ 5227502Sroot ttypend(tp) 5237625Ssam register struct tty *tp; 5247502Sroot { 5257502Sroot struct clist tq; 5267502Sroot register c; 5277502Sroot 5289578Ssam tp->t_flags &= ~PENDIN; 5299578Ssam tp->t_state |= TS_TYPEN; 5307502Sroot tq = tp->t_rawq; 5317502Sroot tp->t_rawq.c_cc = 0; 5327502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5337502Sroot while ((c = getc(&tq)) >= 0) 5347502Sroot ttyinput(c, tp); 5359578Ssam tp->t_state &= ~TS_TYPEN; 5367502Sroot } 5377502Sroot 5387502Sroot /* 5399578Ssam * Place a character on raw TTY input queue, 5409578Ssam * putting in delimiters and waking up top 5419578Ssam * half as needed. Also echo if required. 5429578Ssam * The arguments are the character and the 5439578Ssam * appropriate tty structure. 5447502Sroot */ 5457502Sroot ttyinput(c, tp) 5467625Ssam register c; 5477625Ssam register struct tty *tp; 5487502Sroot { 5499578Ssam register int t_flags = tp->t_flags; 5507502Sroot int i; 5517502Sroot 5529578Ssam /* 5539578Ssam * If input is pending take it first. 5549578Ssam */ 5559578Ssam if (t_flags&PENDIN) 5567502Sroot ttypend(tp); 5577502Sroot tk_nin++; 5587502Sroot c &= 0377; 5599578Ssam 5609578Ssam /* 5619578Ssam * In tandem mode, check high water mark. 5629578Ssam */ 5637502Sroot if (t_flags&TANDEM) 5647502Sroot ttyblock(tp); 5659578Ssam 5669578Ssam if (t_flags&RAW) { 5679578Ssam /* 5689578Ssam * Raw mode, just put character 5699578Ssam * in input q w/o interpretation. 5709578Ssam */ 5719578Ssam if (tp->t_rawq.c_cc > TTYHOG) 5729578Ssam flushtty(tp, FREAD|FWRITE); 5739578Ssam else { 5749578Ssam if (putc(c, &tp->t_rawq) >= 0) 5759578Ssam ttwakeup(tp); 5769578Ssam ttyecho(c, tp); 5777502Sroot } 5789578Ssam goto endcase; 5799578Ssam } 5809578Ssam 5819578Ssam /* 5829578Ssam * Ignore any high bit added during 5839578Ssam * previous ttyinput processing. 5849578Ssam */ 5859578Ssam if ((tp->t_state&TS_TYPEN) == 0) 5869578Ssam c &= 0177; 5879578Ssam /* 5889578Ssam * Check for literal nexting very first 5899578Ssam */ 5909578Ssam if (tp->t_state&TS_LNCH) { 5919578Ssam c |= 0200; 5929578Ssam tp->t_state &= ~TS_LNCH; 5939578Ssam } 5949578Ssam 5959578Ssam /* 5969578Ssam * Scan for special characters. This code 5979578Ssam * is really just a big case statement with 5989578Ssam * non-constant cases. The bottom of the 5999578Ssam * case statement is labeled ``endcase'', so goto 6009578Ssam * it after a case match, or similar. 6019578Ssam */ 6029578Ssam if (tp->t_line == NTTYDISC) { 6039578Ssam if (c == tp->t_lnextc) { 6047502Sroot if (tp->t_flags&ECHO) 6057502Sroot ttyout("^\b", tp); 6069578Ssam tp->t_state |= TS_LNCH; 6079578Ssam goto endcase; 6089578Ssam } 6099578Ssam if (c == tp->t_flushc) { 6109578Ssam if (tp->t_flags&FLUSHO) 6119578Ssam tp->t_flags &= ~FLUSHO; 6127502Sroot else { 6137502Sroot flushtty(tp, FWRITE); 6147502Sroot ttyecho(c, tp); 6159578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6167502Sroot ttyretype(tp); 6179578Ssam tp->t_flags |= FLUSHO; 6187502Sroot } 6199578Ssam goto startoutput; 6209578Ssam } 6219578Ssam if (c == tp->t_suspc) { 6229578Ssam if ((tp->t_flags&NOFLSH) == 0) 6239578Ssam flushtty(tp, FREAD); 6249578Ssam ttyecho(c, tp); 6259578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6269578Ssam goto endcase; 6279578Ssam } 6289578Ssam } 6299578Ssam 6309578Ssam /* 6319578Ssam * Handle start/stop characters. 6329578Ssam */ 6339578Ssam if (c == tp->t_stopc) { 6349578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6359578Ssam tp->t_state |= TS_TTSTOP; 6369578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6377502Sroot return; 6389578Ssam } 6399578Ssam if (c != tp->t_startc) 6409578Ssam return; 6419578Ssam goto endcase; 6429578Ssam } 6439578Ssam if (c == tp->t_startc) 6449578Ssam goto restartoutput; 6459578Ssam 6469578Ssam /* 6479578Ssam * Look for interrupt/quit chars. 6489578Ssam */ 6499578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 6509578Ssam if ((tp->t_flags&NOFLSH) == 0) 6519578Ssam flushtty(tp, FREAD|FWRITE); 6529578Ssam ttyecho(c, tp); 6539578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 6549578Ssam goto endcase; 6559578Ssam } 6569578Ssam 6579578Ssam /* 6589578Ssam * Cbreak mode, don't process line editing 6599578Ssam * characters; check high water mark for wakeup. 6609578Ssam */ 6619578Ssam if (t_flags&CBREAK) { 6629578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 6637502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 6647502Sroot tp->t_line == NTTYDISC) 6657502Sroot (void) ttyoutput(CTRL(g), tp); 6667502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 6677502Sroot ttwakeup(tp); 6687502Sroot ttyecho(c, tp); 6697502Sroot } 6709578Ssam goto endcase; 6719578Ssam } 6729578Ssam 6739578Ssam /* 6749578Ssam * From here on down cooked mode character 6759578Ssam * processing takes place. 6769578Ssam */ 6779578Ssam if ((tp->t_state&TS_QUOT) && 6789578Ssam (c == tp->t_erase || c == tp->t_kill)) { 6799578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6809578Ssam c |= 0200; 6819578Ssam } 6829578Ssam if (c == tp->t_erase) { 6839578Ssam if (tp->t_rawq.c_cc) 6849578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6859578Ssam goto endcase; 6869578Ssam } 6879578Ssam if (c == tp->t_kill) { 6889578Ssam if (tp->t_flags&CRTKIL && 6899578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 6909578Ssam while (tp->t_rawq.c_cc) 6919578Ssam ttyrub(unputc(&tp->t_rawq), tp); 6929578Ssam } else { 6939578Ssam ttyecho(c, tp); 6949578Ssam ttyecho('\n', tp); 6959578Ssam while (getc(&tp->t_rawq) > 0) 6969578Ssam ; 6979578Ssam tp->t_rocount = 0; 6989578Ssam } 6999578Ssam tp->t_state &= ~TS_LOCAL; 7009578Ssam goto endcase; 7019578Ssam } 7029578Ssam 7039578Ssam /* 7049578Ssam * New line discipline, 7059578Ssam * check word erase/reprint line. 7069578Ssam */ 7079578Ssam if (tp->t_line == NTTYDISC) { 7089578Ssam if (c == tp->t_werasc) { 7099578Ssam if (tp->t_rawq.c_cc == 0) 7109578Ssam goto endcase; 7119578Ssam do { 7129578Ssam c = unputc(&tp->t_rawq); 7139578Ssam if (c != ' ' && c != '\t') 7149578Ssam goto erasenb; 7159578Ssam ttyrub(c, tp); 7169578Ssam } while (tp->t_rawq.c_cc); 7179578Ssam goto endcase; 7189578Ssam erasenb: 7199578Ssam do { 7209578Ssam ttyrub(c, tp); 7219578Ssam if (tp->t_rawq.c_cc == 0) 7229578Ssam goto endcase; 7239578Ssam c = unputc(&tp->t_rawq); 7249578Ssam } while (c != ' ' && c != '\t'); 7259578Ssam (void) putc(c, &tp->t_rawq); 7269578Ssam goto endcase; 7279578Ssam } 7289578Ssam if (c == tp->t_rprntc) { 7299578Ssam ttyretype(tp); 7309578Ssam goto endcase; 7319578Ssam } 7329578Ssam } 7339578Ssam 7349578Ssam /* 7359578Ssam * Check for input buffer overflow 7369578Ssam */ 7379578Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) 7389578Ssam goto endcase; 7399578Ssam 7409578Ssam /* 7419578Ssam * Put data char in q for user and 7429578Ssam * wakeup on seeing a line delimiter. 7439578Ssam */ 7449578Ssam if (putc(c, &tp->t_rawq) >= 0) { 7459578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc == TTYHOG 7469578Ssam && tp->t_line == NTTYDISC) 7479578Ssam (void) ttyoutput(CTRL(g), tp); 7489578Ssam if (ttbreakc(c, tp)) { 7499578Ssam tp->t_rocount = 0; 7509578Ssam catq(&tp->t_rawq, &tp->t_canq); 7517502Sroot ttwakeup(tp); 7529578Ssam } else if (tp->t_rocount++ == 0) 7539578Ssam tp->t_rocol = tp->t_col; 7549578Ssam tp->t_state &= ~TS_QUOT; 7559578Ssam if (c == '\\') 7569578Ssam tp->t_state |= TS_QUOT; 7579578Ssam if (tp->t_state&TS_ERASE) { 7589578Ssam tp->t_state &= ~TS_ERASE; 7599578Ssam (void) ttyoutput('/', tp); 7609578Ssam } 7619578Ssam i = tp->t_col; 7627502Sroot ttyecho(c, tp); 7639578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 7649578Ssam i = MIN(2, tp->t_col - i); 7659578Ssam while (i > 0) { 7669578Ssam (void) ttyoutput('\b', tp); 7679578Ssam i--; 7689578Ssam } 7699578Ssam } 7707502Sroot } 7719578Ssam 7729578Ssam endcase: 7739578Ssam /* 7749578Ssam * If DEC-style start/stop is enabled don't restart 7759578Ssam * output until seeing the start character. 7769578Ssam */ 7779578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 7789578Ssam tp->t_startc != tp->t_stopc) 7797502Sroot return; 7809578Ssam 7819578Ssam restartoutput: 7827502Sroot tp->t_state &= ~TS_TTSTOP; 7839578Ssam tp->t_flags &= ~FLUSHO; 7849578Ssam 7859578Ssam startoutput: 7867502Sroot ttstart(tp); 7877502Sroot } 7887502Sroot 7897502Sroot /* 7909578Ssam * Put character on TTY output queue, adding delays, 7917502Sroot * expanding tabs, and handling the CR/NL bit. 7929578Ssam * This is called both from the top half for output, 7939578Ssam * and from interrupt level for echoing. 7947502Sroot * The arguments are the character and the tty structure. 7957502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 7967502Sroot * Must be recursive. 7977502Sroot */ 7987502Sroot ttyoutput(c, tp) 7997502Sroot register c; 8007502Sroot register struct tty *tp; 8017502Sroot { 8027502Sroot register char *colp; 8037502Sroot register ctype; 8047502Sroot 8059578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8069578Ssam if (tp->t_flags&FLUSHO) 8077502Sroot return (-1); 8087502Sroot if (putc(c, &tp->t_outq)) 8097625Ssam return (c); 8107502Sroot tk_nout++; 8117502Sroot return (-1); 8127502Sroot } 8139578Ssam 8147502Sroot /* 8159578Ssam * Ignore EOT in normal mode to avoid 8169578Ssam * hanging up certain terminals. 8177502Sroot */ 8187502Sroot c &= 0177; 8199578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8207502Sroot return (-1); 8217502Sroot /* 8227502Sroot * Turn tabs to spaces as required 8237502Sroot */ 8249578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8257502Sroot register int s; 8267502Sroot 8277502Sroot c = 8 - (tp->t_col&7); 8289578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8297502Sroot s = spl5(); /* don't interrupt tabs */ 8307502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8317502Sroot tk_nout += c; 8327502Sroot splx(s); 8337502Sroot } 8347502Sroot tp->t_col += c; 8357502Sroot return (c ? -1 : '\t'); 8367502Sroot } 8377502Sroot tk_nout++; 8387502Sroot /* 8397502Sroot * for upper-case-only terminals, 8407502Sroot * generate escapes. 8417502Sroot */ 8427502Sroot if (tp->t_flags&LCASE) { 8437502Sroot colp = "({)}!|^~'`"; 8447625Ssam while (*colp++) 8457625Ssam if (c == *colp++) { 8467502Sroot if (ttyoutput('\\', tp) >= 0) 8477502Sroot return (c); 8487502Sroot c = colp[-2]; 8497502Sroot break; 8507502Sroot } 8519578Ssam if ('A' <= c && c <= 'Z') { 8527502Sroot if (ttyoutput('\\', tp) >= 0) 8537502Sroot return (c); 8549578Ssam } else if ('a' <= c && c <= 'z') 8557502Sroot c += 'A' - 'a'; 8567502Sroot } 8579578Ssam 8587502Sroot /* 8597502Sroot * turn <nl> to <cr><lf> if desired. 8607502Sroot */ 8619578Ssam if (c == '\n' && tp->t_flags&CRMOD) 8627502Sroot if (ttyoutput('\r', tp) >= 0) 8637502Sroot return (c); 8649578Ssam if (c == '~' && tp->t_flags&TILDE) 8657502Sroot c = '`'; 8669578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 8677502Sroot return (c); 8687502Sroot /* 8697502Sroot * Calculate delays. 8707502Sroot * The numbers here represent clock ticks 8717502Sroot * and are not necessarily optimal for all terminals. 8727502Sroot * The delays are indicated by characters above 0200. 8737502Sroot * In raw mode there are no delays and the 8747502Sroot * transmission path is 8 bits wide. 8759578Ssam * 8769578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 8777502Sroot */ 8787502Sroot colp = &tp->t_col; 8797502Sroot ctype = partab[c]; 8807502Sroot c = 0; 8817502Sroot switch (ctype&077) { 8827502Sroot 8837502Sroot case ORDINARY: 8847502Sroot (*colp)++; 8857502Sroot 8867502Sroot case CONTROL: 8877502Sroot break; 8887502Sroot 8897502Sroot case BACKSPACE: 8907502Sroot if (*colp) 8917502Sroot (*colp)--; 8927502Sroot break; 8937502Sroot 8947502Sroot case NEWLINE: 8957502Sroot ctype = (tp->t_flags >> 8) & 03; 8967625Ssam if (ctype == 1) { /* tty 37 */ 8977502Sroot if (*colp) 8987502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 8999578Ssam } else if (ctype == 2) /* vt05 */ 9007502Sroot c = 6; 9017502Sroot *colp = 0; 9027502Sroot break; 9037502Sroot 9047502Sroot case TAB: 9057502Sroot ctype = (tp->t_flags >> 10) & 03; 9067625Ssam if (ctype == 1) { /* tty 37 */ 9077502Sroot c = 1 - (*colp | ~07); 9087625Ssam if (c < 5) 9097502Sroot c = 0; 9107502Sroot } 9117502Sroot *colp |= 07; 9127502Sroot (*colp)++; 9137502Sroot break; 9147502Sroot 9157502Sroot case VTAB: 9169578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9177502Sroot c = 0177; 9187502Sroot break; 9197502Sroot 9207502Sroot case RETURN: 9217502Sroot ctype = (tp->t_flags >> 12) & 03; 9229578Ssam if (ctype == 1) /* tn 300 */ 9237502Sroot c = 5; 9249578Ssam else if (ctype == 2) /* ti 700 */ 9257502Sroot c = 10; 9269578Ssam else if (ctype == 3) { /* concept 100 */ 9277502Sroot int i; 9289578Ssam 9297502Sroot if ((i = *colp) >= 0) 9309578Ssam for (; i < 9; i++) 9317502Sroot (void) putc(0177, &tp->t_outq); 9327502Sroot } 9337502Sroot *colp = 0; 9347502Sroot } 9359578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9367502Sroot (void) putc(c|0200, &tp->t_outq); 9377502Sroot return (-1); 9387502Sroot } 9397502Sroot 9407502Sroot /* 9417502Sroot * Called from device's read routine after it has 9427502Sroot * calculated the tty-structure given as argument. 9437502Sroot */ 9447722Swnj ttread(tp, uio) 9457625Ssam register struct tty *tp; 9467722Swnj struct uio *uio; 9477502Sroot { 9487502Sroot register struct clist *qp; 9499578Ssam register c, t_flags; 9509578Ssam int first, error = 0; 9517502Sroot 9527502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9538520Sroot return (EIO); 9547502Sroot loop: 9559578Ssam /* 9569578Ssam * Take any pending input first. 9579578Ssam */ 9587502Sroot (void) spl5(); 9599578Ssam if (tp->t_flags&PENDIN) 9607502Sroot ttypend(tp); 9617502Sroot (void) spl0(); 9629578Ssam 9639578Ssam /* 9649578Ssam * Hang process if it's in the background. 9659578Ssam */ 9667502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9677502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9687502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9697502Sroot /* 9707502Sroot (u.u_procp->p_flag&SDETACH) || 9717502Sroot */ 9727502Sroot u.u_procp->p_flag&SVFORK) 9738520Sroot return (EIO); 9747502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9757502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9767502Sroot } 9779578Ssam t_flags = tp->t_flags; 9789578Ssam 9799578Ssam /* 9809578Ssam * In raw mode take characters directly from the 9819578Ssam * raw queue w/o processing. Interlock against 9829578Ssam * device interrupts when interrogating rawq. 9839578Ssam */ 9849578Ssam if (t_flags&RAW) { 9857502Sroot (void) spl5(); 9867502Sroot if (tp->t_rawq.c_cc <= 0) { 9879578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 9887502Sroot (tp->t_state&TS_NBIO)) { 9897502Sroot (void) spl0(); 9909578Ssam return (0); 9917502Sroot } 9927502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9937502Sroot (void) spl0(); 9947502Sroot goto loop; 9957502Sroot } 9967502Sroot (void) spl0(); 9977722Swnj while (tp->t_rawq.c_cc && uio->uio_iovcnt) { 9988520Sroot error = passuc(getc(&tp->t_rawq), uio); 9998520Sroot if (error) 10007722Swnj break; 10017722Swnj } 10028520Sroot return (error); 10039578Ssam } 10049578Ssam 10059578Ssam /* 10069578Ssam * In cbreak mode use the rawq, otherwise 10079578Ssam * take characters from the canonicalized q. 10089578Ssam */ 10099578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10109578Ssam 10119578Ssam /* 10129578Ssam * No input, sleep on rawq awaiting hardware 10139578Ssam * receipt and notification. 10149578Ssam */ 10159578Ssam (void) spl5(); 10169578Ssam if (qp->c_cc <= 0) { 10179578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10189578Ssam (tp->t_state&TS_NBIO)) { 10197502Sroot (void) spl0(); 10209578Ssam return (EWOULDBLOCK); 10217502Sroot } 10229578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10237502Sroot (void) spl0(); 10249578Ssam goto loop; 10259578Ssam } 10269578Ssam (void) spl0(); 10279578Ssam 10289578Ssam /* 10299578Ssam * Input present, perform input mapping 10309578Ssam * and processing (we're not in raw mode). 10319578Ssam */ 10329578Ssam first = 1; 10339578Ssam while ((c = getc(qp)) >= 0) { 10349578Ssam if (t_flags&CRMOD && c == '\r') 10359578Ssam c = '\n'; 10369578Ssam /* 10379578Ssam * Hack lower case simulation on 10389578Ssam * upper case only terminals. 10399578Ssam */ 10409578Ssam if (t_flags&LCASE && c <= 0177) 10419578Ssam if (tp->t_state&TS_BKSL) { 10429578Ssam if (maptab[c]) 10439578Ssam c = maptab[c]; 10449578Ssam tp->t_state &= ~TS_BKSL; 10459578Ssam } else if (c >= 'A' && c <= 'Z') 10469578Ssam c += 'a' - 'A'; 10479578Ssam else if (c == '\\') { 10489578Ssam tp->t_state |= TS_BKSL; 10499578Ssam continue; 10507502Sroot } 10519578Ssam /* 10529578Ssam * Check for delayed suspend character. 10539578Ssam */ 10549578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 10559578Ssam gsignal(tp->t_pgrp, SIGTSTP); 10569578Ssam if (first) { 10579578Ssam sleep((caddr_t)&lbolt, TTIPRI); 10589578Ssam goto loop; 10599578Ssam } 10609578Ssam break; 10617502Sroot } 10629578Ssam /* 10639578Ssam * Interpret EOF only in cooked mode. 10649578Ssam */ 10659578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 10669578Ssam break; 10679578Ssam /* 10689578Ssam * Give user character. 10699578Ssam */ 10709578Ssam error = passuc(c & 0177, uio); 10719578Ssam if (error) 10729578Ssam break; 10739578Ssam if (uio->uio_iovcnt == 0) 10749578Ssam break; 10759578Ssam /* 10769578Ssam * In cooked mode check for a "break character" 10779578Ssam * marking the end of a "line of input". 10789578Ssam */ 10799578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 10809578Ssam break; 10819578Ssam first = 0; 10827502Sroot } 10839578Ssam tp->t_state &= ~TS_BKSL; 10849578Ssam 10859578Ssam /* 10869578Ssam * Look to unblock output now that (presumably) 10879578Ssam * the input queue has gone down. 10889578Ssam */ 10897502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 10909578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 10917502Sroot tp->t_state &= ~TS_TBLOCK; 10927502Sroot ttstart(tp); 10937502Sroot } 10947502Sroot tp->t_char = 0; 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 14669578Ssam #ifndef vax 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