1*8954Sroot /* tty.c 4.33 82/10/31 */ 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] = 98*8954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 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; 2488556Sroot 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 && 2718556Sroot 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 2808556Sroot /* get discipline number */ 28139Sbill case TIOCGETD: 2827625Ssam *(int *)data = tp->t_line; 28339Sbill break; 28439Sbill 2858556Sroot /* set line discipline */ 2867625Ssam case TIOCSETD: { 2877625Ssam register int t = *(int *)data; 2888556Sroot int error; 2897625Ssam 2908556Sroot if (t >= nldisp) 2918556Sroot return (ENXIO); 2928556Sroot s = spl5(); 29339Sbill if (tp->t_line) 29439Sbill (*linesw[tp->t_line].l_close)(tp); 29539Sbill if (t) 2968556Sroot error = (*linesw[t].l_open)(dev, tp); 2978556Sroot splx(s); 2988556Sroot if (error) 2998556Sroot return (error); 3008556Sroot tp->t_line = t; 30139Sbill break; 3027625Ssam } 30339Sbill 3048556Sroot /* 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 3138556Sroot /* 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 3468556Sroot /* 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 3588556Sroot /* 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 3888556Sroot /* 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 3978556Sroot /* 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 4068556Sroot /* return number of characters immediately available */ 4077625Ssam case FIONREAD: 4087625Ssam *(off_t *)data = ttnread(tp); 409174Sbill break; 410174Sbill 4118556Sroot /* 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 4208556Sroot /* 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 4378589Sroot case TIOCSTOP: 4388589Sroot s = spl5(); 4395573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4405573Swnj tp->t_state |= TS_TTSTOP; 4415573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4425573Swnj } 4437625Ssam splx(s); 4445573Swnj break; 4455573Swnj 4468589Sroot case TIOCSTART: 4478589Sroot s = spl5(); 4485573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4495573Swnj tp->t_state &= ~TS_TTSTOP; 4505573Swnj tp->t_local &= ~LFLUSHO; 4515573Swnj ttstart(tp); 4525573Swnj } 4537625Ssam splx(s); 4545573Swnj break; 4555573Swnj 45639Sbill default: 4578556Sroot return (-1); 45839Sbill } 4598556Sroot return (0); 46039Sbill } 4614484Swnj 4624484Swnj ttnread(tp) 4634484Swnj struct tty *tp; 4644484Swnj { 4654484Swnj int nread = 0; 4664484Swnj 4674484Swnj if (tp->t_local & LPENDIN) 4684484Swnj ttypend(tp); 4694484Swnj nread = tp->t_canq.c_cc; 4704484Swnj if (tp->t_flags & (RAW|CBREAK)) 4714484Swnj nread += tp->t_rawq.c_cc; 4724484Swnj return (nread); 4734484Swnj } 4744484Swnj 4755408Swnj ttselect(dev, rw) 4764484Swnj dev_t dev; 4775408Swnj int rw; 4784484Swnj { 4794484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4804484Swnj int nread; 4815408Swnj int s = spl5(); 4824484Swnj 4835408Swnj switch (rw) { 4844484Swnj 4854484Swnj case FREAD: 4864484Swnj nread = ttnread(tp); 4874484Swnj if (nread > 0) 4885408Swnj goto win; 4894938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 4905408Swnj tp->t_state |= TS_RCOLL; 4914484Swnj else 4924484Swnj tp->t_rsel = u.u_procp; 4935408Swnj break; 4944484Swnj 4955408Swnj case FWRITE: 4965408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 4975408Swnj goto win; 4985408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 4995408Swnj tp->t_state |= TS_WCOLL; 5005408Swnj else 5015408Swnj tp->t_wsel = u.u_procp; 5025408Swnj break; 5034484Swnj } 5045408Swnj splx(s); 5055408Swnj return (0); 5065408Swnj win: 5075408Swnj splx(s); 5085408Swnj return (1); 5094484Swnj } 5107436Skre 5117502Sroot #define OBUFSIZ 100 5127502Sroot 5137502Sroot /* 5147502Sroot * routine called on opens while tp->t_line == NTTYDISC 5157502Sroot * establishes a process group for distribution of 5167502Sroot * quits and interrupts from the tty. 5177502Sroot * (actually, pp->p_pgrp can't be 0 when this routine 5187502Sroot * is called since NTTYDISC is not the default discipline) 5197502Sroot */ 5207502Sroot ttyopen(dev, tp) 5217625Ssam dev_t dev; 5227625Ssam register struct tty *tp; 5237502Sroot { 5247502Sroot register struct proc *pp; 5257502Sroot 5267502Sroot pp = u.u_procp; 5277502Sroot tp->t_dev = dev; 5287625Ssam if (pp->p_pgrp == 0) { 5297502Sroot u.u_ttyp = tp; 5307502Sroot u.u_ttyd = dev; 5317502Sroot if (tp->t_pgrp == 0) 5327502Sroot tp->t_pgrp = pp->p_pid; 5337502Sroot pp->p_pgrp = tp->t_pgrp; 5347502Sroot } 5357502Sroot tp->t_state &= ~TS_WOPEN; 5367502Sroot tp->t_state |= TS_ISOPEN; 5377502Sroot if (tp->t_line != NTTYDISC) 5387502Sroot wflushtty(tp); 5398556Sroot return (0); 5407502Sroot } 5417502Sroot 5427502Sroot /* 5437502Sroot * clean tp on last close 5447502Sroot */ 5457502Sroot ttyclose(tp) 5467625Ssam register struct tty *tp; 5477502Sroot { 5487502Sroot 5497502Sroot if (tp->t_line) { 5507502Sroot wflushtty(tp); 5517502Sroot tp->t_line = 0; 5527502Sroot return; 5537502Sroot } 5547502Sroot tp->t_pgrp = 0; 5557502Sroot wflushtty(tp); 5567502Sroot tp->t_state = 0; 5577502Sroot } 5587502Sroot 5597502Sroot /* 5607502Sroot * reinput pending characters after state switch 5617502Sroot * call at spl5(). 5627502Sroot */ 5637502Sroot ttypend(tp) 5647625Ssam register struct tty *tp; 5657502Sroot { 5667502Sroot struct clist tq; 5677502Sroot register c; 5687502Sroot 5697502Sroot tp->t_local &= ~LPENDIN; 5707502Sroot tp->t_lstate |= LSTYPEN; 5717502Sroot tq = tp->t_rawq; 5727502Sroot tp->t_rawq.c_cc = 0; 5737502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5747502Sroot while ((c = getc(&tq)) >= 0) 5757502Sroot ttyinput(c, tp); 5767502Sroot tp->t_lstate &= ~LSTYPEN; 5777502Sroot } 5787502Sroot 5797502Sroot /* 5807502Sroot * Place a character on raw TTY input queue, putting in delimiters 5817502Sroot * and waking up top half as needed. 5827502Sroot * Also echo if required. 5837502Sroot * The arguments are the character and the appropriate 5847502Sroot * tty structure. 5857502Sroot */ 5867502Sroot ttyinput(c, tp) 5877625Ssam register c; 5887625Ssam register struct tty *tp; 5897502Sroot { 5907502Sroot register int t_flags; 5917502Sroot int i; 5927502Sroot 5937502Sroot if (tp->t_local&LPENDIN) 5947502Sroot ttypend(tp); 5957502Sroot tk_nin++; 5967502Sroot c &= 0377; 5977502Sroot t_flags = tp->t_flags; 5987502Sroot if (t_flags&TANDEM) 5997502Sroot ttyblock(tp); 6007502Sroot if ((t_flags&RAW)==0) { 6017502Sroot if ((tp->t_lstate&LSTYPEN) == 0) 6027502Sroot c &= 0177; 6037502Sroot /* check for literal nexting very first */ 6047502Sroot if (tp->t_lstate&LSLNCH) { 6057502Sroot c |= 0200; 6067502Sroot tp->t_lstate &= ~LSLNCH; 6077502Sroot } 6087502Sroot if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) { 6097502Sroot if (tp->t_flags&ECHO) 6107502Sroot ttyout("^\b", tp); 6117502Sroot tp->t_lstate |= LSLNCH; 6127502Sroot /* check for output control functions */ 6137502Sroot } else if (c==tun.t_stopc) { 6147502Sroot if ((tp->t_state&TS_TTSTOP)==0) { 6157502Sroot tp->t_state |= TS_TTSTOP; 6167502Sroot (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6177502Sroot return; 6187502Sroot } 6197502Sroot if (c!=tun.t_startc) 6207502Sroot return; 6217502Sroot } else if (c==tun.t_startc) { 6227502Sroot tp->t_state &= ~TS_TTSTOP; 6237502Sroot tp->t_local &= ~LFLUSHO; 6247502Sroot ttstart(tp); 6257502Sroot return; 6267502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) { 6277502Sroot if (tp->t_local & LFLUSHO) 6287502Sroot tp->t_local &= ~LFLUSHO; 6297502Sroot else { 6307502Sroot flushtty(tp, FWRITE); 6317502Sroot ttyecho(c, tp); 6327502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc) 6337502Sroot ttyretype(tp); 6347502Sroot tp->t_local |= LFLUSHO; 6357502Sroot } 6367502Sroot ttstart(tp); 6377502Sroot return; 6387502Sroot } else if (c==tun.t_intrc || c==tun.t_quitc || 6397502Sroot (tp->t_line == NTTYDISC && c==tlun.t_suspc)) { 6407502Sroot if ((tp->t_local & LNOFLSH) == 0) 6417502Sroot flushtty(tp, 6427502Sroot c==tlun.t_suspc ? FREAD : FREAD|FWRITE); 6437502Sroot ttyecho(c, tp); 6447502Sroot c = c==tun.t_intrc ? SIGINT : 6457502Sroot ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP); 6467502Sroot ttsignal(tp, c); 6477502Sroot /* check for buffer editing functions - cooked mode */ 6487502Sroot } else if ((t_flags&CBREAK) == 0) { 6497502Sroot if ((tp->t_lstate&LSQUOT) && 6507502Sroot (c==tp->t_erase||c==tp->t_kill)) { 6517502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6527502Sroot c |= 0200; 6537502Sroot } 6547502Sroot if (c==tp->t_erase) { 6557502Sroot if (tp->t_rawq.c_cc) 6567502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6577502Sroot } else if (c==tp->t_kill) { 6587502Sroot if (tp->t_local&LCRTKIL && 6597502Sroot tp->t_rawq.c_cc == tp->t_rocount) { 6607502Sroot while (tp->t_rawq.c_cc) 6617502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6627502Sroot } else { 6637502Sroot ttyecho(c, tp); 6647502Sroot ttyecho('\n', tp); 6657502Sroot while (getc(&tp->t_rawq) > 0) 6667502Sroot ; 6677502Sroot tp->t_rocount = 0; 6687502Sroot } 6697502Sroot tp->t_lstate = 0; 6707502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) { 6717502Sroot if (tp->t_rawq.c_cc == 0) 6727502Sroot goto out; 6737502Sroot do { 6747502Sroot c = unputc(&tp->t_rawq); 6757502Sroot if (c != ' ' && c != '\t') 6767502Sroot goto erasenb; 6777502Sroot ttyrub(c, tp); 6787502Sroot } while (tp->t_rawq.c_cc); 6797502Sroot goto out; 6807502Sroot erasenb: 6817502Sroot do { 6827502Sroot ttyrub(c, tp); 6837502Sroot if (tp->t_rawq.c_cc == 0) 6847502Sroot goto out; 6857502Sroot c = unputc(&tp->t_rawq); 6867502Sroot } while (c != ' ' && c != '\t'); 6877502Sroot (void) putc(c, &tp->t_rawq); 6887502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) { 6897502Sroot ttyretype(tp); 6907502Sroot /* check for cooked mode input buffer overflow */ 6917502Sroot } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 6927502Sroot ; 6937502Sroot /* put data char in q for user and wakeup if a break char */ 6947502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 6957502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG 6967502Sroot && tp->t_line == NTTYDISC) 6977502Sroot (void) ttyoutput(CTRL(g), tp); 6987502Sroot if (!ttbreakc(c, tp)) { 6997502Sroot if (tp->t_rocount++ == 0) 7007502Sroot tp->t_rocol = tp->t_col; 7017502Sroot } else { 7027502Sroot tp->t_rocount = 0; 7037502Sroot catq(&tp->t_rawq, &tp->t_canq); 7047502Sroot /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */ 7057502Sroot ttwakeup(tp); 7067502Sroot } 7077502Sroot tp->t_lstate &= ~LSQUOT; 7087502Sroot if (c == '\\') 7097502Sroot tp->t_lstate |= LSQUOT; 7107502Sroot if (tp->t_lstate&LSERASE) { 7117502Sroot tp->t_lstate &= ~LSERASE; 7127502Sroot (void) ttyoutput('/', tp); 7137502Sroot } 7147502Sroot i = tp->t_col; 7157502Sroot ttyecho(c, tp); 7167502Sroot if (c==tun.t_eofc && tp->t_flags&ECHO) { 7177502Sroot i = MIN(2, tp->t_col - i); 7187502Sroot while (i > 0) { 7197502Sroot (void) ttyoutput('\b', tp); 7207502Sroot i--; 7217502Sroot } 7227502Sroot } 7237502Sroot } 7247502Sroot /* CBREAK mode */ 7257502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) { 7267502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7277502Sroot tp->t_line == NTTYDISC) 7287502Sroot (void) ttyoutput(CTRL(g), tp); 7297502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7307502Sroot ttwakeup(tp); 7317502Sroot ttyecho(c, tp); 7327502Sroot } 7337502Sroot /* RAW mode */ 7347502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) 7357502Sroot flushtty(tp, FREAD|FWRITE); 7367502Sroot else { 7377502Sroot if (putc(c, &tp->t_rawq) >= 0) 7387502Sroot ttwakeup(tp); 7397502Sroot ttyecho(c, tp); 7407502Sroot } 7417502Sroot out: 7427502Sroot if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP && 7437502Sroot tun.t_startc != tun.t_stopc) 7447502Sroot return; 7457502Sroot tp->t_state &= ~TS_TTSTOP; 7467502Sroot tp->t_local &= ~LFLUSHO; 7477502Sroot ttstart(tp); 7487502Sroot } 7497502Sroot 7507502Sroot /* 7517502Sroot * put character on TTY output queue, adding delays, 7527502Sroot * expanding tabs, and handling the CR/NL bit. 7537502Sroot * It is called both from the top half for output, and from 7547502Sroot * interrupt level for echoing. 7557502Sroot * The arguments are the character and the tty structure. 7567502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 7577502Sroot * Must be recursive. 7587502Sroot */ 7597502Sroot ttyoutput(c, tp) 7607502Sroot register c; 7617502Sroot register struct tty *tp; 7627502Sroot { 7637502Sroot register char *colp; 7647502Sroot register ctype; 7657502Sroot 7667502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) { 7677502Sroot if (tp->t_local&LFLUSHO) 7687502Sroot return (-1); 7697502Sroot if (putc(c, &tp->t_outq)) 7707625Ssam return (c); 7717502Sroot tk_nout++; 7727502Sroot return (-1); 7737502Sroot } 7747502Sroot /* 7757502Sroot * Ignore EOT in normal mode to avoid hanging up 7767502Sroot * certain terminals. 7777502Sroot */ 7787502Sroot c &= 0177; 7797502Sroot if (c==CEOT && (tp->t_flags&CBREAK)==0) 7807502Sroot return (-1); 7817502Sroot /* 7827502Sroot * Turn tabs to spaces as required 7837502Sroot */ 7847502Sroot if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 7857502Sroot register int s; 7867502Sroot 7877502Sroot c = 8 - (tp->t_col&7); 7887502Sroot if ((tp->t_local&LFLUSHO) == 0) { 7897502Sroot s = spl5(); /* don't interrupt tabs */ 7907502Sroot c -= b_to_q(" ", c, &tp->t_outq); 7917502Sroot tk_nout += c; 7927502Sroot splx(s); 7937502Sroot } 7947502Sroot tp->t_col += c; 7957502Sroot return (c ? -1 : '\t'); 7967502Sroot } 7977502Sroot tk_nout++; 7987502Sroot /* 7997502Sroot * for upper-case-only terminals, 8007502Sroot * generate escapes. 8017502Sroot */ 8027502Sroot if (tp->t_flags&LCASE) { 8037502Sroot colp = "({)}!|^~'`"; 8047625Ssam while (*colp++) 8057625Ssam if (c == *colp++) { 8067502Sroot if (ttyoutput('\\', tp) >= 0) 8077502Sroot return (c); 8087502Sroot c = colp[-2]; 8097502Sroot break; 8107502Sroot } 8117502Sroot if ('A'<=c && c<='Z') { 8127502Sroot if (ttyoutput('\\', tp) >= 0) 8137502Sroot return (c); 8147502Sroot } else if ('a'<=c && c<='z') 8157502Sroot c += 'A' - 'a'; 8167502Sroot } 8177502Sroot /* 8187502Sroot * turn <nl> to <cr><lf> if desired. 8197502Sroot */ 8207502Sroot if (c=='\n' && tp->t_flags&CRMOD) 8217502Sroot if (ttyoutput('\r', tp) >= 0) 8227502Sroot return (c); 8237502Sroot if (c=='~' && tp->t_local<ILDE) 8247502Sroot c = '`'; 8257502Sroot if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq)) 8267502Sroot return (c); 8277502Sroot /* 8287502Sroot * Calculate delays. 8297502Sroot * The numbers here represent clock ticks 8307502Sroot * and are not necessarily optimal for all terminals. 8317502Sroot * The delays are indicated by characters above 0200. 8327502Sroot * In raw mode there are no delays and the 8337502Sroot * transmission path is 8 bits wide. 8347502Sroot */ 8357502Sroot colp = &tp->t_col; 8367502Sroot ctype = partab[c]; 8377502Sroot c = 0; 8387502Sroot switch (ctype&077) { 8397502Sroot 8407502Sroot case ORDINARY: 8417502Sroot (*colp)++; 8427502Sroot 8437502Sroot case CONTROL: 8447502Sroot break; 8457502Sroot 8467502Sroot case BACKSPACE: 8477502Sroot if (*colp) 8487502Sroot (*colp)--; 8497502Sroot break; 8507502Sroot 8517502Sroot case NEWLINE: 8527502Sroot ctype = (tp->t_flags >> 8) & 03; 8537625Ssam if (ctype == 1) { /* tty 37 */ 8547502Sroot if (*colp) 8557502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 8567502Sroot } else 8577625Ssam if (ctype == 2) { /* vt05 */ 8587502Sroot c = 6; 8597502Sroot } 8607502Sroot *colp = 0; 8617502Sroot break; 8627502Sroot 8637502Sroot case TAB: 8647502Sroot ctype = (tp->t_flags >> 10) & 03; 8657625Ssam if (ctype == 1) { /* tty 37 */ 8667502Sroot c = 1 - (*colp | ~07); 8677625Ssam if (c < 5) 8687502Sroot c = 0; 8697502Sroot } 8707502Sroot *colp |= 07; 8717502Sroot (*colp)++; 8727502Sroot break; 8737502Sroot 8747502Sroot case VTAB: 8757625Ssam if (tp->t_flags & VTDELAY) /* tty 37 */ 8767502Sroot c = 0177; 8777502Sroot break; 8787502Sroot 8797502Sroot case RETURN: 8807502Sroot ctype = (tp->t_flags >> 12) & 03; 8817625Ssam if (ctype == 1) { /* tn 300 */ 8827502Sroot c = 5; 8837625Ssam } else if (ctype == 2) { /* ti 700 */ 8847502Sroot c = 10; 8857625Ssam } else if (ctype == 3) { /* concept 100 */ 8867502Sroot int i; 8877502Sroot if ((i = *colp) >= 0) 8887502Sroot for (; i<9; i++) 8897502Sroot (void) putc(0177, &tp->t_outq); 8907502Sroot } 8917502Sroot *colp = 0; 8927502Sroot } 8937625Ssam if (c && (tp->t_local&LFLUSHO) == 0) 8947502Sroot (void) putc(c|0200, &tp->t_outq); 8957502Sroot return (-1); 8967502Sroot } 8977502Sroot 8987502Sroot /* 8997502Sroot * Called from device's read routine after it has 9007502Sroot * calculated the tty-structure given as argument. 9017502Sroot */ 9027722Swnj ttread(tp, uio) 9037625Ssam register struct tty *tp; 9047722Swnj struct uio *uio; 9057502Sroot { 9067502Sroot register struct clist *qp; 9077502Sroot register c, first; 9088520Sroot int error = 0; 9097502Sroot 9107502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9118520Sroot return (EIO); 9127502Sroot loop: 9137502Sroot (void) spl5(); 9147502Sroot if (tp->t_local&LPENDIN) 9157502Sroot ttypend(tp); 9167502Sroot (void) spl0(); 9177502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9187502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9197502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9207502Sroot /* 9217502Sroot (u.u_procp->p_flag&SDETACH) || 9227502Sroot */ 9237502Sroot u.u_procp->p_flag&SVFORK) 9248520Sroot return (EIO); 9257502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9267502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9277502Sroot } 9287502Sroot if (tp->t_flags&RAW) { 9297502Sroot (void) spl5(); 9307502Sroot if (tp->t_rawq.c_cc <= 0) { 9317502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9327502Sroot (tp->t_state&TS_NBIO)) { 9337502Sroot (void) spl0(); 9348520Sroot return (EWOULDBLOCK); 9357502Sroot } 9367502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9377502Sroot (void) spl0(); 9387502Sroot goto loop; 9397502Sroot } 9407502Sroot (void) spl0(); 9417722Swnj while (tp->t_rawq.c_cc && uio->uio_iovcnt) { 9428520Sroot error = passuc(getc(&tp->t_rawq), uio); 9438520Sroot if (error) 9447722Swnj break; 9457722Swnj } 9468520Sroot return (error); 9477502Sroot } else { 9487502Sroot qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq; 9497502Sroot (void) spl5(); 9507502Sroot if (qp->c_cc <= 0) { 9517502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9527502Sroot (tp->t_state&TS_NBIO)) { 9537502Sroot (void) spl0(); 9548520Sroot return (EWOULDBLOCK); 9557502Sroot } 9567502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9577502Sroot (void) spl0(); 9587502Sroot goto loop; 9597502Sroot } 9607502Sroot (void) spl0(); 9617502Sroot first = 1; 9627502Sroot while ((c = getc(qp)) >= 0) { 9637502Sroot if (tp->t_flags&CRMOD && c == '\r') 9647502Sroot c = '\n'; 9657502Sroot if (tp->t_flags&LCASE && c <= 0177) 9667502Sroot if (tp->t_lstate&LSBKSL) { 9677502Sroot if (maptab[c]) 9687502Sroot c = maptab[c]; 9697502Sroot tp->t_lstate &= ~LSBKSL; 9707502Sroot } else if (c >= 'A' && c <= 'Z') 9717502Sroot c += 'a' - 'A'; 9727502Sroot else if (c == '\\') { 9737502Sroot tp->t_lstate |= LSBKSL; 9747502Sroot continue; 9757502Sroot } 9767658Ssam if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) { 9777502Sroot ttsignal(tp, SIGTSTP); 9787502Sroot if (first) { 9797502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9807502Sroot goto loop; 9817502Sroot } 9827502Sroot break; 9837502Sroot } 9847502Sroot if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0) 9857502Sroot break; 9868520Sroot error = passuc(c & 0177, uio); 9878520Sroot if (error) 9887502Sroot break; 9897722Swnj if (uio->uio_iovcnt == 0) 9907722Swnj break; 9917502Sroot if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp)) 9927502Sroot break; 9937502Sroot first = 0; 9947502Sroot } 9957502Sroot tp->t_lstate &= ~LSBKSL; 9967502Sroot } 9977502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 9987502Sroot if (putc(tun.t_startc, &tp->t_outq)==0) { 9997502Sroot tp->t_state &= ~TS_TBLOCK; 10007502Sroot ttstart(tp); 10017502Sroot } 10027502Sroot tp->t_char = 0; 10037502Sroot } 10048520Sroot return (error); 10057502Sroot } 10067502Sroot 10077502Sroot /* 10087502Sroot * Called from the device's write routine after it has 10097502Sroot * calculated the tty-structure given as argument. 10107502Sroot */ 10117822Sroot ttwrite(tp, uio) 10127625Ssam register struct tty *tp; 10137822Sroot struct uio *uio; 10147502Sroot { 10157502Sroot #ifdef vax 10167502Sroot /* 10177502Sroot * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 10187502Sroot * AND MUST NOT BE CHANGED WITHOUT PATCHING 10197502Sroot * THE 'ASM' INLINES BELOW. WATCH OUT. 10207502Sroot */ 10217502Sroot #endif 10227502Sroot register char *cp; 10237502Sroot register int cc, ce; 10247502Sroot register i; 10257502Sroot char obuf[OBUFSIZ]; 10267502Sroot register c; 10277502Sroot int hiwat = TTHIWAT(tp); 10287822Sroot int cnt = uio->uio_resid; 10298520Sroot int error = 0; 10307502Sroot 10317502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10328520Sroot return (EIO); 10337502Sroot loop: 10347502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 10357502Sroot (tp->t_local<OSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 10367502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 10377502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 10387502Sroot /* 10397502Sroot && 10407502Sroot (u.u_procp->p_flag&SDETACH)==0) { 10417502Sroot */ 10427502Sroot ) { 10437502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 10447502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10457502Sroot } 10467822Sroot while (uio->uio_resid > 0) { 10477822Sroot cc = uio->uio_iov->iov_len; 10487822Sroot if (cc == 0) { 10497822Sroot uio->uio_iovcnt--; 10507822Sroot uio->uio_iov++; 10517822Sroot if (uio->uio_iovcnt < 0) 10527822Sroot panic("ttwrite"); 10537822Sroot continue; 10547822Sroot } 10557822Sroot if (cc > OBUFSIZ) 10567822Sroot cc = OBUFSIZ; 10577502Sroot cp = obuf; 10588520Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 10598520Sroot if (error) 10607502Sroot break; 10617502Sroot if (tp->t_outq.c_cc > hiwat) 10627502Sroot goto ovhiwat; 10637502Sroot if (tp->t_local&LFLUSHO) 10647502Sroot continue; 10657502Sroot if (tp->t_flags&LCASE || tp->t_local<ILDE) { 10667502Sroot while (cc) { 10677502Sroot c = *cp++; 10687502Sroot tp->t_rocount = 0; 10697625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 10707502Sroot /* out of clists, wait a bit */ 10717502Sroot ttstart(tp); 10727502Sroot sleep((caddr_t)&lbolt, TTOPRI); 10737502Sroot tp->t_rocount = 0; 10747502Sroot } 10757502Sroot --cc; 10767502Sroot if (tp->t_outq.c_cc > hiwat) 10777502Sroot goto ovhiwat; 10787502Sroot } 10797502Sroot continue; 10807502Sroot } 10817502Sroot while (cc) { 10827502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 10837502Sroot ce = cc; 10847502Sroot else { 10857502Sroot #ifdef vax 10867502Sroot asm(" scanc r9,(r10),_partab,$077"); 10877502Sroot asm(" subl3 r0,r9,r8"); 10887502Sroot #else 10897502Sroot ce=0; 10907625Ssam while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc)) 10917502Sroot ce++; 10927502Sroot #endif 10937502Sroot if (ce==0) { 10947502Sroot tp->t_rocount = 0; 10957502Sroot if (ttyoutput(*cp, tp) >= 0) { 10967502Sroot ttstart(tp); 10977502Sroot sleep((caddr_t)&lbolt, TTOPRI); 10987502Sroot continue; 10997502Sroot } 11007502Sroot cp++; 11017502Sroot cc--; 11027502Sroot if (tp->t_outq.c_cc > hiwat) 11037502Sroot goto ovhiwat; 11047502Sroot } 11057502Sroot } 11067502Sroot tp->t_rocount = 0; 11077502Sroot i=b_to_q(cp,ce,&tp->t_outq); 11087502Sroot ce-=i; 11097502Sroot tk_nout+=ce; 11107502Sroot tp->t_col+=ce; 11117502Sroot cp+=ce; 11127502Sroot cc-=ce; 11137502Sroot if (i) { 11147502Sroot ttstart(tp); 11157502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11167502Sroot } 11177502Sroot if (ce || tp->t_outq.c_cc > hiwat) 11187502Sroot goto ovhiwat; 11197502Sroot } 11207502Sroot } 11217502Sroot ttstart(tp); 11228520Sroot return (error); 11237502Sroot 11247502Sroot ovhiwat: 11257502Sroot (void) spl5(); 11267822Sroot uio->uio_iov->iov_base -= cc; 11277822Sroot uio->uio_iov->iov_len += cc; 11287822Sroot uio->uio_resid += cc; 11297822Sroot uio->uio_offset -= cc; 11307502Sroot if (tp->t_outq.c_cc <= hiwat) { 11317502Sroot (void) spl0(); 11327502Sroot goto loop; 11337502Sroot } 11347502Sroot ttstart(tp); 11357502Sroot if (tp->t_state & TS_NBIO) { 11367822Sroot if (uio->uio_resid == cnt) 11378520Sroot return (EWOULDBLOCK); 11388520Sroot return (0); 11397502Sroot } 11407502Sroot tp->t_state |= TS_ASLEEP; 11417502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 11427502Sroot (void) spl0(); 11437502Sroot goto loop; 11447502Sroot } 11457502Sroot 11467502Sroot /* 11477502Sroot * Rubout one character from the rawq of tp 11487502Sroot * as cleanly as possible. 11497502Sroot */ 11507502Sroot ttyrub(c, tp) 11517625Ssam register c; 11527625Ssam register struct tty *tp; 11537502Sroot { 11547502Sroot register char *cp; 11557502Sroot register int savecol; 11567502Sroot int s; 11577502Sroot char *nextc(); 11587502Sroot 11597502Sroot if ((tp->t_flags&ECHO)==0) 11607502Sroot return; 11617502Sroot tp->t_local &= ~LFLUSHO; 11627502Sroot c &= 0377; 11637502Sroot if (tp->t_local&LCRTBS) { 11647502Sroot if (tp->t_rocount == 0) { 11657502Sroot /* 11667502Sroot * Screwed by ttwrite; retype 11677502Sroot */ 11687502Sroot ttyretype(tp); 11697502Sroot return; 11707502Sroot } 11717502Sroot if (c==('\t'|0200) || c==('\n'|0200)) 11727502Sroot ttyrubo(tp, 2); 11737625Ssam else switch (partab[c&=0177] & 0177) { 11747502Sroot 11757502Sroot case ORDINARY: 11767502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 11777502Sroot ttyrubo(tp, 2); 11787502Sroot else 11797502Sroot ttyrubo(tp, 1); 11807502Sroot break; 11817502Sroot 11827502Sroot case VTAB: 11837502Sroot case BACKSPACE: 11847502Sroot case CONTROL: 11857502Sroot case RETURN: 11867502Sroot if (tp->t_local & LCTLECH) 11877502Sroot ttyrubo(tp, 2); 11887502Sroot break; 11897502Sroot 11907502Sroot case TAB: 11917502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 11927502Sroot ttyretype(tp); 11937502Sroot return; 11947502Sroot } 11957502Sroot s = spl5(); 11967502Sroot savecol = tp->t_col; 11977502Sroot tp->t_lstate |= LSCNTTB; 11987502Sroot tp->t_local |= LFLUSHO; 11997502Sroot tp->t_col = tp->t_rocol; 12007502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12017502Sroot ttyecho(*cp, tp); 12027502Sroot tp->t_local &= ~LFLUSHO; 12037502Sroot tp->t_lstate &= ~LSCNTTB; 12047502Sroot splx(s); 12057502Sroot /* 12067502Sroot * savecol will now be length of the tab 12077502Sroot */ 12087502Sroot savecol -= tp->t_col; 12097502Sroot tp->t_col += savecol; 12107502Sroot if (savecol > 8) 12117502Sroot savecol = 8; /* overflow screw */ 12127502Sroot while (--savecol >= 0) 12137502Sroot (void) ttyoutput('\b', tp); 12147502Sroot break; 12157502Sroot 12167502Sroot default: 12177502Sroot panic("ttyrub"); 12187502Sroot } 12197502Sroot } else if (tp->t_local&LPRTERA) { 12207502Sroot if ((tp->t_lstate&LSERASE) == 0) { 12217502Sroot (void) ttyoutput('\\', tp); 12227502Sroot tp->t_lstate |= LSERASE; 12237502Sroot } 12247502Sroot ttyecho(c, tp); 12257502Sroot } else 12267502Sroot ttyecho(tp->t_erase, tp); 12277502Sroot tp->t_rocount--; 12287502Sroot } 12297502Sroot 12307502Sroot /* 12317502Sroot * Crt back over cnt chars perhaps 12327502Sroot * erasing them. 12337502Sroot */ 12347502Sroot ttyrubo(tp, cnt) 12357625Ssam register struct tty *tp; 12367625Ssam int cnt; 12377502Sroot { 12387502Sroot 12397502Sroot while (--cnt >= 0) 12407502Sroot ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp); 12417502Sroot } 12427502Sroot 12437502Sroot /* 12447502Sroot * Reprint the rawq line. 12457502Sroot * We assume c_cc has already been checked. 12467502Sroot */ 12477502Sroot ttyretype(tp) 12487625Ssam register struct tty *tp; 12497502Sroot { 12507502Sroot register char *cp; 12517502Sroot char *nextc(); 12527502Sroot int s; 12537502Sroot 12547502Sroot if (tlun.t_rprntc != 0377) 12557502Sroot ttyecho(tlun.t_rprntc, tp); 12567502Sroot (void) ttyoutput('\n', tp); 12577502Sroot s = spl5(); 12587502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 12597502Sroot ttyecho(*cp, tp); 12607502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12617502Sroot ttyecho(*cp, tp); 12627502Sroot tp->t_lstate &= ~LSERASE; 12637502Sroot splx(s); 12647502Sroot tp->t_rocount = tp->t_rawq.c_cc; 12657502Sroot tp->t_rocol = 0; 12667502Sroot } 12677502Sroot 12687502Sroot /* 12697502Sroot * Echo a typed character to the terminal 12707502Sroot */ 12717502Sroot ttyecho(c, tp) 12727625Ssam register c; 12737625Ssam register struct tty *tp; 12747502Sroot { 12757502Sroot 12767502Sroot if ((tp->t_lstate & LSCNTTB) == 0) 12777502Sroot tp->t_local &= ~LFLUSHO; 12787502Sroot if ((tp->t_flags&ECHO) == 0) 12797502Sroot return; 12807502Sroot c &= 0377; 12817502Sroot if (tp->t_flags&RAW) { 12827502Sroot (void) ttyoutput(c, tp); 12837502Sroot return; 12847502Sroot } 12857502Sroot if (c == '\r' && tp->t_flags&CRMOD) 12867502Sroot c = '\n'; 12877502Sroot if (tp->t_local&LCTLECH) { 12887502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 12897502Sroot (void) ttyoutput('^', tp); 12907502Sroot c &= 0177; 12917502Sroot if (c == 0177) 12927502Sroot c = '?'; 12937502Sroot else if (tp->t_flags&LCASE) 12947502Sroot c += 'a' - 1; 12957502Sroot else 12967502Sroot c += 'A' - 1; 12977502Sroot } 12987502Sroot } 12997502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 13007502Sroot c += 'a' - 'A'; 13017502Sroot (void) ttyoutput(c & 0177, tp); 13027502Sroot } 13037502Sroot 13047502Sroot /* 13057502Sroot * Is c a break char for tp? 13067502Sroot */ 13077502Sroot ttbreakc(c, tp) 13087625Ssam register c; 13097625Ssam register struct tty *tp; 13107502Sroot { 13117502Sroot return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc || 13127502Sroot c == '\r' && (tp->t_flags&CRMOD)); 13137502Sroot } 13147502Sroot 13157502Sroot /* 13167502Sroot * send string cp to tp 13177502Sroot */ 13187502Sroot ttyout(cp, tp) 13197625Ssam register char *cp; 13207625Ssam register struct tty *tp; 13217502Sroot { 13227502Sroot register char c; 13237502Sroot 13247502Sroot while (c = *cp++) 13257502Sroot (void) ttyoutput(c, tp); 13267502Sroot } 13277502Sroot 13287502Sroot ttwakeup(tp) 13297502Sroot struct tty *tp; 13307502Sroot { 13317502Sroot 13327502Sroot if (tp->t_rsel) { 13337502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 13347502Sroot tp->t_state &= ~TS_RCOLL; 13357502Sroot tp->t_rsel = 0; 13367502Sroot } 13377502Sroot wakeup((caddr_t)&tp->t_rawq); 13387502Sroot } 13397502Sroot 13407502Sroot ttsignal(tp, signo) 13417502Sroot struct tty *tp; 13427502Sroot int signo; 13437502Sroot { 13447502Sroot 13457502Sroot gsignal(tp->t_pgrp, signo); 13467502Sroot } 1347