1*9325Ssam /* tty.c 4.34 82/11/22 */ 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] = 988954Sroot { 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: 267*9325Ssam case TIOCSTI: 268903Sbill while (tp->t_line == NTTYDISC && 269903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 270903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 271903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2728556Sroot u.u_signal[SIGTTOU] != SIG_HOLD) { 273903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 274903Sbill sleep((caddr_t)&lbolt, TTOPRI); 275903Sbill } 276903Sbill break; 277903Sbill } 278903Sbill 2797625Ssam switch (com) { 280903Sbill 2818556Sroot /* get discipline number */ 28239Sbill case TIOCGETD: 2837625Ssam *(int *)data = tp->t_line; 28439Sbill break; 28539Sbill 2868556Sroot /* set line discipline */ 2877625Ssam case TIOCSETD: { 2887625Ssam register int t = *(int *)data; 2898556Sroot int error; 2907625Ssam 2918556Sroot if (t >= nldisp) 2928556Sroot return (ENXIO); 2938556Sroot s = spl5(); 29439Sbill if (tp->t_line) 29539Sbill (*linesw[tp->t_line].l_close)(tp); 29639Sbill if (t) 2978556Sroot error = (*linesw[t].l_open)(dev, tp); 2988556Sroot splx(s); 2998556Sroot if (error) 3008556Sroot return (error); 3018556Sroot tp->t_line = t; 30239Sbill break; 3037625Ssam } 30439Sbill 3058556Sroot /* prevent more opens on channel */ 3065614Swnj case TIOCEXCL: 3075614Swnj tp->t_state |= TS_XCLUDE; 3085614Swnj break; 3095614Swnj 3105614Swnj case TIOCNXCL: 3115614Swnj tp->t_state &= ~TS_XCLUDE; 3125614Swnj break; 3135614Swnj 3148556Sroot /* set new parameters */ 31539Sbill case TIOCSETP: 3167625Ssam case TIOCSETN: { 3177625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3187625Ssam struct clist tq; 3197625Ssam 320121Sbill (void) spl5(); 3217625Ssam if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP) 3224484Swnj wflushtty(tp); 3237625Ssam else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) { 3247625Ssam if (sg->sg_flags & CBREAK) { 3254484Swnj catq(&tp->t_rawq, &tp->t_canq); 3264484Swnj tq = tp->t_rawq; 3274484Swnj tp->t_rawq = tp->t_canq; 3284484Swnj tp->t_canq = tq; 3294484Swnj } else { 3304484Swnj tp->t_local |= LPENDIN; 3314484Swnj ttwakeup(tp); 332174Sbill } 333174Sbill } 3347625Ssam tp->t_ispeed = sg->sg_ispeed; 3357625Ssam tp->t_ospeed = sg->sg_ospeed; 3367625Ssam tp->t_erase = sg->sg_erase; 3377625Ssam tp->t_kill = sg->sg_kill; 3387625Ssam tp->t_flags = sg->sg_flags; 3393941Sbugs if (tp->t_flags & RAW) { 3405408Swnj tp->t_state &= ~TS_TTSTOP; 3413941Sbugs ttstart(tp); 3423941Sbugs } 343121Sbill (void) spl0(); 34439Sbill break; 3457625Ssam } 34639Sbill 3478556Sroot /* send current parameters to user */ 3487625Ssam case TIOCGETP: { 3497625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3507625Ssam 3517625Ssam sg->sg_ispeed = tp->t_ispeed; 3527625Ssam sg->sg_ospeed = tp->t_ospeed; 3537625Ssam sg->sg_erase = tp->t_erase; 3547625Ssam sg->sg_kill = tp->t_kill; 3557625Ssam sg->sg_flags = tp->t_flags; 35639Sbill break; 3577625Ssam } 35839Sbill 3598556Sroot /* hang up line on last close */ 36039Sbill case TIOCHPCL: 3615408Swnj tp->t_state |= TS_HUPCLS; 36239Sbill break; 36339Sbill 3643942Sbugs case TIOCFLUSH: { 3657625Ssam register int flags = *(int *)data; 3667625Ssam 3677625Ssam if (flags == 0) 3683942Sbugs flags = FREAD|FWRITE; 3697625Ssam else 3707625Ssam flags &= FREAD|FWRITE; 3713942Sbugs flushtty(tp, flags); 37239Sbill break; 3733944Sbugs } 37439Sbill 3757625Ssam case FIONBIO: 3767625Ssam if (*(int *)data) 3775408Swnj tp->t_state |= TS_NBIO; 3785408Swnj else 3795408Swnj tp->t_state &= ~TS_NBIO; 3805408Swnj break; 3815408Swnj 3827625Ssam case FIOASYNC: 3837625Ssam if (*(int *)data) 3846216Swnj tp->t_state |= TS_ASYNC; 3856216Swnj else 3866216Swnj tp->t_state &= ~TS_ASYNC; 3876216Swnj break; 3886216Swnj 3898556Sroot /* set and fetch special characters */ 39039Sbill case TIOCSETC: 3917625Ssam bcopy(data, (caddr_t)&tun, sizeof (struct tchars)); 39239Sbill break; 39339Sbill 39439Sbill case TIOCGETC: 3957625Ssam bcopy((caddr_t)&tun, data, sizeof (struct tchars)); 39639Sbill break; 39739Sbill 3988556Sroot /* set/get local special characters */ 399174Sbill case TIOCSLTC: 4007625Ssam bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars)); 401174Sbill break; 402174Sbill 403174Sbill case TIOCGLTC: 4047625Ssam bcopy((caddr_t)&tlun, data, sizeof (struct ltchars)); 405174Sbill break; 406174Sbill 4078556Sroot /* return number of characters immediately available */ 4087625Ssam case FIONREAD: 4097625Ssam *(off_t *)data = ttnread(tp); 410174Sbill break; 411174Sbill 4128556Sroot /* should allow SPGRP and GPGRP only if tty open for reading */ 413174Sbill case TIOCSPGRP: 4147625Ssam tp->t_pgrp = *(int *)data; 415174Sbill break; 416174Sbill 417174Sbill case TIOCGPGRP: 4187625Ssam *(int *)data = tp->t_pgrp; 419174Sbill break; 420174Sbill 4218556Sroot /* Modify local mode word */ 422174Sbill case TIOCLBIS: 4237625Ssam tp->t_local |= *(int *)data; 424174Sbill break; 425174Sbill 426174Sbill case TIOCLBIC: 4277625Ssam tp->t_local &= ~(*(int *)data); 428174Sbill break; 429174Sbill 430174Sbill case TIOCLSET: 4317625Ssam tp->t_local = *(int *)data; 432174Sbill break; 433174Sbill 434174Sbill case TIOCLGET: 4357625Ssam *(int *)data = tp->t_local; 436174Sbill break; 437174Sbill 4388589Sroot case TIOCSTOP: 4398589Sroot s = spl5(); 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; 4465573Swnj 4478589Sroot case TIOCSTART: 4488589Sroot s = spl5(); 4495573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4505573Swnj tp->t_state &= ~TS_TTSTOP; 4515573Swnj tp->t_local &= ~LFLUSHO; 4525573Swnj ttstart(tp); 4535573Swnj } 4547625Ssam splx(s); 4555573Swnj break; 4565573Swnj 457*9325Ssam /* 458*9325Ssam * Simulate typing of a character at the terminal. 459*9325Ssam */ 460*9325Ssam case TIOCSTI: 461*9325Ssam if (u.u_uid && u.u_ttyp != tp) 462*9325Ssam return (EACCES); 463*9325Ssam else 464*9325Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 465*9325Ssam break; 466*9325Ssam 46739Sbill default: 4688556Sroot return (-1); 46939Sbill } 4708556Sroot return (0); 47139Sbill } 4724484Swnj 4734484Swnj ttnread(tp) 4744484Swnj struct tty *tp; 4754484Swnj { 4764484Swnj int nread = 0; 4774484Swnj 4784484Swnj if (tp->t_local & LPENDIN) 4794484Swnj ttypend(tp); 4804484Swnj nread = tp->t_canq.c_cc; 4814484Swnj if (tp->t_flags & (RAW|CBREAK)) 4824484Swnj nread += tp->t_rawq.c_cc; 4834484Swnj return (nread); 4844484Swnj } 4854484Swnj 4865408Swnj ttselect(dev, rw) 4874484Swnj dev_t dev; 4885408Swnj int rw; 4894484Swnj { 4904484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4914484Swnj int nread; 4925408Swnj int s = spl5(); 4934484Swnj 4945408Swnj switch (rw) { 4954484Swnj 4964484Swnj case FREAD: 4974484Swnj nread = ttnread(tp); 4984484Swnj if (nread > 0) 4995408Swnj goto win; 5004938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5015408Swnj tp->t_state |= TS_RCOLL; 5024484Swnj else 5034484Swnj tp->t_rsel = u.u_procp; 5045408Swnj break; 5054484Swnj 5065408Swnj case FWRITE: 5075408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5085408Swnj goto win; 5095408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5105408Swnj tp->t_state |= TS_WCOLL; 5115408Swnj else 5125408Swnj tp->t_wsel = u.u_procp; 5135408Swnj break; 5144484Swnj } 5155408Swnj splx(s); 5165408Swnj return (0); 5175408Swnj win: 5185408Swnj splx(s); 5195408Swnj return (1); 5204484Swnj } 5217436Skre 5227502Sroot #define OBUFSIZ 100 5237502Sroot 5247502Sroot /* 5257502Sroot * routine called on opens while tp->t_line == NTTYDISC 5267502Sroot * establishes a process group for distribution of 5277502Sroot * quits and interrupts from the tty. 5287502Sroot * (actually, pp->p_pgrp can't be 0 when this routine 5297502Sroot * is called since NTTYDISC is not the default discipline) 5307502Sroot */ 5317502Sroot ttyopen(dev, tp) 5327625Ssam dev_t dev; 5337625Ssam register struct tty *tp; 5347502Sroot { 5357502Sroot register struct proc *pp; 5367502Sroot 5377502Sroot pp = u.u_procp; 5387502Sroot tp->t_dev = dev; 5397625Ssam if (pp->p_pgrp == 0) { 5407502Sroot u.u_ttyp = tp; 5417502Sroot u.u_ttyd = dev; 5427502Sroot if (tp->t_pgrp == 0) 5437502Sroot tp->t_pgrp = pp->p_pid; 5447502Sroot pp->p_pgrp = tp->t_pgrp; 5457502Sroot } 5467502Sroot tp->t_state &= ~TS_WOPEN; 5477502Sroot tp->t_state |= TS_ISOPEN; 5487502Sroot if (tp->t_line != NTTYDISC) 5497502Sroot wflushtty(tp); 5508556Sroot return (0); 5517502Sroot } 5527502Sroot 5537502Sroot /* 5547502Sroot * clean tp on last close 5557502Sroot */ 5567502Sroot ttyclose(tp) 5577625Ssam register struct tty *tp; 5587502Sroot { 5597502Sroot 5607502Sroot if (tp->t_line) { 5617502Sroot wflushtty(tp); 5627502Sroot tp->t_line = 0; 5637502Sroot return; 5647502Sroot } 5657502Sroot tp->t_pgrp = 0; 5667502Sroot wflushtty(tp); 5677502Sroot tp->t_state = 0; 5687502Sroot } 5697502Sroot 5707502Sroot /* 5717502Sroot * reinput pending characters after state switch 5727502Sroot * call at spl5(). 5737502Sroot */ 5747502Sroot ttypend(tp) 5757625Ssam register struct tty *tp; 5767502Sroot { 5777502Sroot struct clist tq; 5787502Sroot register c; 5797502Sroot 5807502Sroot tp->t_local &= ~LPENDIN; 5817502Sroot tp->t_lstate |= LSTYPEN; 5827502Sroot tq = tp->t_rawq; 5837502Sroot tp->t_rawq.c_cc = 0; 5847502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5857502Sroot while ((c = getc(&tq)) >= 0) 5867502Sroot ttyinput(c, tp); 5877502Sroot tp->t_lstate &= ~LSTYPEN; 5887502Sroot } 5897502Sroot 5907502Sroot /* 5917502Sroot * Place a character on raw TTY input queue, putting in delimiters 5927502Sroot * and waking up top half as needed. 5937502Sroot * Also echo if required. 5947502Sroot * The arguments are the character and the appropriate 5957502Sroot * tty structure. 5967502Sroot */ 5977502Sroot ttyinput(c, tp) 5987625Ssam register c; 5997625Ssam register struct tty *tp; 6007502Sroot { 6017502Sroot register int t_flags; 6027502Sroot int i; 6037502Sroot 6047502Sroot if (tp->t_local&LPENDIN) 6057502Sroot ttypend(tp); 6067502Sroot tk_nin++; 6077502Sroot c &= 0377; 6087502Sroot t_flags = tp->t_flags; 6097502Sroot if (t_flags&TANDEM) 6107502Sroot ttyblock(tp); 6117502Sroot if ((t_flags&RAW)==0) { 6127502Sroot if ((tp->t_lstate&LSTYPEN) == 0) 6137502Sroot c &= 0177; 6147502Sroot /* check for literal nexting very first */ 6157502Sroot if (tp->t_lstate&LSLNCH) { 6167502Sroot c |= 0200; 6177502Sroot tp->t_lstate &= ~LSLNCH; 6187502Sroot } 6197502Sroot if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) { 6207502Sroot if (tp->t_flags&ECHO) 6217502Sroot ttyout("^\b", tp); 6227502Sroot tp->t_lstate |= LSLNCH; 6237502Sroot /* check for output control functions */ 6247502Sroot } else if (c==tun.t_stopc) { 6257502Sroot if ((tp->t_state&TS_TTSTOP)==0) { 6267502Sroot tp->t_state |= TS_TTSTOP; 6277502Sroot (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6287502Sroot return; 6297502Sroot } 6307502Sroot if (c!=tun.t_startc) 6317502Sroot return; 6327502Sroot } else if (c==tun.t_startc) { 6337502Sroot tp->t_state &= ~TS_TTSTOP; 6347502Sroot tp->t_local &= ~LFLUSHO; 6357502Sroot ttstart(tp); 6367502Sroot return; 6377502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) { 6387502Sroot if (tp->t_local & LFLUSHO) 6397502Sroot tp->t_local &= ~LFLUSHO; 6407502Sroot else { 6417502Sroot flushtty(tp, FWRITE); 6427502Sroot ttyecho(c, tp); 6437502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc) 6447502Sroot ttyretype(tp); 6457502Sroot tp->t_local |= LFLUSHO; 6467502Sroot } 6477502Sroot ttstart(tp); 6487502Sroot return; 6497502Sroot } else if (c==tun.t_intrc || c==tun.t_quitc || 6507502Sroot (tp->t_line == NTTYDISC && c==tlun.t_suspc)) { 6517502Sroot if ((tp->t_local & LNOFLSH) == 0) 6527502Sroot flushtty(tp, 6537502Sroot c==tlun.t_suspc ? FREAD : FREAD|FWRITE); 6547502Sroot ttyecho(c, tp); 6557502Sroot c = c==tun.t_intrc ? SIGINT : 6567502Sroot ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP); 6577502Sroot ttsignal(tp, c); 6587502Sroot /* check for buffer editing functions - cooked mode */ 6597502Sroot } else if ((t_flags&CBREAK) == 0) { 6607502Sroot if ((tp->t_lstate&LSQUOT) && 6617502Sroot (c==tp->t_erase||c==tp->t_kill)) { 6627502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6637502Sroot c |= 0200; 6647502Sroot } 6657502Sroot if (c==tp->t_erase) { 6667502Sroot if (tp->t_rawq.c_cc) 6677502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6687502Sroot } else if (c==tp->t_kill) { 6697502Sroot if (tp->t_local&LCRTKIL && 6707502Sroot tp->t_rawq.c_cc == tp->t_rocount) { 6717502Sroot while (tp->t_rawq.c_cc) 6727502Sroot ttyrub(unputc(&tp->t_rawq), tp); 6737502Sroot } else { 6747502Sroot ttyecho(c, tp); 6757502Sroot ttyecho('\n', tp); 6767502Sroot while (getc(&tp->t_rawq) > 0) 6777502Sroot ; 6787502Sroot tp->t_rocount = 0; 6797502Sroot } 6807502Sroot tp->t_lstate = 0; 6817502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) { 6827502Sroot if (tp->t_rawq.c_cc == 0) 6837502Sroot goto out; 6847502Sroot do { 6857502Sroot c = unputc(&tp->t_rawq); 6867502Sroot if (c != ' ' && c != '\t') 6877502Sroot goto erasenb; 6887502Sroot ttyrub(c, tp); 6897502Sroot } while (tp->t_rawq.c_cc); 6907502Sroot goto out; 6917502Sroot erasenb: 6927502Sroot do { 6937502Sroot ttyrub(c, tp); 6947502Sroot if (tp->t_rawq.c_cc == 0) 6957502Sroot goto out; 6967502Sroot c = unputc(&tp->t_rawq); 6977502Sroot } while (c != ' ' && c != '\t'); 6987502Sroot (void) putc(c, &tp->t_rawq); 6997502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) { 7007502Sroot ttyretype(tp); 7017502Sroot /* check for cooked mode input buffer overflow */ 7027502Sroot } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 7037502Sroot ; 7047502Sroot /* put data char in q for user and wakeup if a break char */ 7057502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7067502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG 7077502Sroot && tp->t_line == NTTYDISC) 7087502Sroot (void) ttyoutput(CTRL(g), tp); 7097502Sroot if (!ttbreakc(c, tp)) { 7107502Sroot if (tp->t_rocount++ == 0) 7117502Sroot tp->t_rocol = tp->t_col; 7127502Sroot } else { 7137502Sroot tp->t_rocount = 0; 7147502Sroot catq(&tp->t_rawq, &tp->t_canq); 7157502Sroot /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */ 7167502Sroot ttwakeup(tp); 7177502Sroot } 7187502Sroot tp->t_lstate &= ~LSQUOT; 7197502Sroot if (c == '\\') 7207502Sroot tp->t_lstate |= LSQUOT; 7217502Sroot if (tp->t_lstate&LSERASE) { 7227502Sroot tp->t_lstate &= ~LSERASE; 7237502Sroot (void) ttyoutput('/', tp); 7247502Sroot } 7257502Sroot i = tp->t_col; 7267502Sroot ttyecho(c, tp); 7277502Sroot if (c==tun.t_eofc && tp->t_flags&ECHO) { 7287502Sroot i = MIN(2, tp->t_col - i); 7297502Sroot while (i > 0) { 7307502Sroot (void) ttyoutput('\b', tp); 7317502Sroot i--; 7327502Sroot } 7337502Sroot } 7347502Sroot } 7357502Sroot /* CBREAK mode */ 7367502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) { 7377502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7387502Sroot tp->t_line == NTTYDISC) 7397502Sroot (void) ttyoutput(CTRL(g), tp); 7407502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7417502Sroot ttwakeup(tp); 7427502Sroot ttyecho(c, tp); 7437502Sroot } 7447502Sroot /* RAW mode */ 7457502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) 7467502Sroot flushtty(tp, FREAD|FWRITE); 7477502Sroot else { 7487502Sroot if (putc(c, &tp->t_rawq) >= 0) 7497502Sroot ttwakeup(tp); 7507502Sroot ttyecho(c, tp); 7517502Sroot } 7527502Sroot out: 7537502Sroot if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP && 7547502Sroot tun.t_startc != tun.t_stopc) 7557502Sroot return; 7567502Sroot tp->t_state &= ~TS_TTSTOP; 7577502Sroot tp->t_local &= ~LFLUSHO; 7587502Sroot ttstart(tp); 7597502Sroot } 7607502Sroot 7617502Sroot /* 7627502Sroot * put character on TTY output queue, adding delays, 7637502Sroot * expanding tabs, and handling the CR/NL bit. 7647502Sroot * It is called both from the top half for output, and from 7657502Sroot * interrupt level for echoing. 7667502Sroot * The arguments are the character and the tty structure. 7677502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 7687502Sroot * Must be recursive. 7697502Sroot */ 7707502Sroot ttyoutput(c, tp) 7717502Sroot register c; 7727502Sroot register struct tty *tp; 7737502Sroot { 7747502Sroot register char *colp; 7757502Sroot register ctype; 7767502Sroot 7777502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) { 7787502Sroot if (tp->t_local&LFLUSHO) 7797502Sroot return (-1); 7807502Sroot if (putc(c, &tp->t_outq)) 7817625Ssam return (c); 7827502Sroot tk_nout++; 7837502Sroot return (-1); 7847502Sroot } 7857502Sroot /* 7867502Sroot * Ignore EOT in normal mode to avoid hanging up 7877502Sroot * certain terminals. 7887502Sroot */ 7897502Sroot c &= 0177; 7907502Sroot if (c==CEOT && (tp->t_flags&CBREAK)==0) 7917502Sroot return (-1); 7927502Sroot /* 7937502Sroot * Turn tabs to spaces as required 7947502Sroot */ 7957502Sroot if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 7967502Sroot register int s; 7977502Sroot 7987502Sroot c = 8 - (tp->t_col&7); 7997502Sroot if ((tp->t_local&LFLUSHO) == 0) { 8007502Sroot s = spl5(); /* don't interrupt tabs */ 8017502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8027502Sroot tk_nout += c; 8037502Sroot splx(s); 8047502Sroot } 8057502Sroot tp->t_col += c; 8067502Sroot return (c ? -1 : '\t'); 8077502Sroot } 8087502Sroot tk_nout++; 8097502Sroot /* 8107502Sroot * for upper-case-only terminals, 8117502Sroot * generate escapes. 8127502Sroot */ 8137502Sroot if (tp->t_flags&LCASE) { 8147502Sroot colp = "({)}!|^~'`"; 8157625Ssam while (*colp++) 8167625Ssam if (c == *colp++) { 8177502Sroot if (ttyoutput('\\', tp) >= 0) 8187502Sroot return (c); 8197502Sroot c = colp[-2]; 8207502Sroot break; 8217502Sroot } 8227502Sroot if ('A'<=c && c<='Z') { 8237502Sroot if (ttyoutput('\\', tp) >= 0) 8247502Sroot return (c); 8257502Sroot } else if ('a'<=c && c<='z') 8267502Sroot c += 'A' - 'a'; 8277502Sroot } 8287502Sroot /* 8297502Sroot * turn <nl> to <cr><lf> if desired. 8307502Sroot */ 8317502Sroot if (c=='\n' && tp->t_flags&CRMOD) 8327502Sroot if (ttyoutput('\r', tp) >= 0) 8337502Sroot return (c); 8347502Sroot if (c=='~' && tp->t_local<ILDE) 8357502Sroot c = '`'; 8367502Sroot if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq)) 8377502Sroot return (c); 8387502Sroot /* 8397502Sroot * Calculate delays. 8407502Sroot * The numbers here represent clock ticks 8417502Sroot * and are not necessarily optimal for all terminals. 8427502Sroot * The delays are indicated by characters above 0200. 8437502Sroot * In raw mode there are no delays and the 8447502Sroot * transmission path is 8 bits wide. 8457502Sroot */ 8467502Sroot colp = &tp->t_col; 8477502Sroot ctype = partab[c]; 8487502Sroot c = 0; 8497502Sroot switch (ctype&077) { 8507502Sroot 8517502Sroot case ORDINARY: 8527502Sroot (*colp)++; 8537502Sroot 8547502Sroot case CONTROL: 8557502Sroot break; 8567502Sroot 8577502Sroot case BACKSPACE: 8587502Sroot if (*colp) 8597502Sroot (*colp)--; 8607502Sroot break; 8617502Sroot 8627502Sroot case NEWLINE: 8637502Sroot ctype = (tp->t_flags >> 8) & 03; 8647625Ssam if (ctype == 1) { /* tty 37 */ 8657502Sroot if (*colp) 8667502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 8677502Sroot } else 8687625Ssam if (ctype == 2) { /* vt05 */ 8697502Sroot c = 6; 8707502Sroot } 8717502Sroot *colp = 0; 8727502Sroot break; 8737502Sroot 8747502Sroot case TAB: 8757502Sroot ctype = (tp->t_flags >> 10) & 03; 8767625Ssam if (ctype == 1) { /* tty 37 */ 8777502Sroot c = 1 - (*colp | ~07); 8787625Ssam if (c < 5) 8797502Sroot c = 0; 8807502Sroot } 8817502Sroot *colp |= 07; 8827502Sroot (*colp)++; 8837502Sroot break; 8847502Sroot 8857502Sroot case VTAB: 8867625Ssam if (tp->t_flags & VTDELAY) /* tty 37 */ 8877502Sroot c = 0177; 8887502Sroot break; 8897502Sroot 8907502Sroot case RETURN: 8917502Sroot ctype = (tp->t_flags >> 12) & 03; 8927625Ssam if (ctype == 1) { /* tn 300 */ 8937502Sroot c = 5; 8947625Ssam } else if (ctype == 2) { /* ti 700 */ 8957502Sroot c = 10; 8967625Ssam } else if (ctype == 3) { /* concept 100 */ 8977502Sroot int i; 8987502Sroot if ((i = *colp) >= 0) 8997502Sroot for (; i<9; i++) 9007502Sroot (void) putc(0177, &tp->t_outq); 9017502Sroot } 9027502Sroot *colp = 0; 9037502Sroot } 9047625Ssam if (c && (tp->t_local&LFLUSHO) == 0) 9057502Sroot (void) putc(c|0200, &tp->t_outq); 9067502Sroot return (-1); 9077502Sroot } 9087502Sroot 9097502Sroot /* 9107502Sroot * Called from device's read routine after it has 9117502Sroot * calculated the tty-structure given as argument. 9127502Sroot */ 9137722Swnj ttread(tp, uio) 9147625Ssam register struct tty *tp; 9157722Swnj struct uio *uio; 9167502Sroot { 9177502Sroot register struct clist *qp; 9187502Sroot register c, first; 9198520Sroot int error = 0; 9207502Sroot 9217502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9228520Sroot return (EIO); 9237502Sroot loop: 9247502Sroot (void) spl5(); 9257502Sroot if (tp->t_local&LPENDIN) 9267502Sroot ttypend(tp); 9277502Sroot (void) spl0(); 9287502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9297502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9307502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9317502Sroot /* 9327502Sroot (u.u_procp->p_flag&SDETACH) || 9337502Sroot */ 9347502Sroot u.u_procp->p_flag&SVFORK) 9358520Sroot return (EIO); 9367502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9377502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9387502Sroot } 9397502Sroot if (tp->t_flags&RAW) { 9407502Sroot (void) spl5(); 9417502Sroot if (tp->t_rawq.c_cc <= 0) { 9427502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9437502Sroot (tp->t_state&TS_NBIO)) { 9447502Sroot (void) spl0(); 9458520Sroot return (EWOULDBLOCK); 9467502Sroot } 9477502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9487502Sroot (void) spl0(); 9497502Sroot goto loop; 9507502Sroot } 9517502Sroot (void) spl0(); 9527722Swnj while (tp->t_rawq.c_cc && uio->uio_iovcnt) { 9538520Sroot error = passuc(getc(&tp->t_rawq), uio); 9548520Sroot if (error) 9557722Swnj break; 9567722Swnj } 9578520Sroot return (error); 9587502Sroot } else { 9597502Sroot qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq; 9607502Sroot (void) spl5(); 9617502Sroot if (qp->c_cc <= 0) { 9627502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9637502Sroot (tp->t_state&TS_NBIO)) { 9647502Sroot (void) spl0(); 9658520Sroot return (EWOULDBLOCK); 9667502Sroot } 9677502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9687502Sroot (void) spl0(); 9697502Sroot goto loop; 9707502Sroot } 9717502Sroot (void) spl0(); 9727502Sroot first = 1; 9737502Sroot while ((c = getc(qp)) >= 0) { 9747502Sroot if (tp->t_flags&CRMOD && c == '\r') 9757502Sroot c = '\n'; 9767502Sroot if (tp->t_flags&LCASE && c <= 0177) 9777502Sroot if (tp->t_lstate&LSBKSL) { 9787502Sroot if (maptab[c]) 9797502Sroot c = maptab[c]; 9807502Sroot tp->t_lstate &= ~LSBKSL; 9817502Sroot } else if (c >= 'A' && c <= 'Z') 9827502Sroot c += 'a' - 'A'; 9837502Sroot else if (c == '\\') { 9847502Sroot tp->t_lstate |= LSBKSL; 9857502Sroot continue; 9867502Sroot } 9877658Ssam if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) { 9887502Sroot ttsignal(tp, SIGTSTP); 9897502Sroot if (first) { 9907502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9917502Sroot goto loop; 9927502Sroot } 9937502Sroot break; 9947502Sroot } 9957502Sroot if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0) 9967502Sroot break; 9978520Sroot error = passuc(c & 0177, uio); 9988520Sroot if (error) 9997502Sroot break; 10007722Swnj if (uio->uio_iovcnt == 0) 10017722Swnj break; 10027502Sroot if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp)) 10037502Sroot break; 10047502Sroot first = 0; 10057502Sroot } 10067502Sroot tp->t_lstate &= ~LSBKSL; 10077502Sroot } 10087502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 10097502Sroot if (putc(tun.t_startc, &tp->t_outq)==0) { 10107502Sroot tp->t_state &= ~TS_TBLOCK; 10117502Sroot ttstart(tp); 10127502Sroot } 10137502Sroot tp->t_char = 0; 10147502Sroot } 10158520Sroot return (error); 10167502Sroot } 10177502Sroot 10187502Sroot /* 10197502Sroot * Called from the device's write routine after it has 10207502Sroot * calculated the tty-structure given as argument. 10217502Sroot */ 10227822Sroot ttwrite(tp, uio) 10237625Ssam register struct tty *tp; 10247822Sroot struct uio *uio; 10257502Sroot { 10267502Sroot #ifdef vax 10277502Sroot /* 10287502Sroot * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 10297502Sroot * AND MUST NOT BE CHANGED WITHOUT PATCHING 10307502Sroot * THE 'ASM' INLINES BELOW. WATCH OUT. 10317502Sroot */ 10327502Sroot #endif 10337502Sroot register char *cp; 10347502Sroot register int cc, ce; 10357502Sroot register i; 10367502Sroot char obuf[OBUFSIZ]; 10377502Sroot register c; 10387502Sroot int hiwat = TTHIWAT(tp); 10397822Sroot int cnt = uio->uio_resid; 10408520Sroot int error = 0; 10417502Sroot 10427502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10438520Sroot return (EIO); 10447502Sroot loop: 10457502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 10467502Sroot (tp->t_local<OSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 10477502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 10487502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 10497502Sroot /* 10507502Sroot && 10517502Sroot (u.u_procp->p_flag&SDETACH)==0) { 10527502Sroot */ 10537502Sroot ) { 10547502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 10557502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10567502Sroot } 10577822Sroot while (uio->uio_resid > 0) { 10587822Sroot cc = uio->uio_iov->iov_len; 10597822Sroot if (cc == 0) { 10607822Sroot uio->uio_iovcnt--; 10617822Sroot uio->uio_iov++; 10627822Sroot if (uio->uio_iovcnt < 0) 10637822Sroot panic("ttwrite"); 10647822Sroot continue; 10657822Sroot } 10667822Sroot if (cc > OBUFSIZ) 10677822Sroot cc = OBUFSIZ; 10687502Sroot cp = obuf; 10698520Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 10708520Sroot if (error) 10717502Sroot break; 10727502Sroot if (tp->t_outq.c_cc > hiwat) 10737502Sroot goto ovhiwat; 10747502Sroot if (tp->t_local&LFLUSHO) 10757502Sroot continue; 10767502Sroot if (tp->t_flags&LCASE || tp->t_local<ILDE) { 10777502Sroot while (cc) { 10787502Sroot c = *cp++; 10797502Sroot tp->t_rocount = 0; 10807625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 10817502Sroot /* out of clists, wait a bit */ 10827502Sroot ttstart(tp); 10837502Sroot sleep((caddr_t)&lbolt, TTOPRI); 10847502Sroot tp->t_rocount = 0; 10857502Sroot } 10867502Sroot --cc; 10877502Sroot if (tp->t_outq.c_cc > hiwat) 10887502Sroot goto ovhiwat; 10897502Sroot } 10907502Sroot continue; 10917502Sroot } 10927502Sroot while (cc) { 10937502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 10947502Sroot ce = cc; 10957502Sroot else { 10967502Sroot #ifdef vax 10977502Sroot asm(" scanc r9,(r10),_partab,$077"); 10987502Sroot asm(" subl3 r0,r9,r8"); 10997502Sroot #else 11007502Sroot ce=0; 11017625Ssam while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc)) 11027502Sroot ce++; 11037502Sroot #endif 11047502Sroot if (ce==0) { 11057502Sroot tp->t_rocount = 0; 11067502Sroot if (ttyoutput(*cp, tp) >= 0) { 11077502Sroot ttstart(tp); 11087502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11097502Sroot continue; 11107502Sroot } 11117502Sroot cp++; 11127502Sroot cc--; 11137502Sroot if (tp->t_outq.c_cc > hiwat) 11147502Sroot goto ovhiwat; 11157502Sroot } 11167502Sroot } 11177502Sroot tp->t_rocount = 0; 11187502Sroot i=b_to_q(cp,ce,&tp->t_outq); 11197502Sroot ce-=i; 11207502Sroot tk_nout+=ce; 11217502Sroot tp->t_col+=ce; 11227502Sroot cp+=ce; 11237502Sroot cc-=ce; 11247502Sroot if (i) { 11257502Sroot ttstart(tp); 11267502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11277502Sroot } 11287502Sroot if (ce || tp->t_outq.c_cc > hiwat) 11297502Sroot goto ovhiwat; 11307502Sroot } 11317502Sroot } 11327502Sroot ttstart(tp); 11338520Sroot return (error); 11347502Sroot 11357502Sroot ovhiwat: 11367502Sroot (void) spl5(); 11377822Sroot uio->uio_iov->iov_base -= cc; 11387822Sroot uio->uio_iov->iov_len += cc; 11397822Sroot uio->uio_resid += cc; 11407822Sroot uio->uio_offset -= cc; 11417502Sroot if (tp->t_outq.c_cc <= hiwat) { 11427502Sroot (void) spl0(); 11437502Sroot goto loop; 11447502Sroot } 11457502Sroot ttstart(tp); 11467502Sroot if (tp->t_state & TS_NBIO) { 11477822Sroot if (uio->uio_resid == cnt) 11488520Sroot return (EWOULDBLOCK); 11498520Sroot return (0); 11507502Sroot } 11517502Sroot tp->t_state |= TS_ASLEEP; 11527502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 11537502Sroot (void) spl0(); 11547502Sroot goto loop; 11557502Sroot } 11567502Sroot 11577502Sroot /* 11587502Sroot * Rubout one character from the rawq of tp 11597502Sroot * as cleanly as possible. 11607502Sroot */ 11617502Sroot ttyrub(c, tp) 11627625Ssam register c; 11637625Ssam register struct tty *tp; 11647502Sroot { 11657502Sroot register char *cp; 11667502Sroot register int savecol; 11677502Sroot int s; 11687502Sroot char *nextc(); 11697502Sroot 11707502Sroot if ((tp->t_flags&ECHO)==0) 11717502Sroot return; 11727502Sroot tp->t_local &= ~LFLUSHO; 11737502Sroot c &= 0377; 11747502Sroot if (tp->t_local&LCRTBS) { 11757502Sroot if (tp->t_rocount == 0) { 11767502Sroot /* 11777502Sroot * Screwed by ttwrite; retype 11787502Sroot */ 11797502Sroot ttyretype(tp); 11807502Sroot return; 11817502Sroot } 11827502Sroot if (c==('\t'|0200) || c==('\n'|0200)) 11837502Sroot ttyrubo(tp, 2); 11847625Ssam else switch (partab[c&=0177] & 0177) { 11857502Sroot 11867502Sroot case ORDINARY: 11877502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 11887502Sroot ttyrubo(tp, 2); 11897502Sroot else 11907502Sroot ttyrubo(tp, 1); 11917502Sroot break; 11927502Sroot 11937502Sroot case VTAB: 11947502Sroot case BACKSPACE: 11957502Sroot case CONTROL: 11967502Sroot case RETURN: 11977502Sroot if (tp->t_local & LCTLECH) 11987502Sroot ttyrubo(tp, 2); 11997502Sroot break; 12007502Sroot 12017502Sroot case TAB: 12027502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 12037502Sroot ttyretype(tp); 12047502Sroot return; 12057502Sroot } 12067502Sroot s = spl5(); 12077502Sroot savecol = tp->t_col; 12087502Sroot tp->t_lstate |= LSCNTTB; 12097502Sroot tp->t_local |= LFLUSHO; 12107502Sroot tp->t_col = tp->t_rocol; 12117502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12127502Sroot ttyecho(*cp, tp); 12137502Sroot tp->t_local &= ~LFLUSHO; 12147502Sroot tp->t_lstate &= ~LSCNTTB; 12157502Sroot splx(s); 12167502Sroot /* 12177502Sroot * savecol will now be length of the tab 12187502Sroot */ 12197502Sroot savecol -= tp->t_col; 12207502Sroot tp->t_col += savecol; 12217502Sroot if (savecol > 8) 12227502Sroot savecol = 8; /* overflow screw */ 12237502Sroot while (--savecol >= 0) 12247502Sroot (void) ttyoutput('\b', tp); 12257502Sroot break; 12267502Sroot 12277502Sroot default: 12287502Sroot panic("ttyrub"); 12297502Sroot } 12307502Sroot } else if (tp->t_local&LPRTERA) { 12317502Sroot if ((tp->t_lstate&LSERASE) == 0) { 12327502Sroot (void) ttyoutput('\\', tp); 12337502Sroot tp->t_lstate |= LSERASE; 12347502Sroot } 12357502Sroot ttyecho(c, tp); 12367502Sroot } else 12377502Sroot ttyecho(tp->t_erase, tp); 12387502Sroot tp->t_rocount--; 12397502Sroot } 12407502Sroot 12417502Sroot /* 12427502Sroot * Crt back over cnt chars perhaps 12437502Sroot * erasing them. 12447502Sroot */ 12457502Sroot ttyrubo(tp, cnt) 12467625Ssam register struct tty *tp; 12477625Ssam int cnt; 12487502Sroot { 12497502Sroot 12507502Sroot while (--cnt >= 0) 12517502Sroot ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp); 12527502Sroot } 12537502Sroot 12547502Sroot /* 12557502Sroot * Reprint the rawq line. 12567502Sroot * We assume c_cc has already been checked. 12577502Sroot */ 12587502Sroot ttyretype(tp) 12597625Ssam register struct tty *tp; 12607502Sroot { 12617502Sroot register char *cp; 12627502Sroot char *nextc(); 12637502Sroot int s; 12647502Sroot 12657502Sroot if (tlun.t_rprntc != 0377) 12667502Sroot ttyecho(tlun.t_rprntc, tp); 12677502Sroot (void) ttyoutput('\n', tp); 12687502Sroot s = spl5(); 12697502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 12707502Sroot ttyecho(*cp, tp); 12717502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12727502Sroot ttyecho(*cp, tp); 12737502Sroot tp->t_lstate &= ~LSERASE; 12747502Sroot splx(s); 12757502Sroot tp->t_rocount = tp->t_rawq.c_cc; 12767502Sroot tp->t_rocol = 0; 12777502Sroot } 12787502Sroot 12797502Sroot /* 12807502Sroot * Echo a typed character to the terminal 12817502Sroot */ 12827502Sroot ttyecho(c, tp) 12837625Ssam register c; 12847625Ssam register struct tty *tp; 12857502Sroot { 12867502Sroot 12877502Sroot if ((tp->t_lstate & LSCNTTB) == 0) 12887502Sroot tp->t_local &= ~LFLUSHO; 12897502Sroot if ((tp->t_flags&ECHO) == 0) 12907502Sroot return; 12917502Sroot c &= 0377; 12927502Sroot if (tp->t_flags&RAW) { 12937502Sroot (void) ttyoutput(c, tp); 12947502Sroot return; 12957502Sroot } 12967502Sroot if (c == '\r' && tp->t_flags&CRMOD) 12977502Sroot c = '\n'; 12987502Sroot if (tp->t_local&LCTLECH) { 12997502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 13007502Sroot (void) ttyoutput('^', tp); 13017502Sroot c &= 0177; 13027502Sroot if (c == 0177) 13037502Sroot c = '?'; 13047502Sroot else if (tp->t_flags&LCASE) 13057502Sroot c += 'a' - 1; 13067502Sroot else 13077502Sroot c += 'A' - 1; 13087502Sroot } 13097502Sroot } 13107502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 13117502Sroot c += 'a' - 'A'; 13127502Sroot (void) ttyoutput(c & 0177, tp); 13137502Sroot } 13147502Sroot 13157502Sroot /* 13167502Sroot * Is c a break char for tp? 13177502Sroot */ 13187502Sroot ttbreakc(c, tp) 13197625Ssam register c; 13207625Ssam register struct tty *tp; 13217502Sroot { 13227502Sroot return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc || 13237502Sroot c == '\r' && (tp->t_flags&CRMOD)); 13247502Sroot } 13257502Sroot 13267502Sroot /* 13277502Sroot * send string cp to tp 13287502Sroot */ 13297502Sroot ttyout(cp, tp) 13307625Ssam register char *cp; 13317625Ssam register struct tty *tp; 13327502Sroot { 13337502Sroot register char c; 13347502Sroot 13357502Sroot while (c = *cp++) 13367502Sroot (void) ttyoutput(c, tp); 13377502Sroot } 13387502Sroot 13397502Sroot ttwakeup(tp) 13407502Sroot struct tty *tp; 13417502Sroot { 13427502Sroot 13437502Sroot if (tp->t_rsel) { 13447502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 13457502Sroot tp->t_state &= ~TS_RCOLL; 13467502Sroot tp->t_rsel = 0; 13477502Sroot } 13487502Sroot wakeup((caddr_t)&tp->t_rawq); 13497502Sroot } 13507502Sroot 13517502Sroot ttsignal(tp, signo) 13527502Sroot struct tty *tp; 13537502Sroot int signo; 13547502Sroot { 13557502Sroot 13567502Sroot gsignal(tp->t_pgrp, signo); 13577502Sroot } 1358