1*8556Sroot /* tty.c 4.31 82/10/17 */ 239Sbill 339Sbill /* 4903Sbill * TTY subroutines common to more than one line discipline 539Sbill */ 639Sbill #include "../h/param.h" 739Sbill #include "../h/systm.h" 839Sbill #include "../h/dir.h" 939Sbill #include "../h/user.h" 1039Sbill #include "../h/tty.h" 1139Sbill #include "../h/proc.h" 1239Sbill #include "../h/inode.h" 1339Sbill #include "../h/file.h" 1439Sbill #include "../h/reg.h" 1539Sbill #include "../h/conf.h" 1639Sbill #include "../h/buf.h" 17340Sbill #include "../h/dk.h" 187722Swnj #include "../h/uio.h" 198154Sroot #include "../h/kernel.h" 2039Sbill 217436Skre /* 227436Skre * Table giving parity for characters and indicating 237436Skre * character classes to tty driver. In particular, 247436Skre * if the low 6 bits are 0, then the character needs 257436Skre * no special processing on output. 267436Skre */ 2739Sbill 287436Skre char partab[] = { 297436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 307436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 317436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 327436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 337436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 347436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 357436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 367436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 377436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 387436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 397436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 407436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 417436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 427436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 437436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 447436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 457436Skre 467436Skre /* 477436Skre * 7 bit ascii ends with the last character above, 487436Skre * but we contine through all 256 codes for the sake 497436Skre * of the tty output routines which use special vax 507436Skre * instructions which need a 256 character trt table. 517436Skre */ 527436Skre 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 0007,0007,0007,0007,0007,0007,0007,0007 697436Skre }; 707436Skre 71146Sbill /* 7239Sbill * Input mapping table-- if an entry is non-zero, when the 7339Sbill * corresponding character is typed preceded by "\" the escape 7439Sbill * sequence is replaced by the table value. Mostly used for 7539Sbill * upper-case only terminals. 7639Sbill */ 7739Sbill 7839Sbill char maptab[] ={ 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,000,000, 8239Sbill 000,000,000,000,000,000,000,000, 8339Sbill 000,'|',000,000,000,000,000,'`', 8439Sbill '{','}',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,000, 8939Sbill 000,000,000,000,000,000,000,000, 9039Sbill 000,000,000,000,000,000,'~',000, 9139Sbill 000,'A','B','C','D','E','F','G', 9239Sbill 'H','I','J','K','L','M','N','O', 9339Sbill 'P','Q','R','S','T','U','V','W', 9439Sbill 'X','Y','Z',000,000,000,000,000, 9539Sbill }; 9639Sbill 97925Sbill short tthiwat[16] = 98925Sbill { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 99925Sbill short ttlowat[16] = 100925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 101925Sbill 10239Sbill #define OBUFSIZ 100 10339Sbill 10439Sbill /* 10539Sbill * set default control characters. 10639Sbill */ 10739Sbill ttychars(tp) 1087625Ssam register struct tty *tp; 10939Sbill { 110174Sbill 11139Sbill tun.t_intrc = CINTR; 11239Sbill tun.t_quitc = CQUIT; 11339Sbill tun.t_startc = CSTART; 11439Sbill tun.t_stopc = CSTOP; 11539Sbill tun.t_eofc = CEOT; 11639Sbill tun.t_brkc = CBRK; 11739Sbill tp->t_erase = CERASE; 11839Sbill tp->t_kill = CKILL; 119174Sbill /* begin local */ 120208Sbill tlun.t_suspc = CTRL(z); 121208Sbill tlun.t_dsuspc = CTRL(y); 122174Sbill tlun.t_rprntc = CTRL(r); 123174Sbill tlun.t_flushc = CTRL(o); 124174Sbill tlun.t_werasc = CTRL(w); 125174Sbill tlun.t_lnextc = CTRL(v); 126174Sbill tp->t_local = 0; 127174Sbill tp->t_lstate = 0; 128174Sbill /* end local */ 12939Sbill } 13039Sbill 13139Sbill /* 132903Sbill * Wait for output to drain, then flush input waiting. 13339Sbill */ 134903Sbill wflushtty(tp) 1355408Swnj register struct tty *tp; 13639Sbill { 13739Sbill 138903Sbill (void) spl5(); 1395622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1405622Swnj && tp->t_oproc) { /* kludge for pty */ 141903Sbill (*tp->t_oproc)(tp); 1425408Swnj tp->t_state |= TS_ASLEEP; 143903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 144903Sbill } 1455426Swnj flushtty(tp, FREAD); 146903Sbill (void) spl0(); 14739Sbill } 14839Sbill 14939Sbill /* 150903Sbill * flush all TTY queues 15139Sbill */ 152903Sbill flushtty(tp, rw) 1537625Ssam register struct tty *tp; 15439Sbill { 155903Sbill register s; 156903Sbill 157903Sbill s = spl6(); 158903Sbill if (rw & FREAD) { 159903Sbill while (getc(&tp->t_canq) >= 0) 160903Sbill ; 161903Sbill wakeup((caddr_t)&tp->t_rawq); 162903Sbill } 163903Sbill if (rw & FWRITE) { 164903Sbill wakeup((caddr_t)&tp->t_outq); 1655408Swnj tp->t_state &= ~TS_TTSTOP; 1665426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 167903Sbill while (getc(&tp->t_outq) >= 0) 168903Sbill ; 169903Sbill } 170903Sbill if (rw & FREAD) { 171903Sbill while (getc(&tp->t_rawq) >= 0) 172903Sbill ; 173903Sbill tp->t_delct = 0; 174903Sbill tp->t_rocount = 0; /* local */ 175903Sbill tp->t_rocol = 0; 176903Sbill tp->t_lstate = 0; 177903Sbill } 178903Sbill splx(s); 17939Sbill } 18039Sbill 181903Sbill /* 182903Sbill * Send stop character on input overflow. 183903Sbill */ 184903Sbill ttyblock(tp) 1857625Ssam register struct tty *tp; 18639Sbill { 187903Sbill register x; 188903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 189903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 190903Sbill flushtty(tp, FREAD|FWRITE); 1915408Swnj tp->t_state &= ~TS_TBLOCK; 192903Sbill } 193903Sbill if (x >= TTYHOG/2) { 194903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 1955408Swnj tp->t_state |= TS_TBLOCK; 196903Sbill tp->t_char++; 197903Sbill ttstart(tp); 198903Sbill } 199903Sbill } 20039Sbill } 20139Sbill 20239Sbill /* 203903Sbill * Restart typewriter output following a delay 204903Sbill * timeout. 205903Sbill * The name of the routine is passed to the timeout 206903Sbill * subroutine and it is called during a clock interrupt. 207121Sbill */ 208903Sbill ttrstrt(tp) 2097625Ssam register struct tty *tp; 210121Sbill { 211121Sbill 2123351Swnj if (tp == 0) { 2133351Swnj printf("ttrstrt: arg was 0!\n"); 2143351Swnj return; 2153351Swnj } 2165408Swnj tp->t_state &= ~TS_TIMEOUT; 217903Sbill ttstart(tp); 218121Sbill } 219121Sbill 220121Sbill /* 221903Sbill * Start output on the typewriter. It is used from the top half 222903Sbill * after some characters have been put on the output queue, 223903Sbill * from the interrupt routine to transmit the next 224903Sbill * character, and after a timeout has finished. 22539Sbill */ 226903Sbill ttstart(tp) 2277625Ssam register struct tty *tp; 22839Sbill { 229903Sbill register s; 23039Sbill 231903Sbill s = spl5(); 2327625Ssam if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2335622Swnj tp->t_oproc) /* kludge for pty */ 234903Sbill (*tp->t_oproc)(tp); 235903Sbill splx(s); 23639Sbill } 23739Sbill 23839Sbill /* 239903Sbill * Common code for tty ioctls. 24039Sbill */ 2411780Sbill /*ARGSUSED*/ 2427625Ssam ttioctl(tp, com, data, flag) 2437625Ssam register struct tty *tp; 2447625Ssam caddr_t data; 24539Sbill { 2468520Sroot int dev = tp->t_dev; 24739Sbill extern int nldisp; 248*8556Sroot int s; 24939Sbill 250903Sbill /* 251903Sbill * If the ioctl involves modification, 252903Sbill * insist on being able to write the device, 253903Sbill * and hang if in the background. 254903Sbill */ 2557625Ssam switch (com) { 25639Sbill 257915Sbill case TIOCSETD: 258915Sbill case TIOCSETP: 259915Sbill case TIOCSETN: 260903Sbill case TIOCFLUSH: 261903Sbill case TIOCSETC: 262903Sbill case TIOCSLTC: 263903Sbill case TIOCSPGRP: 264903Sbill case TIOCLBIS: 265903Sbill case TIOCLBIC: 266903Sbill case TIOCLSET: 267903Sbill while (tp->t_line == NTTYDISC && 268903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 269903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 270903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 271*8556Sroot u.u_signal[SIGTTOU] != SIG_HOLD) { 272903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 273903Sbill sleep((caddr_t)&lbolt, TTOPRI); 274903Sbill } 275903Sbill break; 276903Sbill } 277903Sbill 2787625Ssam switch (com) { 279903Sbill 280*8556Sroot /* get discipline number */ 28139Sbill case TIOCGETD: 2827625Ssam *(int *)data = tp->t_line; 28339Sbill break; 28439Sbill 285*8556Sroot /* set line discipline */ 2867625Ssam case TIOCSETD: { 2877625Ssam register int t = *(int *)data; 288*8556Sroot int error; 2897625Ssam 290*8556Sroot if (t >= nldisp) 291*8556Sroot return (ENXIO); 292*8556Sroot s = spl5(); 29339Sbill if (tp->t_line) 29439Sbill (*linesw[tp->t_line].l_close)(tp); 29539Sbill if (t) 296*8556Sroot error = (*linesw[t].l_open)(dev, tp); 297*8556Sroot splx(s); 298*8556Sroot if (error) 299*8556Sroot return (error); 300*8556Sroot tp->t_line = t; 30139Sbill break; 3027625Ssam } 30339Sbill 304*8556Sroot /* prevent more opens on channel */ 3055614Swnj case TIOCEXCL: 3065614Swnj tp->t_state |= TS_XCLUDE; 3075614Swnj break; 3085614Swnj 3095614Swnj case TIOCNXCL: 3105614Swnj tp->t_state &= ~TS_XCLUDE; 3115614Swnj break; 3125614Swnj 313*8556Sroot /* set new parameters */ 31439Sbill case TIOCSETP: 3157625Ssam case TIOCSETN: { 3167625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3177625Ssam struct clist tq; 3187625Ssam 319121Sbill (void) spl5(); 3207625Ssam if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP) 3214484Swnj wflushtty(tp); 3227625Ssam else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) { 3237625Ssam if (sg->sg_flags & CBREAK) { 3244484Swnj catq(&tp->t_rawq, &tp->t_canq); 3254484Swnj tq = tp->t_rawq; 3264484Swnj tp->t_rawq = tp->t_canq; 3274484Swnj tp->t_canq = tq; 3284484Swnj } else { 3294484Swnj tp->t_local |= LPENDIN; 3304484Swnj ttwakeup(tp); 331174Sbill } 332174Sbill } 3337625Ssam tp->t_ispeed = sg->sg_ispeed; 3347625Ssam tp->t_ospeed = sg->sg_ospeed; 3357625Ssam tp->t_erase = sg->sg_erase; 3367625Ssam tp->t_kill = sg->sg_kill; 3377625Ssam tp->t_flags = sg->sg_flags; 3383941Sbugs if (tp->t_flags & RAW) { 3395408Swnj tp->t_state &= ~TS_TTSTOP; 3403941Sbugs ttstart(tp); 3413941Sbugs } 342121Sbill (void) spl0(); 34339Sbill break; 3447625Ssam } 34539Sbill 346*8556Sroot /* send current parameters to user */ 3477625Ssam case TIOCGETP: { 3487625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3497625Ssam 3507625Ssam sg->sg_ispeed = tp->t_ispeed; 3517625Ssam sg->sg_ospeed = tp->t_ospeed; 3527625Ssam sg->sg_erase = tp->t_erase; 3537625Ssam sg->sg_kill = tp->t_kill; 3547625Ssam sg->sg_flags = tp->t_flags; 35539Sbill break; 3567625Ssam } 35739Sbill 358*8556Sroot /* hang up line on last close */ 35939Sbill case TIOCHPCL: 3605408Swnj tp->t_state |= TS_HUPCLS; 36139Sbill break; 36239Sbill 3633942Sbugs case TIOCFLUSH: { 3647625Ssam register int flags = *(int *)data; 3657625Ssam 3667625Ssam if (flags == 0) 3673942Sbugs flags = FREAD|FWRITE; 3687625Ssam else 3697625Ssam flags &= FREAD|FWRITE; 3703942Sbugs flushtty(tp, flags); 37139Sbill break; 3723944Sbugs } 37339Sbill 3747625Ssam case FIONBIO: 3757625Ssam if (*(int *)data) 3765408Swnj tp->t_state |= TS_NBIO; 3775408Swnj else 3785408Swnj tp->t_state &= ~TS_NBIO; 3795408Swnj break; 3805408Swnj 3817625Ssam case FIOASYNC: 3827625Ssam if (*(int *)data) 3836216Swnj tp->t_state |= TS_ASYNC; 3846216Swnj else 3856216Swnj tp->t_state &= ~TS_ASYNC; 3866216Swnj break; 3876216Swnj 388*8556Sroot /* set and fetch special characters */ 38939Sbill case TIOCSETC: 3907625Ssam bcopy(data, (caddr_t)&tun, sizeof (struct tchars)); 39139Sbill break; 39239Sbill 39339Sbill case TIOCGETC: 3947625Ssam bcopy((caddr_t)&tun, data, sizeof (struct tchars)); 39539Sbill break; 39639Sbill 397*8556Sroot /* set/get local special characters */ 398174Sbill case TIOCSLTC: 3997625Ssam bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars)); 400174Sbill break; 401174Sbill 402174Sbill case TIOCGLTC: 4037625Ssam bcopy((caddr_t)&tlun, data, sizeof (struct ltchars)); 404174Sbill break; 405174Sbill 406*8556Sroot /* return number of characters immediately available */ 4077625Ssam case FIONREAD: 4087625Ssam *(off_t *)data = ttnread(tp); 409174Sbill break; 410174Sbill 411*8556Sroot /* should allow SPGRP and GPGRP only if tty open for reading */ 412174Sbill case TIOCSPGRP: 4137625Ssam tp->t_pgrp = *(int *)data; 414174Sbill break; 415174Sbill 416174Sbill case TIOCGPGRP: 4177625Ssam *(int *)data = tp->t_pgrp; 418174Sbill break; 419174Sbill 420*8556Sroot /* Modify local mode word */ 421174Sbill case TIOCLBIS: 4227625Ssam tp->t_local |= *(int *)data; 423174Sbill break; 424174Sbill 425174Sbill case TIOCLBIC: 4267625Ssam tp->t_local &= ~(*(int *)data); 427174Sbill break; 428174Sbill 429174Sbill case TIOCLSET: 4307625Ssam tp->t_local = *(int *)data; 431174Sbill break; 432174Sbill 433174Sbill case TIOCLGET: 4347625Ssam *(int *)data = tp->t_local; 435174Sbill break; 436174Sbill 4377625Ssam case TIOCSTOP: { 4387625Ssam int s = spl5(); 439213Sbill 4405573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4415573Swnj tp->t_state |= TS_TTSTOP; 4425573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4435573Swnj } 4447625Ssam splx(s); 4455573Swnj break; 4467625Ssam } 4475573Swnj 4487625Ssam case TIOCSTART: { 4497625Ssam int s = spl5(); 4507625Ssam 4515573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4525573Swnj tp->t_state &= ~TS_TTSTOP; 4535573Swnj tp->t_local &= ~LFLUSHO; 4545573Swnj ttstart(tp); 4555573Swnj } 4567625Ssam splx(s); 4575573Swnj break; 4587625Ssam } 4595573Swnj 46039Sbill default: 461*8556Sroot return (-1); 46239Sbill } 463*8556Sroot return (0); 46439Sbill } 4654484Swnj 4664484Swnj ttnread(tp) 4674484Swnj struct tty *tp; 4684484Swnj { 4694484Swnj int nread = 0; 4704484Swnj 4714484Swnj if (tp->t_local & LPENDIN) 4724484Swnj ttypend(tp); 4734484Swnj nread = tp->t_canq.c_cc; 4744484Swnj if (tp->t_flags & (RAW|CBREAK)) 4754484Swnj nread += tp->t_rawq.c_cc; 4764484Swnj return (nread); 4774484Swnj } 4784484Swnj 4795408Swnj ttselect(dev, rw) 4804484Swnj dev_t dev; 4815408Swnj int rw; 4824484Swnj { 4834484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4844484Swnj int nread; 4855408Swnj int s = spl5(); 4864484Swnj 4875408Swnj switch (rw) { 4884484Swnj 4894484Swnj case FREAD: 4904484Swnj nread = ttnread(tp); 4914484Swnj if (nread > 0) 4925408Swnj goto win; 4934938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 4945408Swnj tp->t_state |= TS_RCOLL; 4954484Swnj else 4964484Swnj tp->t_rsel = u.u_procp; 4975408Swnj break; 4984484Swnj 4995408Swnj case FWRITE: 5005408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5015408Swnj goto win; 5025408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5035408Swnj tp->t_state |= TS_WCOLL; 5045408Swnj else 5055408Swnj tp->t_wsel = u.u_procp; 5065408Swnj break; 5074484Swnj } 5085408Swnj splx(s); 5095408Swnj return (0); 5105408Swnj win: 5115408Swnj splx(s); 5125408Swnj return (1); 5134484Swnj } 5147436Skre 5157502Sroot #define OBUFSIZ 100 5167502Sroot 5177502Sroot /* 5187502Sroot * routine called on opens while tp->t_line == NTTYDISC 5197502Sroot * establishes a process group for distribution of 5207502Sroot * quits and interrupts from the tty. 5217502Sroot * (actually, pp->p_pgrp can't be 0 when this routine 5227502Sroot * is called since NTTYDISC is not the default discipline) 5237502Sroot */ 5247502Sroot ttyopen(dev, tp) 5257625Ssam dev_t dev; 5267625Ssam register struct tty *tp; 5277502Sroot { 5287502Sroot register struct proc *pp; 5297502Sroot 5307502Sroot pp = u.u_procp; 5317502Sroot tp->t_dev = dev; 5327625Ssam if (pp->p_pgrp == 0) { 5337502Sroot u.u_ttyp = tp; 5347502Sroot u.u_ttyd = dev; 5357502Sroot if (tp->t_pgrp == 0) 5367502Sroot tp->t_pgrp = pp->p_pid; 5377502Sroot pp->p_pgrp = tp->t_pgrp; 5387502Sroot } 5397502Sroot tp->t_state &= ~TS_WOPEN; 5407502Sroot tp->t_state |= TS_ISOPEN; 5417502Sroot if (tp->t_line != NTTYDISC) 5427502Sroot wflushtty(tp); 543*8556Sroot return (0); 5447502Sroot } 5457502Sroot 5467502Sroot /* 5477502Sroot * clean tp on last close 5487502Sroot */ 5497502Sroot ttyclose(tp) 5507625Ssam register struct tty *tp; 5517502Sroot { 5527502Sroot 5537502Sroot if (tp->t_line) { 5547502Sroot wflushtty(tp); 5557502Sroot tp->t_line = 0; 5567502Sroot return; 5577502Sroot } 5587502Sroot tp->t_pgrp = 0; 5597502Sroot wflushtty(tp); 5607502Sroot tp->t_state = 0; 5617502Sroot } 5627502Sroot 5637502Sroot /* 5647502Sroot * reinput pending characters after state switch 5657502Sroot * call at spl5(). 5667502Sroot */ 5677502Sroot ttypend(tp) 5687625Ssam register struct tty *tp; 5697502Sroot { 5707502Sroot struct clist tq; 5717502Sroot register c; 5727502Sroot 5737502Sroot tp->t_local &= ~LPENDIN; 5747502Sroot tp->t_lstate |= LSTYPEN; 5757502Sroot tq = tp->t_rawq; 5767502Sroot tp->t_rawq.c_cc = 0; 5777502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5787502Sroot while ((c = getc(&tq)) >= 0) 5797502Sroot ttyinput(c, tp); 5807502Sroot tp->t_lstate &= ~LSTYPEN; 5817502Sroot } 5827502Sroot 5837502Sroot /* 5847502Sroot * Place a character on raw TTY input queue, putting in delimiters 5857502Sroot * and waking up top half as needed. 5867502Sroot * Also echo if required. 5877502Sroot * The arguments are the character and the appropriate 5887502Sroot * tty structure. 5897502Sroot */ 5907502Sroot ttyinput(c, tp) 5917625Ssam register c; 5927625Ssam register struct tty *tp; 5937502Sroot { 5947502Sroot register int t_flags; 5957502Sroot int i; 5967502Sroot 5977502Sroot if (tp->t_local&LPENDIN) 5987502Sroot ttypend(tp); 5997502Sroot tk_nin++; 6007502Sroot c &= 0377; 6017502Sroot t_flags = tp->t_flags; 6027502Sroot if (t_flags&TANDEM) 6037502Sroot ttyblock(tp); 6047502Sroot if ((t_flags&RAW)==0) { 6057502Sroot if ((tp->t_lstate&LSTYPEN) == 0) 6067502Sroot c &= 0177; 6077502Sroot /* check for literal nexting very first */ 6087502Sroot if (tp->t_lstate&LSLNCH) { 6097502Sroot c |= 0200; 6107502Sroot tp->t_lstate &= ~LSLNCH; 6117502Sroot } 6127502Sroot if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) { 6137502Sroot if (tp->t_flags&ECHO) 6147502Sroot ttyout("^\b", tp); 6157502Sroot tp->t_lstate |= LSLNCH; 6167502Sroot /* check for output control functions */ 6177502Sroot } else if (c==tun.t_stopc) { 6187502Sroot if ((tp->t_state&TS_TTSTOP)==0) { 6197502Sroot tp->t_state |= TS_TTSTOP; 6207502Sroot (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6217502Sroot return; 6227502Sroot } 6237502Sroot if (c!=tun.t_startc) 6247502Sroot return; 6257502Sroot } else if (c==tun.t_startc) { 6267502Sroot tp->t_state &= ~TS_TTSTOP; 6277502Sroot tp->t_local &= ~LFLUSHO; 6287502Sroot ttstart(tp); 6297502Sroot return; 6307502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) { 6317502Sroot if (tp->t_local & LFLUSHO) 6327502Sroot tp->t_local &= ~LFLUSHO; 6337502Sroot else { 6347502Sroot flushtty(tp, FWRITE); 6357502Sroot ttyecho(c, tp); 6367502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc) 6377502Sroot ttyretype(tp); 6387502Sroot tp->t_local |= LFLUSHO; 6397502Sroot } 6407502Sroot ttstart(tp); 6417502Sroot return; 6427502Sroot } else if (c==tun.t_intrc || c==tun.t_quitc || 6437502Sroot (tp->t_line == NTTYDISC && c==tlun.t_suspc)) { 6447502Sroot if ((tp->t_local & LNOFLSH) == 0) 6457502Sroot flushtty(tp, 6467502Sroot c==tlun.t_suspc ? FREAD : FREAD|FWRITE); 6477502Sroot ttyecho(c, tp); 6487502Sroot c = c==tun.t_intrc ? SIGINT : 6497502Sroot ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP); 6507502Sroot ttsignal(tp, c); 6517502Sroot /* check for buffer editing functions - cooked mode */ 6527502Sroot } else if ((t_flags&CBREAK) == 0) { 6537502Sroot if ((tp->t_lstate&LSQUOT) && 6547502Sroot (c==tp->t_erase||c==tp->t_kill)) { 6557502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6567502Sroot c |= 0200; 6577502Sroot } 6587502Sroot if (c==tp->t_erase) { 6597502Sroot if (tp->t_rawq.c_cc) 6607502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6617502Sroot } else if (c==tp->t_kill) { 6627502Sroot if (tp->t_local&LCRTKIL && 6637502Sroot tp->t_rawq.c_cc == tp->t_rocount) { 6647502Sroot while (tp->t_rawq.c_cc) 6657502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6667502Sroot } else { 6677502Sroot ttyecho(c, tp); 6687502Sroot ttyecho('\n', tp); 6697502Sroot while (getc(&tp->t_rawq) > 0) 6707502Sroot ; 6717502Sroot tp->t_rocount = 0; 6727502Sroot } 6737502Sroot tp->t_lstate = 0; 6747502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) { 6757502Sroot if (tp->t_rawq.c_cc == 0) 6767502Sroot goto out; 6777502Sroot do { 6787502Sroot c = unputc(&tp->t_rawq); 6797502Sroot if (c != ' ' && c != '\t') 6807502Sroot goto erasenb; 6817502Sroot ttyrub(c, tp); 6827502Sroot } while (tp->t_rawq.c_cc); 6837502Sroot goto out; 6847502Sroot erasenb: 6857502Sroot do { 6867502Sroot ttyrub(c, tp); 6877502Sroot if (tp->t_rawq.c_cc == 0) 6887502Sroot goto out; 6897502Sroot c = unputc(&tp->t_rawq); 6907502Sroot } while (c != ' ' && c != '\t'); 6917502Sroot (void) putc(c, &tp->t_rawq); 6927502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) { 6937502Sroot ttyretype(tp); 6947502Sroot /* check for cooked mode input buffer overflow */ 6957502Sroot } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 6967502Sroot ; 6977502Sroot /* put data char in q for user and wakeup if a break char */ 6987502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 6997502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG 7007502Sroot && tp->t_line == NTTYDISC) 7017502Sroot (void) ttyoutput(CTRL(g), tp); 7027502Sroot if (!ttbreakc(c, tp)) { 7037502Sroot if (tp->t_rocount++ == 0) 7047502Sroot tp->t_rocol = tp->t_col; 7057502Sroot } else { 7067502Sroot tp->t_rocount = 0; 7077502Sroot catq(&tp->t_rawq, &tp->t_canq); 7087502Sroot /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */ 7097502Sroot ttwakeup(tp); 7107502Sroot } 7117502Sroot tp->t_lstate &= ~LSQUOT; 7127502Sroot if (c == '\\') 7137502Sroot tp->t_lstate |= LSQUOT; 7147502Sroot if (tp->t_lstate&LSERASE) { 7157502Sroot tp->t_lstate &= ~LSERASE; 7167502Sroot (void) ttyoutput('/', tp); 7177502Sroot } 7187502Sroot i = tp->t_col; 7197502Sroot ttyecho(c, tp); 7207502Sroot if (c==tun.t_eofc && tp->t_flags&ECHO) { 7217502Sroot i = MIN(2, tp->t_col - i); 7227502Sroot while (i > 0) { 7237502Sroot (void) ttyoutput('\b', tp); 7247502Sroot i--; 7257502Sroot } 7267502Sroot } 7277502Sroot } 7287502Sroot /* CBREAK mode */ 7297502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) { 7307502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7317502Sroot tp->t_line == NTTYDISC) 7327502Sroot (void) ttyoutput(CTRL(g), tp); 7337502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7347502Sroot ttwakeup(tp); 7357502Sroot ttyecho(c, tp); 7367502Sroot } 7377502Sroot /* RAW mode */ 7387502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) 7397502Sroot flushtty(tp, FREAD|FWRITE); 7407502Sroot else { 7417502Sroot if (putc(c, &tp->t_rawq) >= 0) 7427502Sroot ttwakeup(tp); 7437502Sroot ttyecho(c, tp); 7447502Sroot } 7457502Sroot out: 7467502Sroot if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP && 7477502Sroot tun.t_startc != tun.t_stopc) 7487502Sroot return; 7497502Sroot tp->t_state &= ~TS_TTSTOP; 7507502Sroot tp->t_local &= ~LFLUSHO; 7517502Sroot ttstart(tp); 7527502Sroot } 7537502Sroot 7547502Sroot /* 7557502Sroot * put character on TTY output queue, adding delays, 7567502Sroot * expanding tabs, and handling the CR/NL bit. 7577502Sroot * It is called both from the top half for output, and from 7587502Sroot * interrupt level for echoing. 7597502Sroot * The arguments are the character and the tty structure. 7607502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 7617502Sroot * Must be recursive. 7627502Sroot */ 7637502Sroot ttyoutput(c, tp) 7647502Sroot register c; 7657502Sroot register struct tty *tp; 7667502Sroot { 7677502Sroot register char *colp; 7687502Sroot register ctype; 7697502Sroot 7707502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) { 7717502Sroot if (tp->t_local&LFLUSHO) 7727502Sroot return (-1); 7737502Sroot if (putc(c, &tp->t_outq)) 7747625Ssam return (c); 7757502Sroot tk_nout++; 7767502Sroot return (-1); 7777502Sroot } 7787502Sroot /* 7797502Sroot * Ignore EOT in normal mode to avoid hanging up 7807502Sroot * certain terminals. 7817502Sroot */ 7827502Sroot c &= 0177; 7837502Sroot if (c==CEOT && (tp->t_flags&CBREAK)==0) 7847502Sroot return (-1); 7857502Sroot /* 7867502Sroot * Turn tabs to spaces as required 7877502Sroot */ 7887502Sroot if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 7897502Sroot register int s; 7907502Sroot 7917502Sroot c = 8 - (tp->t_col&7); 7927502Sroot if ((tp->t_local&LFLUSHO) == 0) { 7937502Sroot s = spl5(); /* don't interrupt tabs */ 7947502Sroot c -= b_to_q(" ", c, &tp->t_outq); 7957502Sroot tk_nout += c; 7967502Sroot splx(s); 7977502Sroot } 7987502Sroot tp->t_col += c; 7997502Sroot return (c ? -1 : '\t'); 8007502Sroot } 8017502Sroot tk_nout++; 8027502Sroot /* 8037502Sroot * for upper-case-only terminals, 8047502Sroot * generate escapes. 8057502Sroot */ 8067502Sroot if (tp->t_flags&LCASE) { 8077502Sroot colp = "({)}!|^~'`"; 8087625Ssam while (*colp++) 8097625Ssam if (c == *colp++) { 8107502Sroot if (ttyoutput('\\', tp) >= 0) 8117502Sroot return (c); 8127502Sroot c = colp[-2]; 8137502Sroot break; 8147502Sroot } 8157502Sroot if ('A'<=c && c<='Z') { 8167502Sroot if (ttyoutput('\\', tp) >= 0) 8177502Sroot return (c); 8187502Sroot } else if ('a'<=c && c<='z') 8197502Sroot c += 'A' - 'a'; 8207502Sroot } 8217502Sroot /* 8227502Sroot * turn <nl> to <cr><lf> if desired. 8237502Sroot */ 8247502Sroot if (c=='\n' && tp->t_flags&CRMOD) 8257502Sroot if (ttyoutput('\r', tp) >= 0) 8267502Sroot return (c); 8277502Sroot if (c=='~' && tp->t_local<ILDE) 8287502Sroot c = '`'; 8297502Sroot if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq)) 8307502Sroot return (c); 8317502Sroot /* 8327502Sroot * Calculate delays. 8337502Sroot * The numbers here represent clock ticks 8347502Sroot * and are not necessarily optimal for all terminals. 8357502Sroot * The delays are indicated by characters above 0200. 8367502Sroot * In raw mode there are no delays and the 8377502Sroot * transmission path is 8 bits wide. 8387502Sroot */ 8397502Sroot colp = &tp->t_col; 8407502Sroot ctype = partab[c]; 8417502Sroot c = 0; 8427502Sroot switch (ctype&077) { 8437502Sroot 8447502Sroot case ORDINARY: 8457502Sroot (*colp)++; 8467502Sroot 8477502Sroot case CONTROL: 8487502Sroot break; 8497502Sroot 8507502Sroot case BACKSPACE: 8517502Sroot if (*colp) 8527502Sroot (*colp)--; 8537502Sroot break; 8547502Sroot 8557502Sroot case NEWLINE: 8567502Sroot ctype = (tp->t_flags >> 8) & 03; 8577625Ssam if (ctype == 1) { /* tty 37 */ 8587502Sroot if (*colp) 8597502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 8607502Sroot } else 8617625Ssam if (ctype == 2) { /* vt05 */ 8627502Sroot c = 6; 8637502Sroot } 8647502Sroot *colp = 0; 8657502Sroot break; 8667502Sroot 8677502Sroot case TAB: 8687502Sroot ctype = (tp->t_flags >> 10) & 03; 8697625Ssam if (ctype == 1) { /* tty 37 */ 8707502Sroot c = 1 - (*colp | ~07); 8717625Ssam if (c < 5) 8727502Sroot c = 0; 8737502Sroot } 8747502Sroot *colp |= 07; 8757502Sroot (*colp)++; 8767502Sroot break; 8777502Sroot 8787502Sroot case VTAB: 8797625Ssam if (tp->t_flags & VTDELAY) /* tty 37 */ 8807502Sroot c = 0177; 8817502Sroot break; 8827502Sroot 8837502Sroot case RETURN: 8847502Sroot ctype = (tp->t_flags >> 12) & 03; 8857625Ssam if (ctype == 1) { /* tn 300 */ 8867502Sroot c = 5; 8877625Ssam } else if (ctype == 2) { /* ti 700 */ 8887502Sroot c = 10; 8897625Ssam } else if (ctype == 3) { /* concept 100 */ 8907502Sroot int i; 8917502Sroot if ((i = *colp) >= 0) 8927502Sroot for (; i<9; i++) 8937502Sroot (void) putc(0177, &tp->t_outq); 8947502Sroot } 8957502Sroot *colp = 0; 8967502Sroot } 8977625Ssam if (c && (tp->t_local&LFLUSHO) == 0) 8987502Sroot (void) putc(c|0200, &tp->t_outq); 8997502Sroot return (-1); 9007502Sroot } 9017502Sroot 9027502Sroot /* 9037502Sroot * Called from device's read routine after it has 9047502Sroot * calculated the tty-structure given as argument. 9057502Sroot */ 9067722Swnj ttread(tp, uio) 9077625Ssam register struct tty *tp; 9087722Swnj struct uio *uio; 9097502Sroot { 9107502Sroot register struct clist *qp; 9117502Sroot register c, first; 9128520Sroot int error = 0; 9137502Sroot 9147502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9158520Sroot return (EIO); 9167502Sroot loop: 9177502Sroot (void) spl5(); 9187502Sroot if (tp->t_local&LPENDIN) 9197502Sroot ttypend(tp); 9207502Sroot (void) spl0(); 9217502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9227502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9237502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9247502Sroot /* 9257502Sroot (u.u_procp->p_flag&SDETACH) || 9267502Sroot */ 9277502Sroot u.u_procp->p_flag&SVFORK) 9288520Sroot return (EIO); 9297502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9307502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9317502Sroot } 9327502Sroot if (tp->t_flags&RAW) { 9337502Sroot (void) spl5(); 9347502Sroot if (tp->t_rawq.c_cc <= 0) { 9357502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9367502Sroot (tp->t_state&TS_NBIO)) { 9377502Sroot (void) spl0(); 9388520Sroot return (EWOULDBLOCK); 9397502Sroot } 9407502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9417502Sroot (void) spl0(); 9427502Sroot goto loop; 9437502Sroot } 9447502Sroot (void) spl0(); 9457722Swnj while (tp->t_rawq.c_cc && uio->uio_iovcnt) { 9468520Sroot error = passuc(getc(&tp->t_rawq), uio); 9478520Sroot if (error) 9487722Swnj break; 9497722Swnj } 9508520Sroot return (error); 9517502Sroot } else { 9527502Sroot qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq; 9537502Sroot (void) spl5(); 9547502Sroot if (qp->c_cc <= 0) { 9557502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9567502Sroot (tp->t_state&TS_NBIO)) { 9577502Sroot (void) spl0(); 9588520Sroot return (EWOULDBLOCK); 9597502Sroot } 9607502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9617502Sroot (void) spl0(); 9627502Sroot goto loop; 9637502Sroot } 9647502Sroot (void) spl0(); 9657502Sroot first = 1; 9667502Sroot while ((c = getc(qp)) >= 0) { 9677502Sroot if (tp->t_flags&CRMOD && c == '\r') 9687502Sroot c = '\n'; 9697502Sroot if (tp->t_flags&LCASE && c <= 0177) 9707502Sroot if (tp->t_lstate&LSBKSL) { 9717502Sroot if (maptab[c]) 9727502Sroot c = maptab[c]; 9737502Sroot tp->t_lstate &= ~LSBKSL; 9747502Sroot } else if (c >= 'A' && c <= 'Z') 9757502Sroot c += 'a' - 'A'; 9767502Sroot else if (c == '\\') { 9777502Sroot tp->t_lstate |= LSBKSL; 9787502Sroot continue; 9797502Sroot } 9807658Ssam if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) { 9817502Sroot ttsignal(tp, SIGTSTP); 9827502Sroot if (first) { 9837502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9847502Sroot goto loop; 9857502Sroot } 9867502Sroot break; 9877502Sroot } 9887502Sroot if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0) 9897502Sroot break; 9908520Sroot error = passuc(c & 0177, uio); 9918520Sroot if (error) 9927502Sroot break; 9937722Swnj if (uio->uio_iovcnt == 0) 9947722Swnj break; 9957502Sroot if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp)) 9967502Sroot break; 9977502Sroot first = 0; 9987502Sroot } 9997502Sroot tp->t_lstate &= ~LSBKSL; 10007502Sroot } 10017502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 10027502Sroot if (putc(tun.t_startc, &tp->t_outq)==0) { 10037502Sroot tp->t_state &= ~TS_TBLOCK; 10047502Sroot ttstart(tp); 10057502Sroot } 10067502Sroot tp->t_char = 0; 10077502Sroot } 10088520Sroot return (error); 10097502Sroot } 10107502Sroot 10117502Sroot /* 10127502Sroot * Called from the device's write routine after it has 10137502Sroot * calculated the tty-structure given as argument. 10147502Sroot */ 10157822Sroot ttwrite(tp, uio) 10167625Ssam register struct tty *tp; 10177822Sroot struct uio *uio; 10187502Sroot { 10197502Sroot #ifdef vax 10207502Sroot /* 10217502Sroot * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 10227502Sroot * AND MUST NOT BE CHANGED WITHOUT PATCHING 10237502Sroot * THE 'ASM' INLINES BELOW. WATCH OUT. 10247502Sroot */ 10257502Sroot #endif 10267502Sroot register char *cp; 10277502Sroot register int cc, ce; 10287502Sroot register i; 10297502Sroot char obuf[OBUFSIZ]; 10307502Sroot register c; 10317502Sroot int hiwat = TTHIWAT(tp); 10327822Sroot int cnt = uio->uio_resid; 10338520Sroot int error = 0; 10347502Sroot 10357502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10368520Sroot return (EIO); 10377502Sroot loop: 10387502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 10397502Sroot (tp->t_local<OSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 10407502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 10417502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 10427502Sroot /* 10437502Sroot && 10447502Sroot (u.u_procp->p_flag&SDETACH)==0) { 10457502Sroot */ 10467502Sroot ) { 10477502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 10487502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10497502Sroot } 10507822Sroot while (uio->uio_resid > 0) { 10517822Sroot cc = uio->uio_iov->iov_len; 10527822Sroot if (cc == 0) { 10537822Sroot uio->uio_iovcnt--; 10547822Sroot uio->uio_iov++; 10557822Sroot if (uio->uio_iovcnt < 0) 10567822Sroot panic("ttwrite"); 10577822Sroot continue; 10587822Sroot } 10597822Sroot if (cc > OBUFSIZ) 10607822Sroot cc = OBUFSIZ; 10617502Sroot cp = obuf; 10628520Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 10638520Sroot if (error) 10647502Sroot break; 10657502Sroot if (tp->t_outq.c_cc > hiwat) 10667502Sroot goto ovhiwat; 10677502Sroot if (tp->t_local&LFLUSHO) 10687502Sroot continue; 10697502Sroot if (tp->t_flags&LCASE || tp->t_local<ILDE) { 10707502Sroot while (cc) { 10717502Sroot c = *cp++; 10727502Sroot tp->t_rocount = 0; 10737625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 10747502Sroot /* out of clists, wait a bit */ 10757502Sroot ttstart(tp); 10767502Sroot sleep((caddr_t)&lbolt, TTOPRI); 10777502Sroot tp->t_rocount = 0; 10787502Sroot } 10797502Sroot --cc; 10807502Sroot if (tp->t_outq.c_cc > hiwat) 10817502Sroot goto ovhiwat; 10827502Sroot } 10837502Sroot continue; 10847502Sroot } 10857502Sroot while (cc) { 10867502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 10877502Sroot ce = cc; 10887502Sroot else { 10897502Sroot #ifdef vax 10907502Sroot asm(" scanc r9,(r10),_partab,$077"); 10917502Sroot asm(" subl3 r0,r9,r8"); 10927502Sroot #else 10937502Sroot ce=0; 10947625Ssam while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc)) 10957502Sroot ce++; 10967502Sroot #endif 10977502Sroot if (ce==0) { 10987502Sroot tp->t_rocount = 0; 10997502Sroot if (ttyoutput(*cp, tp) >= 0) { 11007502Sroot ttstart(tp); 11017502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11027502Sroot continue; 11037502Sroot } 11047502Sroot cp++; 11057502Sroot cc--; 11067502Sroot if (tp->t_outq.c_cc > hiwat) 11077502Sroot goto ovhiwat; 11087502Sroot } 11097502Sroot } 11107502Sroot tp->t_rocount = 0; 11117502Sroot i=b_to_q(cp,ce,&tp->t_outq); 11127502Sroot ce-=i; 11137502Sroot tk_nout+=ce; 11147502Sroot tp->t_col+=ce; 11157502Sroot cp+=ce; 11167502Sroot cc-=ce; 11177502Sroot if (i) { 11187502Sroot ttstart(tp); 11197502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11207502Sroot } 11217502Sroot if (ce || tp->t_outq.c_cc > hiwat) 11227502Sroot goto ovhiwat; 11237502Sroot } 11247502Sroot } 11257502Sroot ttstart(tp); 11268520Sroot return (error); 11277502Sroot 11287502Sroot ovhiwat: 11297502Sroot (void) spl5(); 11307822Sroot uio->uio_iov->iov_base -= cc; 11317822Sroot uio->uio_iov->iov_len += cc; 11327822Sroot uio->uio_resid += cc; 11337822Sroot uio->uio_offset -= cc; 11347502Sroot if (tp->t_outq.c_cc <= hiwat) { 11357502Sroot (void) spl0(); 11367502Sroot goto loop; 11377502Sroot } 11387502Sroot ttstart(tp); 11397502Sroot if (tp->t_state & TS_NBIO) { 11407822Sroot if (uio->uio_resid == cnt) 11418520Sroot return (EWOULDBLOCK); 11428520Sroot return (0); 11437502Sroot } 11447502Sroot tp->t_state |= TS_ASLEEP; 11457502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 11467502Sroot (void) spl0(); 11477502Sroot goto loop; 11487502Sroot } 11497502Sroot 11507502Sroot /* 11517502Sroot * Rubout one character from the rawq of tp 11527502Sroot * as cleanly as possible. 11537502Sroot */ 11547502Sroot ttyrub(c, tp) 11557625Ssam register c; 11567625Ssam register struct tty *tp; 11577502Sroot { 11587502Sroot register char *cp; 11597502Sroot register int savecol; 11607502Sroot int s; 11617502Sroot char *nextc(); 11627502Sroot 11637502Sroot if ((tp->t_flags&ECHO)==0) 11647502Sroot return; 11657502Sroot tp->t_local &= ~LFLUSHO; 11667502Sroot c &= 0377; 11677502Sroot if (tp->t_local&LCRTBS) { 11687502Sroot if (tp->t_rocount == 0) { 11697502Sroot /* 11707502Sroot * Screwed by ttwrite; retype 11717502Sroot */ 11727502Sroot ttyretype(tp); 11737502Sroot return; 11747502Sroot } 11757502Sroot if (c==('\t'|0200) || c==('\n'|0200)) 11767502Sroot ttyrubo(tp, 2); 11777625Ssam else switch (partab[c&=0177] & 0177) { 11787502Sroot 11797502Sroot case ORDINARY: 11807502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 11817502Sroot ttyrubo(tp, 2); 11827502Sroot else 11837502Sroot ttyrubo(tp, 1); 11847502Sroot break; 11857502Sroot 11867502Sroot case VTAB: 11877502Sroot case BACKSPACE: 11887502Sroot case CONTROL: 11897502Sroot case RETURN: 11907502Sroot if (tp->t_local & LCTLECH) 11917502Sroot ttyrubo(tp, 2); 11927502Sroot break; 11937502Sroot 11947502Sroot case TAB: 11957502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 11967502Sroot ttyretype(tp); 11977502Sroot return; 11987502Sroot } 11997502Sroot s = spl5(); 12007502Sroot savecol = tp->t_col; 12017502Sroot tp->t_lstate |= LSCNTTB; 12027502Sroot tp->t_local |= LFLUSHO; 12037502Sroot tp->t_col = tp->t_rocol; 12047502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12057502Sroot ttyecho(*cp, tp); 12067502Sroot tp->t_local &= ~LFLUSHO; 12077502Sroot tp->t_lstate &= ~LSCNTTB; 12087502Sroot splx(s); 12097502Sroot /* 12107502Sroot * savecol will now be length of the tab 12117502Sroot */ 12127502Sroot savecol -= tp->t_col; 12137502Sroot tp->t_col += savecol; 12147502Sroot if (savecol > 8) 12157502Sroot savecol = 8; /* overflow screw */ 12167502Sroot while (--savecol >= 0) 12177502Sroot (void) ttyoutput('\b', tp); 12187502Sroot break; 12197502Sroot 12207502Sroot default: 12217502Sroot panic("ttyrub"); 12227502Sroot } 12237502Sroot } else if (tp->t_local&LPRTERA) { 12247502Sroot if ((tp->t_lstate&LSERASE) == 0) { 12257502Sroot (void) ttyoutput('\\', tp); 12267502Sroot tp->t_lstate |= LSERASE; 12277502Sroot } 12287502Sroot ttyecho(c, tp); 12297502Sroot } else 12307502Sroot ttyecho(tp->t_erase, tp); 12317502Sroot tp->t_rocount--; 12327502Sroot } 12337502Sroot 12347502Sroot /* 12357502Sroot * Crt back over cnt chars perhaps 12367502Sroot * erasing them. 12377502Sroot */ 12387502Sroot ttyrubo(tp, cnt) 12397625Ssam register struct tty *tp; 12407625Ssam int cnt; 12417502Sroot { 12427502Sroot 12437502Sroot while (--cnt >= 0) 12447502Sroot ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp); 12457502Sroot } 12467502Sroot 12477502Sroot /* 12487502Sroot * Reprint the rawq line. 12497502Sroot * We assume c_cc has already been checked. 12507502Sroot */ 12517502Sroot ttyretype(tp) 12527625Ssam register struct tty *tp; 12537502Sroot { 12547502Sroot register char *cp; 12557502Sroot char *nextc(); 12567502Sroot int s; 12577502Sroot 12587502Sroot if (tlun.t_rprntc != 0377) 12597502Sroot ttyecho(tlun.t_rprntc, tp); 12607502Sroot (void) ttyoutput('\n', tp); 12617502Sroot s = spl5(); 12627502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 12637502Sroot ttyecho(*cp, tp); 12647502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12657502Sroot ttyecho(*cp, tp); 12667502Sroot tp->t_lstate &= ~LSERASE; 12677502Sroot splx(s); 12687502Sroot tp->t_rocount = tp->t_rawq.c_cc; 12697502Sroot tp->t_rocol = 0; 12707502Sroot } 12717502Sroot 12727502Sroot /* 12737502Sroot * Echo a typed character to the terminal 12747502Sroot */ 12757502Sroot ttyecho(c, tp) 12767625Ssam register c; 12777625Ssam register struct tty *tp; 12787502Sroot { 12797502Sroot 12807502Sroot if ((tp->t_lstate & LSCNTTB) == 0) 12817502Sroot tp->t_local &= ~LFLUSHO; 12827502Sroot if ((tp->t_flags&ECHO) == 0) 12837502Sroot return; 12847502Sroot c &= 0377; 12857502Sroot if (tp->t_flags&RAW) { 12867502Sroot (void) ttyoutput(c, tp); 12877502Sroot return; 12887502Sroot } 12897502Sroot if (c == '\r' && tp->t_flags&CRMOD) 12907502Sroot c = '\n'; 12917502Sroot if (tp->t_local&LCTLECH) { 12927502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 12937502Sroot (void) ttyoutput('^', tp); 12947502Sroot c &= 0177; 12957502Sroot if (c == 0177) 12967502Sroot c = '?'; 12977502Sroot else if (tp->t_flags&LCASE) 12987502Sroot c += 'a' - 1; 12997502Sroot else 13007502Sroot c += 'A' - 1; 13017502Sroot } 13027502Sroot } 13037502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 13047502Sroot c += 'a' - 'A'; 13057502Sroot (void) ttyoutput(c & 0177, tp); 13067502Sroot } 13077502Sroot 13087502Sroot /* 13097502Sroot * Is c a break char for tp? 13107502Sroot */ 13117502Sroot ttbreakc(c, tp) 13127625Ssam register c; 13137625Ssam register struct tty *tp; 13147502Sroot { 13157502Sroot return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc || 13167502Sroot c == '\r' && (tp->t_flags&CRMOD)); 13177502Sroot } 13187502Sroot 13197502Sroot /* 13207502Sroot * send string cp to tp 13217502Sroot */ 13227502Sroot ttyout(cp, tp) 13237625Ssam register char *cp; 13247625Ssam register struct tty *tp; 13257502Sroot { 13267502Sroot register char c; 13277502Sroot 13287502Sroot while (c = *cp++) 13297502Sroot (void) ttyoutput(c, tp); 13307502Sroot } 13317502Sroot 13327502Sroot ttwakeup(tp) 13337502Sroot struct tty *tp; 13347502Sroot { 13357502Sroot 13367502Sroot if (tp->t_rsel) { 13377502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 13387502Sroot tp->t_state &= ~TS_RCOLL; 13397502Sroot tp->t_rsel = 0; 13407502Sroot } 13417502Sroot wakeup((caddr_t)&tp->t_rawq); 13427502Sroot } 13437502Sroot 13447502Sroot ttsignal(tp, signo) 13457502Sroot struct tty *tp; 13467502Sroot int signo; 13477502Sroot { 13487502Sroot 13497502Sroot gsignal(tp->t_pgrp, signo); 13507502Sroot } 1351