1*7722Swnj /* tty.c 4.27 82/08/13 */ 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" 18*7722Swnj #include "../h/uio.h" 1939Sbill 207436Skre /* 217436Skre * Table giving parity for characters and indicating 227436Skre * character classes to tty driver. In particular, 237436Skre * if the low 6 bits are 0, then the character needs 247436Skre * no special processing on output. 257436Skre */ 2639Sbill 277436Skre char partab[] = { 287436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 297436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 307436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 317436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 327436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 337436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 347436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 357436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 367436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 377436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 387436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 397436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 407436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 417436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 427436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 437436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 447436Skre 457436Skre /* 467436Skre * 7 bit ascii ends with the last character above, 477436Skre * but we contine through all 256 codes for the sake 487436Skre * of the tty output routines which use special vax 497436Skre * instructions which need a 256 character trt table. 507436Skre */ 517436Skre 527436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 537436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 547436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 557436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 567436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 577436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 587436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 597436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 607436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 617436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 627436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 637436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 647436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 657436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 667436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 677436Skre 0007,0007,0007,0007,0007,0007,0007,0007 687436Skre }; 697436Skre 70146Sbill /* 7139Sbill * Input mapping table-- if an entry is non-zero, when the 7239Sbill * corresponding character is typed preceded by "\" the escape 7339Sbill * sequence is replaced by the table value. Mostly used for 7439Sbill * upper-case only terminals. 7539Sbill */ 7639Sbill 7739Sbill char maptab[] ={ 7839Sbill 000,000,000,000,000,000,000,000, 7939Sbill 000,000,000,000,000,000,000,000, 8039Sbill 000,000,000,000,000,000,000,000, 8139Sbill 000,000,000,000,000,000,000,000, 8239Sbill 000,'|',000,000,000,000,000,'`', 8339Sbill '{','}',000,000,000,000,000,000, 8439Sbill 000,000,000,000,000,000,000,000, 8539Sbill 000,000,000,000,000,000,000,000, 8639Sbill 000,000,000,000,000,000,000,000, 8739Sbill 000,000,000,000,000,000,000,000, 8839Sbill 000,000,000,000,000,000,000,000, 8939Sbill 000,000,000,000,000,000,'~',000, 9039Sbill 000,'A','B','C','D','E','F','G', 9139Sbill 'H','I','J','K','L','M','N','O', 9239Sbill 'P','Q','R','S','T','U','V','W', 9339Sbill 'X','Y','Z',000,000,000,000,000, 9439Sbill }; 9539Sbill 96925Sbill short tthiwat[16] = 97925Sbill { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 98925Sbill short ttlowat[16] = 99925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 100925Sbill 10139Sbill #define OBUFSIZ 100 10239Sbill 10339Sbill /* 10439Sbill * set default control characters. 10539Sbill */ 10639Sbill ttychars(tp) 1077625Ssam register struct tty *tp; 10839Sbill { 109174Sbill 11039Sbill tun.t_intrc = CINTR; 11139Sbill tun.t_quitc = CQUIT; 11239Sbill tun.t_startc = CSTART; 11339Sbill tun.t_stopc = CSTOP; 11439Sbill tun.t_eofc = CEOT; 11539Sbill tun.t_brkc = CBRK; 11639Sbill tp->t_erase = CERASE; 11739Sbill tp->t_kill = CKILL; 118174Sbill /* begin local */ 119208Sbill tlun.t_suspc = CTRL(z); 120208Sbill tlun.t_dsuspc = CTRL(y); 121174Sbill tlun.t_rprntc = CTRL(r); 122174Sbill tlun.t_flushc = CTRL(o); 123174Sbill tlun.t_werasc = CTRL(w); 124174Sbill tlun.t_lnextc = CTRL(v); 125174Sbill tp->t_local = 0; 126174Sbill tp->t_lstate = 0; 127174Sbill /* end local */ 12839Sbill } 12939Sbill 13039Sbill /* 131903Sbill * Wait for output to drain, then flush input waiting. 13239Sbill */ 133903Sbill wflushtty(tp) 1345408Swnj register struct tty *tp; 13539Sbill { 13639Sbill 137903Sbill (void) spl5(); 1385622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1395622Swnj && tp->t_oproc) { /* kludge for pty */ 140903Sbill (*tp->t_oproc)(tp); 1415408Swnj tp->t_state |= TS_ASLEEP; 142903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 143903Sbill } 1445426Swnj flushtty(tp, FREAD); 145903Sbill (void) spl0(); 14639Sbill } 14739Sbill 14839Sbill /* 149903Sbill * flush all TTY queues 15039Sbill */ 151903Sbill flushtty(tp, rw) 1527625Ssam register struct tty *tp; 15339Sbill { 154903Sbill register s; 155903Sbill 156903Sbill s = spl6(); 157903Sbill if (rw & FREAD) { 158903Sbill while (getc(&tp->t_canq) >= 0) 159903Sbill ; 160903Sbill wakeup((caddr_t)&tp->t_rawq); 161903Sbill } 162903Sbill if (rw & FWRITE) { 163903Sbill wakeup((caddr_t)&tp->t_outq); 1645408Swnj tp->t_state &= ~TS_TTSTOP; 1655426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 166903Sbill while (getc(&tp->t_outq) >= 0) 167903Sbill ; 168903Sbill } 169903Sbill if (rw & FREAD) { 170903Sbill while (getc(&tp->t_rawq) >= 0) 171903Sbill ; 172903Sbill tp->t_delct = 0; 173903Sbill tp->t_rocount = 0; /* local */ 174903Sbill tp->t_rocol = 0; 175903Sbill tp->t_lstate = 0; 176903Sbill } 177903Sbill splx(s); 17839Sbill } 17939Sbill 180903Sbill /* 181903Sbill * Send stop character on input overflow. 182903Sbill */ 183903Sbill ttyblock(tp) 1847625Ssam register struct tty *tp; 18539Sbill { 186903Sbill register x; 187903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 188903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 189903Sbill flushtty(tp, FREAD|FWRITE); 1905408Swnj tp->t_state &= ~TS_TBLOCK; 191903Sbill } 192903Sbill if (x >= TTYHOG/2) { 193903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 1945408Swnj tp->t_state |= TS_TBLOCK; 195903Sbill tp->t_char++; 196903Sbill ttstart(tp); 197903Sbill } 198903Sbill } 19939Sbill } 20039Sbill 20139Sbill /* 202903Sbill * Restart typewriter output following a delay 203903Sbill * timeout. 204903Sbill * The name of the routine is passed to the timeout 205903Sbill * subroutine and it is called during a clock interrupt. 206121Sbill */ 207903Sbill ttrstrt(tp) 2087625Ssam register struct tty *tp; 209121Sbill { 210121Sbill 2113351Swnj if (tp == 0) { 2123351Swnj printf("ttrstrt: arg was 0!\n"); 2133351Swnj return; 2143351Swnj } 2155408Swnj tp->t_state &= ~TS_TIMEOUT; 216903Sbill ttstart(tp); 217121Sbill } 218121Sbill 219121Sbill /* 220903Sbill * Start output on the typewriter. It is used from the top half 221903Sbill * after some characters have been put on the output queue, 222903Sbill * from the interrupt routine to transmit the next 223903Sbill * character, and after a timeout has finished. 22439Sbill */ 225903Sbill ttstart(tp) 2267625Ssam register struct tty *tp; 22739Sbill { 228903Sbill register s; 22939Sbill 230903Sbill s = spl5(); 2317625Ssam if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2325622Swnj tp->t_oproc) /* kludge for pty */ 233903Sbill (*tp->t_oproc)(tp); 234903Sbill splx(s); 23539Sbill } 23639Sbill 23739Sbill /* 238903Sbill * Common code for tty ioctls. 23939Sbill */ 2401780Sbill /*ARGSUSED*/ 2417625Ssam ttioctl(tp, com, data, flag) 2427625Ssam register struct tty *tp; 2437625Ssam caddr_t data; 24439Sbill { 2451904Swnj int dev; 24639Sbill extern int nldisp; 24739Sbill 248903Sbill /* 249915Sbill * This is especially so that isatty() will 250915Sbill * fail when carrier is gone. 251915Sbill */ 2525408Swnj if ((tp->t_state&TS_CARR_ON) == 0) { 253915Sbill u.u_error = EBADF; 254915Sbill return (1); 255915Sbill } 256915Sbill 2571904Swnj dev = tp->t_dev; 258915Sbill /* 259903Sbill * If the ioctl involves modification, 260903Sbill * insist on being able to write the device, 261903Sbill * and hang if in the background. 262903Sbill */ 2637625Ssam switch (com) { 26439Sbill 265915Sbill case TIOCSETD: 266915Sbill case TIOCSETP: 267915Sbill case TIOCSETN: 268903Sbill case TIOCFLUSH: 269903Sbill case TIOCSETC: 270903Sbill case TIOCSLTC: 271903Sbill case TIOCSPGRP: 272903Sbill case TIOCLBIS: 273903Sbill case TIOCLBIC: 274903Sbill case TIOCLSET: 275915Sbill /* this is reasonable, but impractical... 276903Sbill if ((flag & FWRITE) == 0) { 277903Sbill u.u_error = EBADF; 278903Sbill return (1); 279903Sbill } 280915Sbill */ 281903Sbill while (tp->t_line == NTTYDISC && 282903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 283903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 284903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2855626Swnj u.u_signal[SIGTTOU] != SIG_HOLD 2865626Swnj /* 2875626Swnj && 288903Sbill (u.u_procp->p_flag&SDETACH)==0) { 2895626Swnj */ 2905626Swnj ) { 291903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 292903Sbill sleep((caddr_t)&lbolt, TTOPRI); 293903Sbill } 294903Sbill break; 295903Sbill } 296903Sbill 29739Sbill /* 298903Sbill * Process the ioctl. 29939Sbill */ 3007625Ssam switch (com) { 301903Sbill 302903Sbill /* 303903Sbill * Get discipline number 304903Sbill */ 30539Sbill case TIOCGETD: 3067625Ssam *(int *)data = tp->t_line; 30739Sbill break; 30839Sbill 30939Sbill /* 310903Sbill * Set line discipline 31139Sbill */ 3127625Ssam case TIOCSETD: { 3137625Ssam register int t = *(int *)data; 3147625Ssam 31539Sbill if (t >= nldisp) { 31639Sbill u.u_error = ENXIO; 31739Sbill break; 31839Sbill } 319174Sbill (void) spl5(); 32039Sbill if (tp->t_line) 32139Sbill (*linesw[tp->t_line].l_close)(tp); 32239Sbill if (t) 3237625Ssam (*linesw[t].l_open)(dev, tp); 32439Sbill if (u.u_error==0) 32539Sbill tp->t_line = t; 326174Sbill (void) spl0(); 32739Sbill break; 3287625Ssam } 32939Sbill 33039Sbill /* 3315614Swnj * Prevent more opens on channel 3325614Swnj */ 3335614Swnj case TIOCEXCL: 3345614Swnj tp->t_state |= TS_XCLUDE; 3355614Swnj break; 3365614Swnj 3375614Swnj case TIOCNXCL: 3385614Swnj tp->t_state &= ~TS_XCLUDE; 3395614Swnj break; 3405614Swnj 3415614Swnj /* 34239Sbill * Set new parameters 34339Sbill */ 34439Sbill case TIOCSETP: 3457625Ssam case TIOCSETN: { 3467625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3477625Ssam struct clist tq; 3487625Ssam 349121Sbill (void) spl5(); 3507625Ssam if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP) 3514484Swnj wflushtty(tp); 3527625Ssam else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) { 3537625Ssam if (sg->sg_flags & CBREAK) { 3544484Swnj catq(&tp->t_rawq, &tp->t_canq); 3554484Swnj tq = tp->t_rawq; 3564484Swnj tp->t_rawq = tp->t_canq; 3574484Swnj tp->t_canq = tq; 3584484Swnj } else { 3594484Swnj tp->t_local |= LPENDIN; 3604484Swnj ttwakeup(tp); 361174Sbill } 362174Sbill } 3637625Ssam tp->t_ispeed = sg->sg_ispeed; 3647625Ssam tp->t_ospeed = sg->sg_ospeed; 3657625Ssam tp->t_erase = sg->sg_erase; 3667625Ssam tp->t_kill = sg->sg_kill; 3677625Ssam tp->t_flags = sg->sg_flags; 3683941Sbugs if (tp->t_flags & RAW) { 3695408Swnj tp->t_state &= ~TS_TTSTOP; 3703941Sbugs ttstart(tp); 3713941Sbugs } 372121Sbill (void) spl0(); 37339Sbill break; 3747625Ssam } 37539Sbill 37639Sbill /* 377903Sbill * Send current parameters to user 37839Sbill */ 3797625Ssam case TIOCGETP: { 3807625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3817625Ssam 3827625Ssam sg->sg_ispeed = tp->t_ispeed; 3837625Ssam sg->sg_ospeed = tp->t_ospeed; 3847625Ssam sg->sg_erase = tp->t_erase; 3857625Ssam sg->sg_kill = tp->t_kill; 3867625Ssam sg->sg_flags = tp->t_flags; 38739Sbill break; 3887625Ssam } 38939Sbill 39039Sbill /* 39139Sbill * Hang up line on last close 39239Sbill */ 39339Sbill case TIOCHPCL: 3945408Swnj tp->t_state |= TS_HUPCLS; 39539Sbill break; 39639Sbill 3973942Sbugs case TIOCFLUSH: { 3987625Ssam register int flags = *(int *)data; 3997625Ssam 4007625Ssam if (flags == 0) 4013942Sbugs flags = FREAD|FWRITE; 4027625Ssam else 4037625Ssam flags &= FREAD|FWRITE; 4043942Sbugs flushtty(tp, flags); 40539Sbill break; 4063944Sbugs } 40739Sbill 4087625Ssam case FIONBIO: 4097625Ssam if (*(int *)data) 4105408Swnj tp->t_state |= TS_NBIO; 4115408Swnj else 4125408Swnj tp->t_state &= ~TS_NBIO; 4135408Swnj break; 4145408Swnj 4157625Ssam case FIOASYNC: 4167625Ssam if (*(int *)data) 4176216Swnj tp->t_state |= TS_ASYNC; 4186216Swnj else 4196216Swnj tp->t_state &= ~TS_ASYNC; 4206216Swnj break; 4216216Swnj 42239Sbill /* 423903Sbill * Set and fetch special characters 42439Sbill */ 42539Sbill case TIOCSETC: 4267625Ssam bcopy(data, (caddr_t)&tun, sizeof (struct tchars)); 42739Sbill break; 42839Sbill 42939Sbill case TIOCGETC: 4307625Ssam bcopy((caddr_t)&tun, data, sizeof (struct tchars)); 43139Sbill break; 43239Sbill 433174Sbill /* local ioctls */ 434903Sbill /* 435903Sbill * Set/get local special characters. 436903Sbill */ 437174Sbill case TIOCSLTC: 4387625Ssam bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars)); 439174Sbill break; 440174Sbill 441174Sbill case TIOCGLTC: 4427625Ssam bcopy((caddr_t)&tlun, data, sizeof (struct ltchars)); 443174Sbill break; 444174Sbill 445903Sbill /* 446903Sbill * Return number of characters immediately available. 447903Sbill */ 4487625Ssam case FIONREAD: 4497625Ssam *(off_t *)data = ttnread(tp); 450174Sbill break; 451174Sbill 452174Sbill /* 453174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 454174Sbill */ 455174Sbill case TIOCSPGRP: 4567625Ssam tp->t_pgrp = *(int *)data; 457174Sbill break; 458174Sbill 459174Sbill case TIOCGPGRP: 4607625Ssam *(int *)data = tp->t_pgrp; 461174Sbill break; 462174Sbill 463174Sbill /* 464174Sbill * Modify local mode word. 465174Sbill */ 466174Sbill case TIOCLBIS: 4677625Ssam tp->t_local |= *(int *)data; 468174Sbill break; 469174Sbill 470174Sbill case TIOCLBIC: 4717625Ssam tp->t_local &= ~(*(int *)data); 472174Sbill break; 473174Sbill 474174Sbill case TIOCLSET: 4757625Ssam tp->t_local = *(int *)data; 476174Sbill break; 477174Sbill 478174Sbill case TIOCLGET: 4797625Ssam *(int *)data = tp->t_local; 480174Sbill break; 481174Sbill 4827625Ssam case TIOCSTOP: { 4837625Ssam int s = spl5(); 484213Sbill 4855573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4865573Swnj tp->t_state |= TS_TTSTOP; 4875573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4885573Swnj } 4897625Ssam splx(s); 4905573Swnj break; 4917625Ssam } 4925573Swnj 4937625Ssam case TIOCSTART: { 4947625Ssam int s = spl5(); 4957625Ssam 4965573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4975573Swnj tp->t_state &= ~TS_TTSTOP; 4985573Swnj tp->t_local &= ~LFLUSHO; 4995573Swnj ttstart(tp); 5005573Swnj } 5017625Ssam splx(s); 5025573Swnj break; 5037625Ssam } 5045573Swnj 505174Sbill /* end of locals */ 506887Sbill 50739Sbill default: 5087625Ssam return (0); 50939Sbill } 5107625Ssam return (1); 51139Sbill } 5124484Swnj 5134484Swnj ttnread(tp) 5144484Swnj struct tty *tp; 5154484Swnj { 5164484Swnj int nread = 0; 5174484Swnj 5184484Swnj if (tp->t_local & LPENDIN) 5194484Swnj ttypend(tp); 5204484Swnj nread = tp->t_canq.c_cc; 5214484Swnj if (tp->t_flags & (RAW|CBREAK)) 5224484Swnj nread += tp->t_rawq.c_cc; 5234484Swnj return (nread); 5244484Swnj } 5254484Swnj 5265408Swnj ttselect(dev, rw) 5274484Swnj dev_t dev; 5285408Swnj int rw; 5294484Swnj { 5304484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5314484Swnj int nread; 5325408Swnj int s = spl5(); 5334484Swnj 5345408Swnj switch (rw) { 5354484Swnj 5364484Swnj case FREAD: 5374484Swnj nread = ttnread(tp); 5384484Swnj if (nread > 0) 5395408Swnj goto win; 5404938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5415408Swnj tp->t_state |= TS_RCOLL; 5424484Swnj else 5434484Swnj tp->t_rsel = u.u_procp; 5445408Swnj break; 5454484Swnj 5465408Swnj case FWRITE: 5475408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5485408Swnj goto win; 5495408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5505408Swnj tp->t_state |= TS_WCOLL; 5515408Swnj else 5525408Swnj tp->t_wsel = u.u_procp; 5535408Swnj break; 5544484Swnj } 5555408Swnj splx(s); 5565408Swnj return (0); 5575408Swnj win: 5585408Swnj splx(s); 5595408Swnj return (1); 5604484Swnj } 5617436Skre 5627502Sroot #define OBUFSIZ 100 5637502Sroot 5647502Sroot /* 5657502Sroot * routine called on opens while tp->t_line == NTTYDISC 5667502Sroot * establishes a process group for distribution of 5677502Sroot * quits and interrupts from the tty. 5687502Sroot * (actually, pp->p_pgrp can't be 0 when this routine 5697502Sroot * is called since NTTYDISC is not the default discipline) 5707502Sroot */ 5717502Sroot ttyopen(dev, tp) 5727625Ssam dev_t dev; 5737625Ssam register struct tty *tp; 5747502Sroot { 5757502Sroot register struct proc *pp; 5767502Sroot 5777502Sroot pp = u.u_procp; 5787502Sroot tp->t_dev = dev; 5797625Ssam if (pp->p_pgrp == 0) { 5807502Sroot u.u_ttyp = tp; 5817502Sroot u.u_ttyd = dev; 5827502Sroot if (tp->t_pgrp == 0) 5837502Sroot tp->t_pgrp = pp->p_pid; 5847502Sroot pp->p_pgrp = tp->t_pgrp; 5857502Sroot } 5867502Sroot tp->t_state &= ~TS_WOPEN; 5877502Sroot tp->t_state |= TS_ISOPEN; 5887502Sroot if (tp->t_line != NTTYDISC) 5897502Sroot wflushtty(tp); 5907502Sroot } 5917502Sroot 5927502Sroot /* 5937502Sroot * clean tp on last close 5947502Sroot */ 5957502Sroot ttyclose(tp) 5967625Ssam register struct tty *tp; 5977502Sroot { 5987502Sroot 5997502Sroot if (tp->t_line) { 6007502Sroot wflushtty(tp); 6017502Sroot tp->t_line = 0; 6027502Sroot return; 6037502Sroot } 6047502Sroot tp->t_pgrp = 0; 6057502Sroot wflushtty(tp); 6067502Sroot tp->t_state = 0; 6077502Sroot } 6087502Sroot 6097502Sroot /* 6107502Sroot * reinput pending characters after state switch 6117502Sroot * call at spl5(). 6127502Sroot */ 6137502Sroot ttypend(tp) 6147625Ssam register struct tty *tp; 6157502Sroot { 6167502Sroot struct clist tq; 6177502Sroot register c; 6187502Sroot 6197502Sroot tp->t_local &= ~LPENDIN; 6207502Sroot tp->t_lstate |= LSTYPEN; 6217502Sroot tq = tp->t_rawq; 6227502Sroot tp->t_rawq.c_cc = 0; 6237502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6247502Sroot while ((c = getc(&tq)) >= 0) 6257502Sroot ttyinput(c, tp); 6267502Sroot tp->t_lstate &= ~LSTYPEN; 6277502Sroot } 6287502Sroot 6297502Sroot /* 6307502Sroot * Place a character on raw TTY input queue, putting in delimiters 6317502Sroot * and waking up top half as needed. 6327502Sroot * Also echo if required. 6337502Sroot * The arguments are the character and the appropriate 6347502Sroot * tty structure. 6357502Sroot */ 6367502Sroot ttyinput(c, tp) 6377625Ssam register c; 6387625Ssam register struct tty *tp; 6397502Sroot { 6407502Sroot register int t_flags; 6417502Sroot int i; 6427502Sroot 6437502Sroot if (tp->t_local&LPENDIN) 6447502Sroot ttypend(tp); 6457502Sroot tk_nin++; 6467502Sroot c &= 0377; 6477502Sroot t_flags = tp->t_flags; 6487502Sroot if (t_flags&TANDEM) 6497502Sroot ttyblock(tp); 6507502Sroot if ((t_flags&RAW)==0) { 6517502Sroot if ((tp->t_lstate&LSTYPEN) == 0) 6527502Sroot c &= 0177; 6537502Sroot /* check for literal nexting very first */ 6547502Sroot if (tp->t_lstate&LSLNCH) { 6557502Sroot c |= 0200; 6567502Sroot tp->t_lstate &= ~LSLNCH; 6577502Sroot } 6587502Sroot if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) { 6597502Sroot if (tp->t_flags&ECHO) 6607502Sroot ttyout("^\b", tp); 6617502Sroot tp->t_lstate |= LSLNCH; 6627502Sroot /* check for output control functions */ 6637502Sroot } else if (c==tun.t_stopc) { 6647502Sroot if ((tp->t_state&TS_TTSTOP)==0) { 6657502Sroot tp->t_state |= TS_TTSTOP; 6667502Sroot (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6677502Sroot return; 6687502Sroot } 6697502Sroot if (c!=tun.t_startc) 6707502Sroot return; 6717502Sroot } else if (c==tun.t_startc) { 6727502Sroot tp->t_state &= ~TS_TTSTOP; 6737502Sroot tp->t_local &= ~LFLUSHO; 6747502Sroot ttstart(tp); 6757502Sroot return; 6767502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) { 6777502Sroot if (tp->t_local & LFLUSHO) 6787502Sroot tp->t_local &= ~LFLUSHO; 6797502Sroot else { 6807502Sroot flushtty(tp, FWRITE); 6817502Sroot ttyecho(c, tp); 6827502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc) 6837502Sroot ttyretype(tp); 6847502Sroot tp->t_local |= LFLUSHO; 6857502Sroot } 6867502Sroot ttstart(tp); 6877502Sroot return; 6887502Sroot } else if (c==tun.t_intrc || c==tun.t_quitc || 6897502Sroot (tp->t_line == NTTYDISC && c==tlun.t_suspc)) { 6907502Sroot if ((tp->t_local & LNOFLSH) == 0) 6917502Sroot flushtty(tp, 6927502Sroot c==tlun.t_suspc ? FREAD : FREAD|FWRITE); 6937502Sroot ttyecho(c, tp); 6947502Sroot c = c==tun.t_intrc ? SIGINT : 6957502Sroot ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP); 6967502Sroot ttsignal(tp, c); 6977502Sroot /* check for buffer editing functions - cooked mode */ 6987502Sroot } else if ((t_flags&CBREAK) == 0) { 6997502Sroot if ((tp->t_lstate&LSQUOT) && 7007502Sroot (c==tp->t_erase||c==tp->t_kill)) { 7017502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7027502Sroot c |= 0200; 7037502Sroot } 7047502Sroot if (c==tp->t_erase) { 7057502Sroot if (tp->t_rawq.c_cc) 7067502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7077502Sroot } else if (c==tp->t_kill) { 7087502Sroot if (tp->t_local&LCRTKIL && 7097502Sroot tp->t_rawq.c_cc == tp->t_rocount) { 7107502Sroot while (tp->t_rawq.c_cc) 7117502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7127502Sroot } else { 7137502Sroot ttyecho(c, tp); 7147502Sroot ttyecho('\n', tp); 7157502Sroot while (getc(&tp->t_rawq) > 0) 7167502Sroot ; 7177502Sroot tp->t_rocount = 0; 7187502Sroot } 7197502Sroot tp->t_lstate = 0; 7207502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) { 7217502Sroot if (tp->t_rawq.c_cc == 0) 7227502Sroot goto out; 7237502Sroot do { 7247502Sroot c = unputc(&tp->t_rawq); 7257502Sroot if (c != ' ' && c != '\t') 7267502Sroot goto erasenb; 7277502Sroot ttyrub(c, tp); 7287502Sroot } while (tp->t_rawq.c_cc); 7297502Sroot goto out; 7307502Sroot erasenb: 7317502Sroot do { 7327502Sroot ttyrub(c, tp); 7337502Sroot if (tp->t_rawq.c_cc == 0) 7347502Sroot goto out; 7357502Sroot c = unputc(&tp->t_rawq); 7367502Sroot } while (c != ' ' && c != '\t'); 7377502Sroot (void) putc(c, &tp->t_rawq); 7387502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) { 7397502Sroot ttyretype(tp); 7407502Sroot /* check for cooked mode input buffer overflow */ 7417502Sroot } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 7427502Sroot ; 7437502Sroot /* put data char in q for user and wakeup if a break char */ 7447502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7457502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG 7467502Sroot && tp->t_line == NTTYDISC) 7477502Sroot (void) ttyoutput(CTRL(g), tp); 7487502Sroot if (!ttbreakc(c, tp)) { 7497502Sroot if (tp->t_rocount++ == 0) 7507502Sroot tp->t_rocol = tp->t_col; 7517502Sroot } else { 7527502Sroot tp->t_rocount = 0; 7537502Sroot catq(&tp->t_rawq, &tp->t_canq); 7547502Sroot /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */ 7557502Sroot ttwakeup(tp); 7567502Sroot } 7577502Sroot tp->t_lstate &= ~LSQUOT; 7587502Sroot if (c == '\\') 7597502Sroot tp->t_lstate |= LSQUOT; 7607502Sroot if (tp->t_lstate&LSERASE) { 7617502Sroot tp->t_lstate &= ~LSERASE; 7627502Sroot (void) ttyoutput('/', tp); 7637502Sroot } 7647502Sroot i = tp->t_col; 7657502Sroot ttyecho(c, tp); 7667502Sroot if (c==tun.t_eofc && tp->t_flags&ECHO) { 7677502Sroot i = MIN(2, tp->t_col - i); 7687502Sroot while (i > 0) { 7697502Sroot (void) ttyoutput('\b', tp); 7707502Sroot i--; 7717502Sroot } 7727502Sroot } 7737502Sroot } 7747502Sroot /* CBREAK mode */ 7757502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) { 7767502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7777502Sroot tp->t_line == NTTYDISC) 7787502Sroot (void) ttyoutput(CTRL(g), tp); 7797502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7807502Sroot ttwakeup(tp); 7817502Sroot ttyecho(c, tp); 7827502Sroot } 7837502Sroot /* RAW mode */ 7847502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) 7857502Sroot flushtty(tp, FREAD|FWRITE); 7867502Sroot else { 7877502Sroot if (putc(c, &tp->t_rawq) >= 0) 7887502Sroot ttwakeup(tp); 7897502Sroot ttyecho(c, tp); 7907502Sroot } 7917502Sroot out: 7927502Sroot if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP && 7937502Sroot tun.t_startc != tun.t_stopc) 7947502Sroot return; 7957502Sroot tp->t_state &= ~TS_TTSTOP; 7967502Sroot tp->t_local &= ~LFLUSHO; 7977502Sroot ttstart(tp); 7987502Sroot } 7997502Sroot 8007502Sroot /* 8017502Sroot * put character on TTY output queue, adding delays, 8027502Sroot * expanding tabs, and handling the CR/NL bit. 8037502Sroot * It is called both from the top half for output, and from 8047502Sroot * interrupt level for echoing. 8057502Sroot * The arguments are the character and the tty structure. 8067502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8077502Sroot * Must be recursive. 8087502Sroot */ 8097502Sroot ttyoutput(c, tp) 8107502Sroot register c; 8117502Sroot register struct tty *tp; 8127502Sroot { 8137502Sroot register char *colp; 8147502Sroot register ctype; 8157502Sroot 8167502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) { 8177502Sroot if (tp->t_local&LFLUSHO) 8187502Sroot return (-1); 8197502Sroot if (putc(c, &tp->t_outq)) 8207625Ssam return (c); 8217502Sroot tk_nout++; 8227502Sroot return (-1); 8237502Sroot } 8247502Sroot /* 8257502Sroot * Ignore EOT in normal mode to avoid hanging up 8267502Sroot * certain terminals. 8277502Sroot */ 8287502Sroot c &= 0177; 8297502Sroot if (c==CEOT && (tp->t_flags&CBREAK)==0) 8307502Sroot return (-1); 8317502Sroot /* 8327502Sroot * Turn tabs to spaces as required 8337502Sroot */ 8347502Sroot if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 8357502Sroot register int s; 8367502Sroot 8377502Sroot c = 8 - (tp->t_col&7); 8387502Sroot if ((tp->t_local&LFLUSHO) == 0) { 8397502Sroot s = spl5(); /* don't interrupt tabs */ 8407502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8417502Sroot tk_nout += c; 8427502Sroot splx(s); 8437502Sroot } 8447502Sroot tp->t_col += c; 8457502Sroot return (c ? -1 : '\t'); 8467502Sroot } 8477502Sroot tk_nout++; 8487502Sroot /* 8497502Sroot * for upper-case-only terminals, 8507502Sroot * generate escapes. 8517502Sroot */ 8527502Sroot if (tp->t_flags&LCASE) { 8537502Sroot colp = "({)}!|^~'`"; 8547625Ssam while (*colp++) 8557625Ssam if (c == *colp++) { 8567502Sroot if (ttyoutput('\\', tp) >= 0) 8577502Sroot return (c); 8587502Sroot c = colp[-2]; 8597502Sroot break; 8607502Sroot } 8617502Sroot if ('A'<=c && c<='Z') { 8627502Sroot if (ttyoutput('\\', tp) >= 0) 8637502Sroot return (c); 8647502Sroot } else if ('a'<=c && c<='z') 8657502Sroot c += 'A' - 'a'; 8667502Sroot } 8677502Sroot /* 8687502Sroot * turn <nl> to <cr><lf> if desired. 8697502Sroot */ 8707502Sroot if (c=='\n' && tp->t_flags&CRMOD) 8717502Sroot if (ttyoutput('\r', tp) >= 0) 8727502Sroot return (c); 8737502Sroot if (c=='~' && tp->t_local<ILDE) 8747502Sroot c = '`'; 8757502Sroot if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq)) 8767502Sroot return (c); 8777502Sroot /* 8787502Sroot * Calculate delays. 8797502Sroot * The numbers here represent clock ticks 8807502Sroot * and are not necessarily optimal for all terminals. 8817502Sroot * The delays are indicated by characters above 0200. 8827502Sroot * In raw mode there are no delays and the 8837502Sroot * transmission path is 8 bits wide. 8847502Sroot */ 8857502Sroot colp = &tp->t_col; 8867502Sroot ctype = partab[c]; 8877502Sroot c = 0; 8887502Sroot switch (ctype&077) { 8897502Sroot 8907502Sroot case ORDINARY: 8917502Sroot (*colp)++; 8927502Sroot 8937502Sroot case CONTROL: 8947502Sroot break; 8957502Sroot 8967502Sroot case BACKSPACE: 8977502Sroot if (*colp) 8987502Sroot (*colp)--; 8997502Sroot break; 9007502Sroot 9017502Sroot case NEWLINE: 9027502Sroot ctype = (tp->t_flags >> 8) & 03; 9037625Ssam if (ctype == 1) { /* tty 37 */ 9047502Sroot if (*colp) 9057502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9067502Sroot } else 9077625Ssam if (ctype == 2) { /* vt05 */ 9087502Sroot c = 6; 9097502Sroot } 9107502Sroot *colp = 0; 9117502Sroot break; 9127502Sroot 9137502Sroot case TAB: 9147502Sroot ctype = (tp->t_flags >> 10) & 03; 9157625Ssam if (ctype == 1) { /* tty 37 */ 9167502Sroot c = 1 - (*colp | ~07); 9177625Ssam if (c < 5) 9187502Sroot c = 0; 9197502Sroot } 9207502Sroot *colp |= 07; 9217502Sroot (*colp)++; 9227502Sroot break; 9237502Sroot 9247502Sroot case VTAB: 9257625Ssam if (tp->t_flags & VTDELAY) /* tty 37 */ 9267502Sroot c = 0177; 9277502Sroot break; 9287502Sroot 9297502Sroot case RETURN: 9307502Sroot ctype = (tp->t_flags >> 12) & 03; 9317625Ssam if (ctype == 1) { /* tn 300 */ 9327502Sroot c = 5; 9337625Ssam } else if (ctype == 2) { /* ti 700 */ 9347502Sroot c = 10; 9357625Ssam } else if (ctype == 3) { /* concept 100 */ 9367502Sroot int i; 9377502Sroot if ((i = *colp) >= 0) 9387502Sroot for (; i<9; i++) 9397502Sroot (void) putc(0177, &tp->t_outq); 9407502Sroot } 9417502Sroot *colp = 0; 9427502Sroot } 9437625Ssam if (c && (tp->t_local&LFLUSHO) == 0) 9447502Sroot (void) putc(c|0200, &tp->t_outq); 9457502Sroot return (-1); 9467502Sroot } 9477502Sroot 9487502Sroot /* 9497502Sroot * Called from device's read routine after it has 9507502Sroot * calculated the tty-structure given as argument. 9517502Sroot */ 952*7722Swnj ttread(tp, uio) 9537625Ssam register struct tty *tp; 954*7722Swnj struct uio *uio; 9557502Sroot { 9567502Sroot register struct clist *qp; 9577502Sroot register c, first; 9587502Sroot 9597502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9607625Ssam return (0); 9617502Sroot loop: 9627502Sroot (void) spl5(); 9637502Sroot if (tp->t_local&LPENDIN) 9647502Sroot ttypend(tp); 9657502Sroot (void) spl0(); 9667502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9677502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9687502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9697502Sroot /* 9707502Sroot (u.u_procp->p_flag&SDETACH) || 9717502Sroot */ 9727502Sroot u.u_procp->p_flag&SVFORK) 9737502Sroot return (0); 9747502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9757502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9767502Sroot } 9777502Sroot if (tp->t_flags&RAW) { 9787502Sroot (void) spl5(); 9797502Sroot if (tp->t_rawq.c_cc <= 0) { 9807502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9817502Sroot (tp->t_state&TS_NBIO)) { 9827502Sroot (void) spl0(); 9837502Sroot return (0); 9847502Sroot } 9857502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9867502Sroot (void) spl0(); 9877502Sroot goto loop; 9887502Sroot } 9897502Sroot (void) spl0(); 990*7722Swnj while (tp->t_rawq.c_cc && uio->uio_iovcnt) { 991*7722Swnj u.u_error = passuc(getc(&tp->t_rawq), uio); 992*7722Swnj if (u.u_error) 993*7722Swnj break; 994*7722Swnj } 9957502Sroot return (0); 9967502Sroot } else { 9977502Sroot qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq; 9987502Sroot (void) spl5(); 9997502Sroot if (qp->c_cc <= 0) { 10007502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 10017502Sroot (tp->t_state&TS_NBIO)) { 10027502Sroot (void) spl0(); 10037502Sroot return (0); 10047502Sroot } 10057502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10067502Sroot (void) spl0(); 10077502Sroot goto loop; 10087502Sroot } 10097502Sroot (void) spl0(); 10107502Sroot first = 1; 10117502Sroot while ((c = getc(qp)) >= 0) { 10127502Sroot if (tp->t_flags&CRMOD && c == '\r') 10137502Sroot c = '\n'; 10147502Sroot if (tp->t_flags&LCASE && c <= 0177) 10157502Sroot if (tp->t_lstate&LSBKSL) { 10167502Sroot if (maptab[c]) 10177502Sroot c = maptab[c]; 10187502Sroot tp->t_lstate &= ~LSBKSL; 10197502Sroot } else if (c >= 'A' && c <= 'Z') 10207502Sroot c += 'a' - 'A'; 10217502Sroot else if (c == '\\') { 10227502Sroot tp->t_lstate |= LSBKSL; 10237502Sroot continue; 10247502Sroot } 10257658Ssam if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) { 10267502Sroot ttsignal(tp, SIGTSTP); 10277502Sroot if (first) { 10287502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10297502Sroot goto loop; 10307502Sroot } 10317502Sroot break; 10327502Sroot } 10337502Sroot if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0) 10347502Sroot break; 1035*7722Swnj u.u_error = passuc(c & 0177, uio); 1036*7722Swnj if (u.u_error) 10377502Sroot break; 1038*7722Swnj if (uio->uio_iovcnt == 0) 1039*7722Swnj break; 10407502Sroot if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp)) 10417502Sroot break; 10427502Sroot first = 0; 10437502Sroot } 10447502Sroot tp->t_lstate &= ~LSBKSL; 10457502Sroot } 10467502Sroot 10477502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 10487502Sroot if (putc(tun.t_startc, &tp->t_outq)==0) { 10497502Sroot tp->t_state &= ~TS_TBLOCK; 10507502Sroot ttstart(tp); 10517502Sroot } 10527502Sroot tp->t_char = 0; 10537502Sroot } 10547502Sroot 10557502Sroot return (tp->t_rawq.c_cc + tp->t_canq.c_cc); 10567502Sroot } 10577502Sroot 10587502Sroot /* 10597502Sroot * Called from the device's write routine after it has 10607502Sroot * calculated the tty-structure given as argument. 10617502Sroot */ 10627502Sroot caddr_t 10637502Sroot ttwrite(tp) 10647625Ssam register struct tty *tp; 10657502Sroot { 10667502Sroot #ifdef vax 10677502Sroot /* 10687502Sroot * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 10697502Sroot * AND MUST NOT BE CHANGED WITHOUT PATCHING 10707502Sroot * THE 'ASM' INLINES BELOW. WATCH OUT. 10717502Sroot */ 10727502Sroot #endif 10737502Sroot register char *cp; 10747502Sroot register int cc, ce; 10757502Sroot register i; 10767502Sroot char obuf[OBUFSIZ]; 10777502Sroot register c; 10787502Sroot int hiwat = TTHIWAT(tp); 10797502Sroot int cnt = u.u_count; 10807502Sroot 10817502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10827502Sroot return (NULL); 10837502Sroot loop: 10847502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 10857502Sroot (tp->t_local<OSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 10867502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 10877502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 10887502Sroot /* 10897502Sroot && 10907502Sroot (u.u_procp->p_flag&SDETACH)==0) { 10917502Sroot */ 10927502Sroot ) { 10937502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 10947502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10957502Sroot } 10967502Sroot while (u.u_count) { 10977502Sroot cc = MIN(u.u_count, OBUFSIZ); 10987502Sroot cp = obuf; 10997502Sroot iomove(cp, (unsigned)cc, B_WRITE); 11007502Sroot if (u.u_error) 11017502Sroot break; 11027502Sroot if (tp->t_outq.c_cc > hiwat) 11037502Sroot goto ovhiwat; 11047502Sroot if (tp->t_local&LFLUSHO) 11057502Sroot continue; 11067502Sroot if (tp->t_flags&LCASE || tp->t_local<ILDE) { 11077502Sroot while (cc) { 11087502Sroot c = *cp++; 11097502Sroot tp->t_rocount = 0; 11107625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 11117502Sroot /* out of clists, wait a bit */ 11127502Sroot ttstart(tp); 11137502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11147502Sroot tp->t_rocount = 0; 11157502Sroot } 11167502Sroot --cc; 11177502Sroot if (tp->t_outq.c_cc > hiwat) 11187502Sroot goto ovhiwat; 11197502Sroot } 11207502Sroot continue; 11217502Sroot } 11227502Sroot while (cc) { 11237502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 11247502Sroot ce = cc; 11257502Sroot else { 11267502Sroot #ifdef vax 11277502Sroot asm(" scanc r9,(r10),_partab,$077"); 11287502Sroot asm(" subl3 r0,r9,r8"); 11297502Sroot #else 11307502Sroot ce=0; 11317625Ssam while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc)) 11327502Sroot ce++; 11337502Sroot #endif 11347502Sroot if (ce==0) { 11357502Sroot tp->t_rocount = 0; 11367502Sroot if (ttyoutput(*cp, tp) >= 0) { 11377502Sroot ttstart(tp); 11387502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11397502Sroot continue; 11407502Sroot } 11417502Sroot cp++; 11427502Sroot cc--; 11437502Sroot if (tp->t_outq.c_cc > hiwat) 11447502Sroot goto ovhiwat; 11457502Sroot } 11467502Sroot } 11477502Sroot tp->t_rocount = 0; 11487502Sroot i=b_to_q(cp,ce,&tp->t_outq); 11497502Sroot ce-=i; 11507502Sroot tk_nout+=ce; 11517502Sroot tp->t_col+=ce; 11527502Sroot cp+=ce; 11537502Sroot cc-=ce; 11547502Sroot if (i) { 11557502Sroot ttstart(tp); 11567502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11577502Sroot } 11587502Sroot if (ce || tp->t_outq.c_cc > hiwat) 11597502Sroot goto ovhiwat; 11607502Sroot } 11617502Sroot } 11627502Sroot ttstart(tp); 11637625Ssam return (NULL); 11647502Sroot 11657502Sroot ovhiwat: 11667502Sroot (void) spl5(); 11677502Sroot u.u_base -= cc; 11687502Sroot u.u_offset -= cc; 11697502Sroot u.u_count += cc; 11707502Sroot if (tp->t_outq.c_cc <= hiwat) { 11717502Sroot (void) spl0(); 11727502Sroot goto loop; 11737502Sroot } 11747502Sroot ttstart(tp); 11757502Sroot if (tp->t_state & TS_NBIO) { 11767502Sroot if (u.u_count == cnt) 11777502Sroot u.u_error = EWOULDBLOCK; 11787502Sroot return (NULL); 11797502Sroot } 11807502Sroot tp->t_state |= TS_ASLEEP; 11817502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 11827502Sroot (void) spl0(); 11837502Sroot goto loop; 11847502Sroot } 11857502Sroot 11867502Sroot /* 11877502Sroot * Rubout one character from the rawq of tp 11887502Sroot * as cleanly as possible. 11897502Sroot */ 11907502Sroot ttyrub(c, tp) 11917625Ssam register c; 11927625Ssam register struct tty *tp; 11937502Sroot { 11947502Sroot register char *cp; 11957502Sroot register int savecol; 11967502Sroot int s; 11977502Sroot char *nextc(); 11987502Sroot 11997502Sroot if ((tp->t_flags&ECHO)==0) 12007502Sroot return; 12017502Sroot tp->t_local &= ~LFLUSHO; 12027502Sroot c &= 0377; 12037502Sroot if (tp->t_local&LCRTBS) { 12047502Sroot if (tp->t_rocount == 0) { 12057502Sroot /* 12067502Sroot * Screwed by ttwrite; retype 12077502Sroot */ 12087502Sroot ttyretype(tp); 12097502Sroot return; 12107502Sroot } 12117502Sroot if (c==('\t'|0200) || c==('\n'|0200)) 12127502Sroot ttyrubo(tp, 2); 12137625Ssam else switch (partab[c&=0177] & 0177) { 12147502Sroot 12157502Sroot case ORDINARY: 12167502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 12177502Sroot ttyrubo(tp, 2); 12187502Sroot else 12197502Sroot ttyrubo(tp, 1); 12207502Sroot break; 12217502Sroot 12227502Sroot case VTAB: 12237502Sroot case BACKSPACE: 12247502Sroot case CONTROL: 12257502Sroot case RETURN: 12267502Sroot if (tp->t_local & LCTLECH) 12277502Sroot ttyrubo(tp, 2); 12287502Sroot break; 12297502Sroot 12307502Sroot case TAB: 12317502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 12327502Sroot ttyretype(tp); 12337502Sroot return; 12347502Sroot } 12357502Sroot s = spl5(); 12367502Sroot savecol = tp->t_col; 12377502Sroot tp->t_lstate |= LSCNTTB; 12387502Sroot tp->t_local |= LFLUSHO; 12397502Sroot tp->t_col = tp->t_rocol; 12407502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12417502Sroot ttyecho(*cp, tp); 12427502Sroot tp->t_local &= ~LFLUSHO; 12437502Sroot tp->t_lstate &= ~LSCNTTB; 12447502Sroot splx(s); 12457502Sroot /* 12467502Sroot * savecol will now be length of the tab 12477502Sroot */ 12487502Sroot savecol -= tp->t_col; 12497502Sroot tp->t_col += savecol; 12507502Sroot if (savecol > 8) 12517502Sroot savecol = 8; /* overflow screw */ 12527502Sroot while (--savecol >= 0) 12537502Sroot (void) ttyoutput('\b', tp); 12547502Sroot break; 12557502Sroot 12567502Sroot default: 12577502Sroot panic("ttyrub"); 12587502Sroot } 12597502Sroot } else if (tp->t_local&LPRTERA) { 12607502Sroot if ((tp->t_lstate&LSERASE) == 0) { 12617502Sroot (void) ttyoutput('\\', tp); 12627502Sroot tp->t_lstate |= LSERASE; 12637502Sroot } 12647502Sroot ttyecho(c, tp); 12657502Sroot } else 12667502Sroot ttyecho(tp->t_erase, tp); 12677502Sroot tp->t_rocount--; 12687502Sroot } 12697502Sroot 12707502Sroot /* 12717502Sroot * Crt back over cnt chars perhaps 12727502Sroot * erasing them. 12737502Sroot */ 12747502Sroot ttyrubo(tp, cnt) 12757625Ssam register struct tty *tp; 12767625Ssam int cnt; 12777502Sroot { 12787502Sroot 12797502Sroot while (--cnt >= 0) 12807502Sroot ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp); 12817502Sroot } 12827502Sroot 12837502Sroot /* 12847502Sroot * Reprint the rawq line. 12857502Sroot * We assume c_cc has already been checked. 12867502Sroot */ 12877502Sroot ttyretype(tp) 12887625Ssam register struct tty *tp; 12897502Sroot { 12907502Sroot register char *cp; 12917502Sroot char *nextc(); 12927502Sroot int s; 12937502Sroot 12947502Sroot if (tlun.t_rprntc != 0377) 12957502Sroot ttyecho(tlun.t_rprntc, tp); 12967502Sroot (void) ttyoutput('\n', tp); 12977502Sroot s = spl5(); 12987502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 12997502Sroot ttyecho(*cp, tp); 13007502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 13017502Sroot ttyecho(*cp, tp); 13027502Sroot tp->t_lstate &= ~LSERASE; 13037502Sroot splx(s); 13047502Sroot tp->t_rocount = tp->t_rawq.c_cc; 13057502Sroot tp->t_rocol = 0; 13067502Sroot } 13077502Sroot 13087502Sroot /* 13097502Sroot * Echo a typed character to the terminal 13107502Sroot */ 13117502Sroot ttyecho(c, tp) 13127625Ssam register c; 13137625Ssam register struct tty *tp; 13147502Sroot { 13157502Sroot 13167502Sroot if ((tp->t_lstate & LSCNTTB) == 0) 13177502Sroot tp->t_local &= ~LFLUSHO; 13187502Sroot if ((tp->t_flags&ECHO) == 0) 13197502Sroot return; 13207502Sroot c &= 0377; 13217502Sroot if (tp->t_flags&RAW) { 13227502Sroot (void) ttyoutput(c, tp); 13237502Sroot return; 13247502Sroot } 13257502Sroot if (c == '\r' && tp->t_flags&CRMOD) 13267502Sroot c = '\n'; 13277502Sroot if (tp->t_local&LCTLECH) { 13287502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 13297502Sroot (void) ttyoutput('^', tp); 13307502Sroot c &= 0177; 13317502Sroot if (c == 0177) 13327502Sroot c = '?'; 13337502Sroot else if (tp->t_flags&LCASE) 13347502Sroot c += 'a' - 1; 13357502Sroot else 13367502Sroot c += 'A' - 1; 13377502Sroot } 13387502Sroot } 13397502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 13407502Sroot c += 'a' - 'A'; 13417502Sroot (void) ttyoutput(c & 0177, tp); 13427502Sroot } 13437502Sroot 13447502Sroot /* 13457502Sroot * Is c a break char for tp? 13467502Sroot */ 13477502Sroot ttbreakc(c, tp) 13487625Ssam register c; 13497625Ssam register struct tty *tp; 13507502Sroot { 13517502Sroot return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc || 13527502Sroot c == '\r' && (tp->t_flags&CRMOD)); 13537502Sroot } 13547502Sroot 13557502Sroot /* 13567502Sroot * send string cp to tp 13577502Sroot */ 13587502Sroot ttyout(cp, tp) 13597625Ssam register char *cp; 13607625Ssam register struct tty *tp; 13617502Sroot { 13627502Sroot register char c; 13637502Sroot 13647502Sroot while (c = *cp++) 13657502Sroot (void) ttyoutput(c, tp); 13667502Sroot } 13677502Sroot 13687502Sroot ttwakeup(tp) 13697502Sroot struct tty *tp; 13707502Sroot { 13717502Sroot 13727502Sroot if (tp->t_rsel) { 13737502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 13747502Sroot tp->t_state &= ~TS_RCOLL; 13757502Sroot tp->t_rsel = 0; 13767502Sroot } 13777502Sroot wakeup((caddr_t)&tp->t_rawq); 13787502Sroot } 13797502Sroot 13807502Sroot ttsignal(tp, signo) 13817502Sroot struct tty *tp; 13827502Sroot int signo; 13837502Sroot { 13847502Sroot 13857502Sroot gsignal(tp->t_pgrp, signo); 13867502Sroot } 1387