1*8154Sroot /* tty.c 4.29 82/09/12 */ 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" 19*8154Sroot #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 { 2461904Swnj int dev; 24739Sbill extern int nldisp; 24839Sbill 249903Sbill /* 250915Sbill * This is especially so that isatty() will 251915Sbill * fail when carrier is gone. 252915Sbill */ 2535408Swnj if ((tp->t_state&TS_CARR_ON) == 0) { 254915Sbill u.u_error = EBADF; 255915Sbill return (1); 256915Sbill } 257915Sbill 2581904Swnj dev = tp->t_dev; 259915Sbill /* 260903Sbill * If the ioctl involves modification, 261903Sbill * insist on being able to write the device, 262903Sbill * and hang if in the background. 263903Sbill */ 2647625Ssam switch (com) { 26539Sbill 266915Sbill case TIOCSETD: 267915Sbill case TIOCSETP: 268915Sbill case TIOCSETN: 269903Sbill case TIOCFLUSH: 270903Sbill case TIOCSETC: 271903Sbill case TIOCSLTC: 272903Sbill case TIOCSPGRP: 273903Sbill case TIOCLBIS: 274903Sbill case TIOCLBIC: 275903Sbill case TIOCLSET: 276915Sbill /* this is reasonable, but impractical... 277903Sbill if ((flag & FWRITE) == 0) { 278903Sbill u.u_error = EBADF; 279903Sbill return (1); 280903Sbill } 281915Sbill */ 282903Sbill while (tp->t_line == NTTYDISC && 283903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 284903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 285903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2865626Swnj u.u_signal[SIGTTOU] != SIG_HOLD 2875626Swnj /* 2885626Swnj && 289903Sbill (u.u_procp->p_flag&SDETACH)==0) { 2905626Swnj */ 2915626Swnj ) { 292903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 293903Sbill sleep((caddr_t)&lbolt, TTOPRI); 294903Sbill } 295903Sbill break; 296903Sbill } 297903Sbill 29839Sbill /* 299903Sbill * Process the ioctl. 30039Sbill */ 3017625Ssam switch (com) { 302903Sbill 303903Sbill /* 304903Sbill * Get discipline number 305903Sbill */ 30639Sbill case TIOCGETD: 3077625Ssam *(int *)data = tp->t_line; 30839Sbill break; 30939Sbill 31039Sbill /* 311903Sbill * Set line discipline 31239Sbill */ 3137625Ssam case TIOCSETD: { 3147625Ssam register int t = *(int *)data; 3157625Ssam 31639Sbill if (t >= nldisp) { 31739Sbill u.u_error = ENXIO; 31839Sbill break; 31939Sbill } 320174Sbill (void) spl5(); 32139Sbill if (tp->t_line) 32239Sbill (*linesw[tp->t_line].l_close)(tp); 32339Sbill if (t) 3247625Ssam (*linesw[t].l_open)(dev, tp); 32539Sbill if (u.u_error==0) 32639Sbill tp->t_line = t; 327174Sbill (void) spl0(); 32839Sbill break; 3297625Ssam } 33039Sbill 33139Sbill /* 3325614Swnj * Prevent more opens on channel 3335614Swnj */ 3345614Swnj case TIOCEXCL: 3355614Swnj tp->t_state |= TS_XCLUDE; 3365614Swnj break; 3375614Swnj 3385614Swnj case TIOCNXCL: 3395614Swnj tp->t_state &= ~TS_XCLUDE; 3405614Swnj break; 3415614Swnj 3425614Swnj /* 34339Sbill * Set new parameters 34439Sbill */ 34539Sbill case TIOCSETP: 3467625Ssam case TIOCSETN: { 3477625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3487625Ssam struct clist tq; 3497625Ssam 350121Sbill (void) spl5(); 3517625Ssam if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP) 3524484Swnj wflushtty(tp); 3537625Ssam else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) { 3547625Ssam if (sg->sg_flags & CBREAK) { 3554484Swnj catq(&tp->t_rawq, &tp->t_canq); 3564484Swnj tq = tp->t_rawq; 3574484Swnj tp->t_rawq = tp->t_canq; 3584484Swnj tp->t_canq = tq; 3594484Swnj } else { 3604484Swnj tp->t_local |= LPENDIN; 3614484Swnj ttwakeup(tp); 362174Sbill } 363174Sbill } 3647625Ssam tp->t_ispeed = sg->sg_ispeed; 3657625Ssam tp->t_ospeed = sg->sg_ospeed; 3667625Ssam tp->t_erase = sg->sg_erase; 3677625Ssam tp->t_kill = sg->sg_kill; 3687625Ssam tp->t_flags = sg->sg_flags; 3693941Sbugs if (tp->t_flags & RAW) { 3705408Swnj tp->t_state &= ~TS_TTSTOP; 3713941Sbugs ttstart(tp); 3723941Sbugs } 373121Sbill (void) spl0(); 37439Sbill break; 3757625Ssam } 37639Sbill 37739Sbill /* 378903Sbill * Send current parameters to user 37939Sbill */ 3807625Ssam case TIOCGETP: { 3817625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3827625Ssam 3837625Ssam sg->sg_ispeed = tp->t_ispeed; 3847625Ssam sg->sg_ospeed = tp->t_ospeed; 3857625Ssam sg->sg_erase = tp->t_erase; 3867625Ssam sg->sg_kill = tp->t_kill; 3877625Ssam sg->sg_flags = tp->t_flags; 38839Sbill break; 3897625Ssam } 39039Sbill 39139Sbill /* 39239Sbill * Hang up line on last close 39339Sbill */ 39439Sbill case TIOCHPCL: 3955408Swnj tp->t_state |= TS_HUPCLS; 39639Sbill break; 39739Sbill 3983942Sbugs case TIOCFLUSH: { 3997625Ssam register int flags = *(int *)data; 4007625Ssam 4017625Ssam if (flags == 0) 4023942Sbugs flags = FREAD|FWRITE; 4037625Ssam else 4047625Ssam flags &= FREAD|FWRITE; 4053942Sbugs flushtty(tp, flags); 40639Sbill break; 4073944Sbugs } 40839Sbill 4097625Ssam case FIONBIO: 4107625Ssam if (*(int *)data) 4115408Swnj tp->t_state |= TS_NBIO; 4125408Swnj else 4135408Swnj tp->t_state &= ~TS_NBIO; 4145408Swnj break; 4155408Swnj 4167625Ssam case FIOASYNC: 4177625Ssam if (*(int *)data) 4186216Swnj tp->t_state |= TS_ASYNC; 4196216Swnj else 4206216Swnj tp->t_state &= ~TS_ASYNC; 4216216Swnj break; 4226216Swnj 42339Sbill /* 424903Sbill * Set and fetch special characters 42539Sbill */ 42639Sbill case TIOCSETC: 4277625Ssam bcopy(data, (caddr_t)&tun, sizeof (struct tchars)); 42839Sbill break; 42939Sbill 43039Sbill case TIOCGETC: 4317625Ssam bcopy((caddr_t)&tun, data, sizeof (struct tchars)); 43239Sbill break; 43339Sbill 434174Sbill /* local ioctls */ 435903Sbill /* 436903Sbill * Set/get local special characters. 437903Sbill */ 438174Sbill case TIOCSLTC: 4397625Ssam bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars)); 440174Sbill break; 441174Sbill 442174Sbill case TIOCGLTC: 4437625Ssam bcopy((caddr_t)&tlun, data, sizeof (struct ltchars)); 444174Sbill break; 445174Sbill 446903Sbill /* 447903Sbill * Return number of characters immediately available. 448903Sbill */ 4497625Ssam case FIONREAD: 4507625Ssam *(off_t *)data = ttnread(tp); 451174Sbill break; 452174Sbill 453174Sbill /* 454174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 455174Sbill */ 456174Sbill case TIOCSPGRP: 4577625Ssam tp->t_pgrp = *(int *)data; 458174Sbill break; 459174Sbill 460174Sbill case TIOCGPGRP: 4617625Ssam *(int *)data = tp->t_pgrp; 462174Sbill break; 463174Sbill 464174Sbill /* 465174Sbill * Modify local mode word. 466174Sbill */ 467174Sbill case TIOCLBIS: 4687625Ssam tp->t_local |= *(int *)data; 469174Sbill break; 470174Sbill 471174Sbill case TIOCLBIC: 4727625Ssam tp->t_local &= ~(*(int *)data); 473174Sbill break; 474174Sbill 475174Sbill case TIOCLSET: 4767625Ssam tp->t_local = *(int *)data; 477174Sbill break; 478174Sbill 479174Sbill case TIOCLGET: 4807625Ssam *(int *)data = tp->t_local; 481174Sbill break; 482174Sbill 4837625Ssam case TIOCSTOP: { 4847625Ssam int s = spl5(); 485213Sbill 4865573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4875573Swnj tp->t_state |= TS_TTSTOP; 4885573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4895573Swnj } 4907625Ssam splx(s); 4915573Swnj break; 4927625Ssam } 4935573Swnj 4947625Ssam case TIOCSTART: { 4957625Ssam int s = spl5(); 4967625Ssam 4975573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4985573Swnj tp->t_state &= ~TS_TTSTOP; 4995573Swnj tp->t_local &= ~LFLUSHO; 5005573Swnj ttstart(tp); 5015573Swnj } 5027625Ssam splx(s); 5035573Swnj break; 5047625Ssam } 5055573Swnj 506174Sbill /* end of locals */ 507887Sbill 50839Sbill default: 5097625Ssam return (0); 51039Sbill } 5117625Ssam return (1); 51239Sbill } 5134484Swnj 5144484Swnj ttnread(tp) 5154484Swnj struct tty *tp; 5164484Swnj { 5174484Swnj int nread = 0; 5184484Swnj 5194484Swnj if (tp->t_local & LPENDIN) 5204484Swnj ttypend(tp); 5214484Swnj nread = tp->t_canq.c_cc; 5224484Swnj if (tp->t_flags & (RAW|CBREAK)) 5234484Swnj nread += tp->t_rawq.c_cc; 5244484Swnj return (nread); 5254484Swnj } 5264484Swnj 5275408Swnj ttselect(dev, rw) 5284484Swnj dev_t dev; 5295408Swnj int rw; 5304484Swnj { 5314484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5324484Swnj int nread; 5335408Swnj int s = spl5(); 5344484Swnj 5355408Swnj switch (rw) { 5364484Swnj 5374484Swnj case FREAD: 5384484Swnj nread = ttnread(tp); 5394484Swnj if (nread > 0) 5405408Swnj goto win; 5414938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5425408Swnj tp->t_state |= TS_RCOLL; 5434484Swnj else 5444484Swnj tp->t_rsel = u.u_procp; 5455408Swnj break; 5464484Swnj 5475408Swnj case FWRITE: 5485408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5495408Swnj goto win; 5505408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5515408Swnj tp->t_state |= TS_WCOLL; 5525408Swnj else 5535408Swnj tp->t_wsel = u.u_procp; 5545408Swnj break; 5554484Swnj } 5565408Swnj splx(s); 5575408Swnj return (0); 5585408Swnj win: 5595408Swnj splx(s); 5605408Swnj return (1); 5614484Swnj } 5627436Skre 5637502Sroot #define OBUFSIZ 100 5647502Sroot 5657502Sroot /* 5667502Sroot * routine called on opens while tp->t_line == NTTYDISC 5677502Sroot * establishes a process group for distribution of 5687502Sroot * quits and interrupts from the tty. 5697502Sroot * (actually, pp->p_pgrp can't be 0 when this routine 5707502Sroot * is called since NTTYDISC is not the default discipline) 5717502Sroot */ 5727502Sroot ttyopen(dev, tp) 5737625Ssam dev_t dev; 5747625Ssam register struct tty *tp; 5757502Sroot { 5767502Sroot register struct proc *pp; 5777502Sroot 5787502Sroot pp = u.u_procp; 5797502Sroot tp->t_dev = dev; 5807625Ssam if (pp->p_pgrp == 0) { 5817502Sroot u.u_ttyp = tp; 5827502Sroot u.u_ttyd = dev; 5837502Sroot if (tp->t_pgrp == 0) 5847502Sroot tp->t_pgrp = pp->p_pid; 5857502Sroot pp->p_pgrp = tp->t_pgrp; 5867502Sroot } 5877502Sroot tp->t_state &= ~TS_WOPEN; 5887502Sroot tp->t_state |= TS_ISOPEN; 5897502Sroot if (tp->t_line != NTTYDISC) 5907502Sroot wflushtty(tp); 5917502Sroot } 5927502Sroot 5937502Sroot /* 5947502Sroot * clean tp on last close 5957502Sroot */ 5967502Sroot ttyclose(tp) 5977625Ssam register struct tty *tp; 5987502Sroot { 5997502Sroot 6007502Sroot if (tp->t_line) { 6017502Sroot wflushtty(tp); 6027502Sroot tp->t_line = 0; 6037502Sroot return; 6047502Sroot } 6057502Sroot tp->t_pgrp = 0; 6067502Sroot wflushtty(tp); 6077502Sroot tp->t_state = 0; 6087502Sroot } 6097502Sroot 6107502Sroot /* 6117502Sroot * reinput pending characters after state switch 6127502Sroot * call at spl5(). 6137502Sroot */ 6147502Sroot ttypend(tp) 6157625Ssam register struct tty *tp; 6167502Sroot { 6177502Sroot struct clist tq; 6187502Sroot register c; 6197502Sroot 6207502Sroot tp->t_local &= ~LPENDIN; 6217502Sroot tp->t_lstate |= LSTYPEN; 6227502Sroot tq = tp->t_rawq; 6237502Sroot tp->t_rawq.c_cc = 0; 6247502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6257502Sroot while ((c = getc(&tq)) >= 0) 6267502Sroot ttyinput(c, tp); 6277502Sroot tp->t_lstate &= ~LSTYPEN; 6287502Sroot } 6297502Sroot 6307502Sroot /* 6317502Sroot * Place a character on raw TTY input queue, putting in delimiters 6327502Sroot * and waking up top half as needed. 6337502Sroot * Also echo if required. 6347502Sroot * The arguments are the character and the appropriate 6357502Sroot * tty structure. 6367502Sroot */ 6377502Sroot ttyinput(c, tp) 6387625Ssam register c; 6397625Ssam register struct tty *tp; 6407502Sroot { 6417502Sroot register int t_flags; 6427502Sroot int i; 6437502Sroot 6447502Sroot if (tp->t_local&LPENDIN) 6457502Sroot ttypend(tp); 6467502Sroot tk_nin++; 6477502Sroot c &= 0377; 6487502Sroot t_flags = tp->t_flags; 6497502Sroot if (t_flags&TANDEM) 6507502Sroot ttyblock(tp); 6517502Sroot if ((t_flags&RAW)==0) { 6527502Sroot if ((tp->t_lstate&LSTYPEN) == 0) 6537502Sroot c &= 0177; 6547502Sroot /* check for literal nexting very first */ 6557502Sroot if (tp->t_lstate&LSLNCH) { 6567502Sroot c |= 0200; 6577502Sroot tp->t_lstate &= ~LSLNCH; 6587502Sroot } 6597502Sroot if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) { 6607502Sroot if (tp->t_flags&ECHO) 6617502Sroot ttyout("^\b", tp); 6627502Sroot tp->t_lstate |= LSLNCH; 6637502Sroot /* check for output control functions */ 6647502Sroot } else if (c==tun.t_stopc) { 6657502Sroot if ((tp->t_state&TS_TTSTOP)==0) { 6667502Sroot tp->t_state |= TS_TTSTOP; 6677502Sroot (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6687502Sroot return; 6697502Sroot } 6707502Sroot if (c!=tun.t_startc) 6717502Sroot return; 6727502Sroot } else if (c==tun.t_startc) { 6737502Sroot tp->t_state &= ~TS_TTSTOP; 6747502Sroot tp->t_local &= ~LFLUSHO; 6757502Sroot ttstart(tp); 6767502Sroot return; 6777502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) { 6787502Sroot if (tp->t_local & LFLUSHO) 6797502Sroot tp->t_local &= ~LFLUSHO; 6807502Sroot else { 6817502Sroot flushtty(tp, FWRITE); 6827502Sroot ttyecho(c, tp); 6837502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc) 6847502Sroot ttyretype(tp); 6857502Sroot tp->t_local |= LFLUSHO; 6867502Sroot } 6877502Sroot ttstart(tp); 6887502Sroot return; 6897502Sroot } else if (c==tun.t_intrc || c==tun.t_quitc || 6907502Sroot (tp->t_line == NTTYDISC && c==tlun.t_suspc)) { 6917502Sroot if ((tp->t_local & LNOFLSH) == 0) 6927502Sroot flushtty(tp, 6937502Sroot c==tlun.t_suspc ? FREAD : FREAD|FWRITE); 6947502Sroot ttyecho(c, tp); 6957502Sroot c = c==tun.t_intrc ? SIGINT : 6967502Sroot ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP); 6977502Sroot ttsignal(tp, c); 6987502Sroot /* check for buffer editing functions - cooked mode */ 6997502Sroot } else if ((t_flags&CBREAK) == 0) { 7007502Sroot if ((tp->t_lstate&LSQUOT) && 7017502Sroot (c==tp->t_erase||c==tp->t_kill)) { 7027502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7037502Sroot c |= 0200; 7047502Sroot } 7057502Sroot if (c==tp->t_erase) { 7067502Sroot if (tp->t_rawq.c_cc) 7077502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7087502Sroot } else if (c==tp->t_kill) { 7097502Sroot if (tp->t_local&LCRTKIL && 7107502Sroot tp->t_rawq.c_cc == tp->t_rocount) { 7117502Sroot while (tp->t_rawq.c_cc) 7127502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7137502Sroot } else { 7147502Sroot ttyecho(c, tp); 7157502Sroot ttyecho('\n', tp); 7167502Sroot while (getc(&tp->t_rawq) > 0) 7177502Sroot ; 7187502Sroot tp->t_rocount = 0; 7197502Sroot } 7207502Sroot tp->t_lstate = 0; 7217502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) { 7227502Sroot if (tp->t_rawq.c_cc == 0) 7237502Sroot goto out; 7247502Sroot do { 7257502Sroot c = unputc(&tp->t_rawq); 7267502Sroot if (c != ' ' && c != '\t') 7277502Sroot goto erasenb; 7287502Sroot ttyrub(c, tp); 7297502Sroot } while (tp->t_rawq.c_cc); 7307502Sroot goto out; 7317502Sroot erasenb: 7327502Sroot do { 7337502Sroot ttyrub(c, tp); 7347502Sroot if (tp->t_rawq.c_cc == 0) 7357502Sroot goto out; 7367502Sroot c = unputc(&tp->t_rawq); 7377502Sroot } while (c != ' ' && c != '\t'); 7387502Sroot (void) putc(c, &tp->t_rawq); 7397502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) { 7407502Sroot ttyretype(tp); 7417502Sroot /* check for cooked mode input buffer overflow */ 7427502Sroot } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 7437502Sroot ; 7447502Sroot /* put data char in q for user and wakeup if a break char */ 7457502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7467502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG 7477502Sroot && tp->t_line == NTTYDISC) 7487502Sroot (void) ttyoutput(CTRL(g), tp); 7497502Sroot if (!ttbreakc(c, tp)) { 7507502Sroot if (tp->t_rocount++ == 0) 7517502Sroot tp->t_rocol = tp->t_col; 7527502Sroot } else { 7537502Sroot tp->t_rocount = 0; 7547502Sroot catq(&tp->t_rawq, &tp->t_canq); 7557502Sroot /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */ 7567502Sroot ttwakeup(tp); 7577502Sroot } 7587502Sroot tp->t_lstate &= ~LSQUOT; 7597502Sroot if (c == '\\') 7607502Sroot tp->t_lstate |= LSQUOT; 7617502Sroot if (tp->t_lstate&LSERASE) { 7627502Sroot tp->t_lstate &= ~LSERASE; 7637502Sroot (void) ttyoutput('/', tp); 7647502Sroot } 7657502Sroot i = tp->t_col; 7667502Sroot ttyecho(c, tp); 7677502Sroot if (c==tun.t_eofc && tp->t_flags&ECHO) { 7687502Sroot i = MIN(2, tp->t_col - i); 7697502Sroot while (i > 0) { 7707502Sroot (void) ttyoutput('\b', tp); 7717502Sroot i--; 7727502Sroot } 7737502Sroot } 7747502Sroot } 7757502Sroot /* CBREAK mode */ 7767502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) { 7777502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7787502Sroot tp->t_line == NTTYDISC) 7797502Sroot (void) ttyoutput(CTRL(g), tp); 7807502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7817502Sroot ttwakeup(tp); 7827502Sroot ttyecho(c, tp); 7837502Sroot } 7847502Sroot /* RAW mode */ 7857502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) 7867502Sroot flushtty(tp, FREAD|FWRITE); 7877502Sroot else { 7887502Sroot if (putc(c, &tp->t_rawq) >= 0) 7897502Sroot ttwakeup(tp); 7907502Sroot ttyecho(c, tp); 7917502Sroot } 7927502Sroot out: 7937502Sroot if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP && 7947502Sroot tun.t_startc != tun.t_stopc) 7957502Sroot return; 7967502Sroot tp->t_state &= ~TS_TTSTOP; 7977502Sroot tp->t_local &= ~LFLUSHO; 7987502Sroot ttstart(tp); 7997502Sroot } 8007502Sroot 8017502Sroot /* 8027502Sroot * put character on TTY output queue, adding delays, 8037502Sroot * expanding tabs, and handling the CR/NL bit. 8047502Sroot * It is called both from the top half for output, and from 8057502Sroot * interrupt level for echoing. 8067502Sroot * The arguments are the character and the tty structure. 8077502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8087502Sroot * Must be recursive. 8097502Sroot */ 8107502Sroot ttyoutput(c, tp) 8117502Sroot register c; 8127502Sroot register struct tty *tp; 8137502Sroot { 8147502Sroot register char *colp; 8157502Sroot register ctype; 8167502Sroot 8177502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) { 8187502Sroot if (tp->t_local&LFLUSHO) 8197502Sroot return (-1); 8207502Sroot if (putc(c, &tp->t_outq)) 8217625Ssam return (c); 8227502Sroot tk_nout++; 8237502Sroot return (-1); 8247502Sroot } 8257502Sroot /* 8267502Sroot * Ignore EOT in normal mode to avoid hanging up 8277502Sroot * certain terminals. 8287502Sroot */ 8297502Sroot c &= 0177; 8307502Sroot if (c==CEOT && (tp->t_flags&CBREAK)==0) 8317502Sroot return (-1); 8327502Sroot /* 8337502Sroot * Turn tabs to spaces as required 8347502Sroot */ 8357502Sroot if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 8367502Sroot register int s; 8377502Sroot 8387502Sroot c = 8 - (tp->t_col&7); 8397502Sroot if ((tp->t_local&LFLUSHO) == 0) { 8407502Sroot s = spl5(); /* don't interrupt tabs */ 8417502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8427502Sroot tk_nout += c; 8437502Sroot splx(s); 8447502Sroot } 8457502Sroot tp->t_col += c; 8467502Sroot return (c ? -1 : '\t'); 8477502Sroot } 8487502Sroot tk_nout++; 8497502Sroot /* 8507502Sroot * for upper-case-only terminals, 8517502Sroot * generate escapes. 8527502Sroot */ 8537502Sroot if (tp->t_flags&LCASE) { 8547502Sroot colp = "({)}!|^~'`"; 8557625Ssam while (*colp++) 8567625Ssam if (c == *colp++) { 8577502Sroot if (ttyoutput('\\', tp) >= 0) 8587502Sroot return (c); 8597502Sroot c = colp[-2]; 8607502Sroot break; 8617502Sroot } 8627502Sroot if ('A'<=c && c<='Z') { 8637502Sroot if (ttyoutput('\\', tp) >= 0) 8647502Sroot return (c); 8657502Sroot } else if ('a'<=c && c<='z') 8667502Sroot c += 'A' - 'a'; 8677502Sroot } 8687502Sroot /* 8697502Sroot * turn <nl> to <cr><lf> if desired. 8707502Sroot */ 8717502Sroot if (c=='\n' && tp->t_flags&CRMOD) 8727502Sroot if (ttyoutput('\r', tp) >= 0) 8737502Sroot return (c); 8747502Sroot if (c=='~' && tp->t_local<ILDE) 8757502Sroot c = '`'; 8767502Sroot if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq)) 8777502Sroot return (c); 8787502Sroot /* 8797502Sroot * Calculate delays. 8807502Sroot * The numbers here represent clock ticks 8817502Sroot * and are not necessarily optimal for all terminals. 8827502Sroot * The delays are indicated by characters above 0200. 8837502Sroot * In raw mode there are no delays and the 8847502Sroot * transmission path is 8 bits wide. 8857502Sroot */ 8867502Sroot colp = &tp->t_col; 8877502Sroot ctype = partab[c]; 8887502Sroot c = 0; 8897502Sroot switch (ctype&077) { 8907502Sroot 8917502Sroot case ORDINARY: 8927502Sroot (*colp)++; 8937502Sroot 8947502Sroot case CONTROL: 8957502Sroot break; 8967502Sroot 8977502Sroot case BACKSPACE: 8987502Sroot if (*colp) 8997502Sroot (*colp)--; 9007502Sroot break; 9017502Sroot 9027502Sroot case NEWLINE: 9037502Sroot ctype = (tp->t_flags >> 8) & 03; 9047625Ssam if (ctype == 1) { /* tty 37 */ 9057502Sroot if (*colp) 9067502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9077502Sroot } else 9087625Ssam if (ctype == 2) { /* vt05 */ 9097502Sroot c = 6; 9107502Sroot } 9117502Sroot *colp = 0; 9127502Sroot break; 9137502Sroot 9147502Sroot case TAB: 9157502Sroot ctype = (tp->t_flags >> 10) & 03; 9167625Ssam if (ctype == 1) { /* tty 37 */ 9177502Sroot c = 1 - (*colp | ~07); 9187625Ssam if (c < 5) 9197502Sroot c = 0; 9207502Sroot } 9217502Sroot *colp |= 07; 9227502Sroot (*colp)++; 9237502Sroot break; 9247502Sroot 9257502Sroot case VTAB: 9267625Ssam if (tp->t_flags & VTDELAY) /* tty 37 */ 9277502Sroot c = 0177; 9287502Sroot break; 9297502Sroot 9307502Sroot case RETURN: 9317502Sroot ctype = (tp->t_flags >> 12) & 03; 9327625Ssam if (ctype == 1) { /* tn 300 */ 9337502Sroot c = 5; 9347625Ssam } else if (ctype == 2) { /* ti 700 */ 9357502Sroot c = 10; 9367625Ssam } else if (ctype == 3) { /* concept 100 */ 9377502Sroot int i; 9387502Sroot if ((i = *colp) >= 0) 9397502Sroot for (; i<9; i++) 9407502Sroot (void) putc(0177, &tp->t_outq); 9417502Sroot } 9427502Sroot *colp = 0; 9437502Sroot } 9447625Ssam if (c && (tp->t_local&LFLUSHO) == 0) 9457502Sroot (void) putc(c|0200, &tp->t_outq); 9467502Sroot return (-1); 9477502Sroot } 9487502Sroot 9497502Sroot /* 9507502Sroot * Called from device's read routine after it has 9517502Sroot * calculated the tty-structure given as argument. 9527502Sroot */ 9537722Swnj ttread(tp, uio) 9547625Ssam register struct tty *tp; 9557722Swnj struct uio *uio; 9567502Sroot { 9577502Sroot register struct clist *qp; 9587502Sroot register c, first; 9597502Sroot 9607502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9617625Ssam return (0); 9627502Sroot loop: 9637502Sroot (void) spl5(); 9647502Sroot if (tp->t_local&LPENDIN) 9657502Sroot ttypend(tp); 9667502Sroot (void) spl0(); 9677502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9687502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9697502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9707502Sroot /* 9717502Sroot (u.u_procp->p_flag&SDETACH) || 9727502Sroot */ 9737502Sroot u.u_procp->p_flag&SVFORK) 9747502Sroot return (0); 9757502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9767502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9777502Sroot } 9787502Sroot if (tp->t_flags&RAW) { 9797502Sroot (void) spl5(); 9807502Sroot if (tp->t_rawq.c_cc <= 0) { 9817502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9827502Sroot (tp->t_state&TS_NBIO)) { 9837502Sroot (void) spl0(); 9847502Sroot return (0); 9857502Sroot } 9867502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9877502Sroot (void) spl0(); 9887502Sroot goto loop; 9897502Sroot } 9907502Sroot (void) spl0(); 9917722Swnj while (tp->t_rawq.c_cc && uio->uio_iovcnt) { 9927722Swnj u.u_error = passuc(getc(&tp->t_rawq), uio); 9937722Swnj if (u.u_error) 9947722Swnj break; 9957722Swnj } 9967502Sroot return (0); 9977502Sroot } else { 9987502Sroot qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq; 9997502Sroot (void) spl5(); 10007502Sroot if (qp->c_cc <= 0) { 10017502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 10027502Sroot (tp->t_state&TS_NBIO)) { 10037502Sroot (void) spl0(); 10047502Sroot return (0); 10057502Sroot } 10067502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10077502Sroot (void) spl0(); 10087502Sroot goto loop; 10097502Sroot } 10107502Sroot (void) spl0(); 10117502Sroot first = 1; 10127502Sroot while ((c = getc(qp)) >= 0) { 10137502Sroot if (tp->t_flags&CRMOD && c == '\r') 10147502Sroot c = '\n'; 10157502Sroot if (tp->t_flags&LCASE && c <= 0177) 10167502Sroot if (tp->t_lstate&LSBKSL) { 10177502Sroot if (maptab[c]) 10187502Sroot c = maptab[c]; 10197502Sroot tp->t_lstate &= ~LSBKSL; 10207502Sroot } else if (c >= 'A' && c <= 'Z') 10217502Sroot c += 'a' - 'A'; 10227502Sroot else if (c == '\\') { 10237502Sroot tp->t_lstate |= LSBKSL; 10247502Sroot continue; 10257502Sroot } 10267658Ssam if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) { 10277502Sroot ttsignal(tp, SIGTSTP); 10287502Sroot if (first) { 10297502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10307502Sroot goto loop; 10317502Sroot } 10327502Sroot break; 10337502Sroot } 10347502Sroot if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0) 10357502Sroot break; 10367722Swnj u.u_error = passuc(c & 0177, uio); 10377722Swnj if (u.u_error) 10387502Sroot break; 10397722Swnj if (uio->uio_iovcnt == 0) 10407722Swnj break; 10417502Sroot if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp)) 10427502Sroot break; 10437502Sroot first = 0; 10447502Sroot } 10457502Sroot tp->t_lstate &= ~LSBKSL; 10467502Sroot } 10477502Sroot 10487502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 10497502Sroot if (putc(tun.t_startc, &tp->t_outq)==0) { 10507502Sroot tp->t_state &= ~TS_TBLOCK; 10517502Sroot ttstart(tp); 10527502Sroot } 10537502Sroot tp->t_char = 0; 10547502Sroot } 10557502Sroot 10567502Sroot return (tp->t_rawq.c_cc + tp->t_canq.c_cc); 10577502Sroot } 10587502Sroot 10597502Sroot /* 10607502Sroot * Called from the device's write routine after it has 10617502Sroot * calculated the tty-structure given as argument. 10627502Sroot */ 10637502Sroot caddr_t 10647822Sroot ttwrite(tp, uio) 10657625Ssam register struct tty *tp; 10667822Sroot struct uio *uio; 10677502Sroot { 10687502Sroot #ifdef vax 10697502Sroot /* 10707502Sroot * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 10717502Sroot * AND MUST NOT BE CHANGED WITHOUT PATCHING 10727502Sroot * THE 'ASM' INLINES BELOW. WATCH OUT. 10737502Sroot */ 10747502Sroot #endif 10757502Sroot register char *cp; 10767502Sroot register int cc, ce; 10777502Sroot register i; 10787502Sroot char obuf[OBUFSIZ]; 10797502Sroot register c; 10807502Sroot int hiwat = TTHIWAT(tp); 10817822Sroot int cnt = uio->uio_resid; 10827502Sroot 10837502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10847502Sroot return (NULL); 10857502Sroot loop: 10867502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 10877502Sroot (tp->t_local<OSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 10887502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 10897502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 10907502Sroot /* 10917502Sroot && 10927502Sroot (u.u_procp->p_flag&SDETACH)==0) { 10937502Sroot */ 10947502Sroot ) { 10957502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 10967502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10977502Sroot } 10987822Sroot while (uio->uio_resid > 0) { 10997822Sroot cc = uio->uio_iov->iov_len; 11007822Sroot if (cc == 0) { 11017822Sroot uio->uio_iovcnt--; 11027822Sroot uio->uio_iov++; 11037822Sroot if (uio->uio_iovcnt < 0) 11047822Sroot panic("ttwrite"); 11057822Sroot continue; 11067822Sroot } 11077822Sroot if (cc > OBUFSIZ) 11087822Sroot cc = OBUFSIZ; 11097502Sroot cp = obuf; 11107822Sroot u.u_error = uiomove(cp, cc, UIO_WRITE, uio); 11117502Sroot if (u.u_error) 11127502Sroot break; 11137502Sroot if (tp->t_outq.c_cc > hiwat) 11147502Sroot goto ovhiwat; 11157502Sroot if (tp->t_local&LFLUSHO) 11167502Sroot continue; 11177502Sroot if (tp->t_flags&LCASE || tp->t_local<ILDE) { 11187502Sroot while (cc) { 11197502Sroot c = *cp++; 11207502Sroot tp->t_rocount = 0; 11217625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 11227502Sroot /* out of clists, wait a bit */ 11237502Sroot ttstart(tp); 11247502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11257502Sroot tp->t_rocount = 0; 11267502Sroot } 11277502Sroot --cc; 11287502Sroot if (tp->t_outq.c_cc > hiwat) 11297502Sroot goto ovhiwat; 11307502Sroot } 11317502Sroot continue; 11327502Sroot } 11337502Sroot while (cc) { 11347502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 11357502Sroot ce = cc; 11367502Sroot else { 11377502Sroot #ifdef vax 11387502Sroot asm(" scanc r9,(r10),_partab,$077"); 11397502Sroot asm(" subl3 r0,r9,r8"); 11407502Sroot #else 11417502Sroot ce=0; 11427625Ssam while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc)) 11437502Sroot ce++; 11447502Sroot #endif 11457502Sroot if (ce==0) { 11467502Sroot tp->t_rocount = 0; 11477502Sroot if (ttyoutput(*cp, tp) >= 0) { 11487502Sroot ttstart(tp); 11497502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11507502Sroot continue; 11517502Sroot } 11527502Sroot cp++; 11537502Sroot cc--; 11547502Sroot if (tp->t_outq.c_cc > hiwat) 11557502Sroot goto ovhiwat; 11567502Sroot } 11577502Sroot } 11587502Sroot tp->t_rocount = 0; 11597502Sroot i=b_to_q(cp,ce,&tp->t_outq); 11607502Sroot ce-=i; 11617502Sroot tk_nout+=ce; 11627502Sroot tp->t_col+=ce; 11637502Sroot cp+=ce; 11647502Sroot cc-=ce; 11657502Sroot if (i) { 11667502Sroot ttstart(tp); 11677502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11687502Sroot } 11697502Sroot if (ce || tp->t_outq.c_cc > hiwat) 11707502Sroot goto ovhiwat; 11717502Sroot } 11727502Sroot } 11737502Sroot ttstart(tp); 11747625Ssam return (NULL); 11757502Sroot 11767502Sroot ovhiwat: 11777502Sroot (void) spl5(); 11787822Sroot uio->uio_iov->iov_base -= cc; 11797822Sroot uio->uio_iov->iov_len += cc; 11807822Sroot uio->uio_resid += cc; 11817822Sroot uio->uio_offset -= cc; 11827502Sroot if (tp->t_outq.c_cc <= hiwat) { 11837502Sroot (void) spl0(); 11847502Sroot goto loop; 11857502Sroot } 11867502Sroot ttstart(tp); 11877502Sroot if (tp->t_state & TS_NBIO) { 11887822Sroot if (uio->uio_resid == cnt) 11897502Sroot u.u_error = EWOULDBLOCK; 11907502Sroot return (NULL); 11917502Sroot } 11927502Sroot tp->t_state |= TS_ASLEEP; 11937502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 11947502Sroot (void) spl0(); 11957502Sroot goto loop; 11967502Sroot } 11977502Sroot 11987502Sroot /* 11997502Sroot * Rubout one character from the rawq of tp 12007502Sroot * as cleanly as possible. 12017502Sroot */ 12027502Sroot ttyrub(c, tp) 12037625Ssam register c; 12047625Ssam register struct tty *tp; 12057502Sroot { 12067502Sroot register char *cp; 12077502Sroot register int savecol; 12087502Sroot int s; 12097502Sroot char *nextc(); 12107502Sroot 12117502Sroot if ((tp->t_flags&ECHO)==0) 12127502Sroot return; 12137502Sroot tp->t_local &= ~LFLUSHO; 12147502Sroot c &= 0377; 12157502Sroot if (tp->t_local&LCRTBS) { 12167502Sroot if (tp->t_rocount == 0) { 12177502Sroot /* 12187502Sroot * Screwed by ttwrite; retype 12197502Sroot */ 12207502Sroot ttyretype(tp); 12217502Sroot return; 12227502Sroot } 12237502Sroot if (c==('\t'|0200) || c==('\n'|0200)) 12247502Sroot ttyrubo(tp, 2); 12257625Ssam else switch (partab[c&=0177] & 0177) { 12267502Sroot 12277502Sroot case ORDINARY: 12287502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 12297502Sroot ttyrubo(tp, 2); 12307502Sroot else 12317502Sroot ttyrubo(tp, 1); 12327502Sroot break; 12337502Sroot 12347502Sroot case VTAB: 12357502Sroot case BACKSPACE: 12367502Sroot case CONTROL: 12377502Sroot case RETURN: 12387502Sroot if (tp->t_local & LCTLECH) 12397502Sroot ttyrubo(tp, 2); 12407502Sroot break; 12417502Sroot 12427502Sroot case TAB: 12437502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 12447502Sroot ttyretype(tp); 12457502Sroot return; 12467502Sroot } 12477502Sroot s = spl5(); 12487502Sroot savecol = tp->t_col; 12497502Sroot tp->t_lstate |= LSCNTTB; 12507502Sroot tp->t_local |= LFLUSHO; 12517502Sroot tp->t_col = tp->t_rocol; 12527502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12537502Sroot ttyecho(*cp, tp); 12547502Sroot tp->t_local &= ~LFLUSHO; 12557502Sroot tp->t_lstate &= ~LSCNTTB; 12567502Sroot splx(s); 12577502Sroot /* 12587502Sroot * savecol will now be length of the tab 12597502Sroot */ 12607502Sroot savecol -= tp->t_col; 12617502Sroot tp->t_col += savecol; 12627502Sroot if (savecol > 8) 12637502Sroot savecol = 8; /* overflow screw */ 12647502Sroot while (--savecol >= 0) 12657502Sroot (void) ttyoutput('\b', tp); 12667502Sroot break; 12677502Sroot 12687502Sroot default: 12697502Sroot panic("ttyrub"); 12707502Sroot } 12717502Sroot } else if (tp->t_local&LPRTERA) { 12727502Sroot if ((tp->t_lstate&LSERASE) == 0) { 12737502Sroot (void) ttyoutput('\\', tp); 12747502Sroot tp->t_lstate |= LSERASE; 12757502Sroot } 12767502Sroot ttyecho(c, tp); 12777502Sroot } else 12787502Sroot ttyecho(tp->t_erase, tp); 12797502Sroot tp->t_rocount--; 12807502Sroot } 12817502Sroot 12827502Sroot /* 12837502Sroot * Crt back over cnt chars perhaps 12847502Sroot * erasing them. 12857502Sroot */ 12867502Sroot ttyrubo(tp, cnt) 12877625Ssam register struct tty *tp; 12887625Ssam int cnt; 12897502Sroot { 12907502Sroot 12917502Sroot while (--cnt >= 0) 12927502Sroot ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp); 12937502Sroot } 12947502Sroot 12957502Sroot /* 12967502Sroot * Reprint the rawq line. 12977502Sroot * We assume c_cc has already been checked. 12987502Sroot */ 12997502Sroot ttyretype(tp) 13007625Ssam register struct tty *tp; 13017502Sroot { 13027502Sroot register char *cp; 13037502Sroot char *nextc(); 13047502Sroot int s; 13057502Sroot 13067502Sroot if (tlun.t_rprntc != 0377) 13077502Sroot ttyecho(tlun.t_rprntc, tp); 13087502Sroot (void) ttyoutput('\n', tp); 13097502Sroot s = spl5(); 13107502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 13117502Sroot ttyecho(*cp, tp); 13127502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 13137502Sroot ttyecho(*cp, tp); 13147502Sroot tp->t_lstate &= ~LSERASE; 13157502Sroot splx(s); 13167502Sroot tp->t_rocount = tp->t_rawq.c_cc; 13177502Sroot tp->t_rocol = 0; 13187502Sroot } 13197502Sroot 13207502Sroot /* 13217502Sroot * Echo a typed character to the terminal 13227502Sroot */ 13237502Sroot ttyecho(c, tp) 13247625Ssam register c; 13257625Ssam register struct tty *tp; 13267502Sroot { 13277502Sroot 13287502Sroot if ((tp->t_lstate & LSCNTTB) == 0) 13297502Sroot tp->t_local &= ~LFLUSHO; 13307502Sroot if ((tp->t_flags&ECHO) == 0) 13317502Sroot return; 13327502Sroot c &= 0377; 13337502Sroot if (tp->t_flags&RAW) { 13347502Sroot (void) ttyoutput(c, tp); 13357502Sroot return; 13367502Sroot } 13377502Sroot if (c == '\r' && tp->t_flags&CRMOD) 13387502Sroot c = '\n'; 13397502Sroot if (tp->t_local&LCTLECH) { 13407502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 13417502Sroot (void) ttyoutput('^', tp); 13427502Sroot c &= 0177; 13437502Sroot if (c == 0177) 13447502Sroot c = '?'; 13457502Sroot else if (tp->t_flags&LCASE) 13467502Sroot c += 'a' - 1; 13477502Sroot else 13487502Sroot c += 'A' - 1; 13497502Sroot } 13507502Sroot } 13517502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 13527502Sroot c += 'a' - 'A'; 13537502Sroot (void) ttyoutput(c & 0177, tp); 13547502Sroot } 13557502Sroot 13567502Sroot /* 13577502Sroot * Is c a break char for tp? 13587502Sroot */ 13597502Sroot ttbreakc(c, tp) 13607625Ssam register c; 13617625Ssam register struct tty *tp; 13627502Sroot { 13637502Sroot return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc || 13647502Sroot c == '\r' && (tp->t_flags&CRMOD)); 13657502Sroot } 13667502Sroot 13677502Sroot /* 13687502Sroot * send string cp to tp 13697502Sroot */ 13707502Sroot ttyout(cp, tp) 13717625Ssam register char *cp; 13727625Ssam register struct tty *tp; 13737502Sroot { 13747502Sroot register char c; 13757502Sroot 13767502Sroot while (c = *cp++) 13777502Sroot (void) ttyoutput(c, tp); 13787502Sroot } 13797502Sroot 13807502Sroot ttwakeup(tp) 13817502Sroot struct tty *tp; 13827502Sroot { 13837502Sroot 13847502Sroot if (tp->t_rsel) { 13857502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 13867502Sroot tp->t_state &= ~TS_RCOLL; 13877502Sroot tp->t_rsel = 0; 13887502Sroot } 13897502Sroot wakeup((caddr_t)&tp->t_rawq); 13907502Sroot } 13917502Sroot 13927502Sroot ttsignal(tp, signo) 13937502Sroot struct tty *tp; 13947502Sroot int signo; 13957502Sroot { 13967502Sroot 13977502Sroot gsignal(tp->t_pgrp, signo); 13987502Sroot } 1399