1*7625Ssam /* tty.c 4.25 82/08/01 */ 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" 1839Sbill 197436Skre /* 207436Skre * Table giving parity for characters and indicating 217436Skre * character classes to tty driver. In particular, 227436Skre * if the low 6 bits are 0, then the character needs 237436Skre * no special processing on output. 247436Skre */ 2539Sbill 267436Skre char partab[] = { 277436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 287436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 297436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 307436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 317436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 327436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 337436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 347436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 357436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 367436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 377436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 387436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 397436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 407436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 417436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 427436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 437436Skre 447436Skre /* 457436Skre * 7 bit ascii ends with the last character above, 467436Skre * but we contine through all 256 codes for the sake 477436Skre * of the tty output routines which use special vax 487436Skre * instructions which need a 256 character trt table. 497436Skre */ 507436Skre 517436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 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 }; 687436Skre 69146Sbill /* 7039Sbill * Input mapping table-- if an entry is non-zero, when the 7139Sbill * corresponding character is typed preceded by "\" the escape 7239Sbill * sequence is replaced by the table value. Mostly used for 7339Sbill * upper-case only terminals. 7439Sbill */ 7539Sbill 7639Sbill char maptab[] ={ 7739Sbill 000,000,000,000,000,000,000,000, 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,'`', 8239Sbill '{','}',000,000,000,000,000,000, 8339Sbill 000,000,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, 8939Sbill 000,'A','B','C','D','E','F','G', 9039Sbill 'H','I','J','K','L','M','N','O', 9139Sbill 'P','Q','R','S','T','U','V','W', 9239Sbill 'X','Y','Z',000,000,000,000,000, 9339Sbill }; 9439Sbill 95925Sbill short tthiwat[16] = 96925Sbill { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 97925Sbill short ttlowat[16] = 98925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 99925Sbill 10039Sbill #define OBUFSIZ 100 10139Sbill 10239Sbill /* 10339Sbill * set default control characters. 10439Sbill */ 10539Sbill ttychars(tp) 106*7625Ssam register struct tty *tp; 10739Sbill { 108174Sbill 10939Sbill tun.t_intrc = CINTR; 11039Sbill tun.t_quitc = CQUIT; 11139Sbill tun.t_startc = CSTART; 11239Sbill tun.t_stopc = CSTOP; 11339Sbill tun.t_eofc = CEOT; 11439Sbill tun.t_brkc = CBRK; 11539Sbill tp->t_erase = CERASE; 11639Sbill tp->t_kill = CKILL; 117174Sbill /* begin local */ 118208Sbill tlun.t_suspc = CTRL(z); 119208Sbill tlun.t_dsuspc = CTRL(y); 120174Sbill tlun.t_rprntc = CTRL(r); 121174Sbill tlun.t_flushc = CTRL(o); 122174Sbill tlun.t_werasc = CTRL(w); 123174Sbill tlun.t_lnextc = CTRL(v); 124174Sbill tp->t_local = 0; 125174Sbill tp->t_lstate = 0; 126174Sbill /* end local */ 12739Sbill } 12839Sbill 12939Sbill /* 130903Sbill * Wait for output to drain, then flush input waiting. 13139Sbill */ 132903Sbill wflushtty(tp) 1335408Swnj register struct tty *tp; 13439Sbill { 13539Sbill 136903Sbill (void) spl5(); 1375622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1385622Swnj && tp->t_oproc) { /* kludge for pty */ 139903Sbill (*tp->t_oproc)(tp); 1405408Swnj tp->t_state |= TS_ASLEEP; 141903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 142903Sbill } 1435426Swnj flushtty(tp, FREAD); 144903Sbill (void) spl0(); 14539Sbill } 14639Sbill 14739Sbill /* 148903Sbill * flush all TTY queues 14939Sbill */ 150903Sbill flushtty(tp, rw) 151*7625Ssam register struct tty *tp; 15239Sbill { 153903Sbill register s; 154903Sbill 155903Sbill s = spl6(); 156903Sbill if (rw & FREAD) { 157903Sbill while (getc(&tp->t_canq) >= 0) 158903Sbill ; 159903Sbill wakeup((caddr_t)&tp->t_rawq); 160903Sbill } 161903Sbill if (rw & FWRITE) { 162903Sbill wakeup((caddr_t)&tp->t_outq); 1635408Swnj tp->t_state &= ~TS_TTSTOP; 1645426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 165903Sbill while (getc(&tp->t_outq) >= 0) 166903Sbill ; 167903Sbill } 168903Sbill if (rw & FREAD) { 169903Sbill while (getc(&tp->t_rawq) >= 0) 170903Sbill ; 171903Sbill tp->t_delct = 0; 172903Sbill tp->t_rocount = 0; /* local */ 173903Sbill tp->t_rocol = 0; 174903Sbill tp->t_lstate = 0; 175903Sbill } 176903Sbill splx(s); 17739Sbill } 17839Sbill 179903Sbill /* 180903Sbill * Send stop character on input overflow. 181903Sbill */ 182903Sbill ttyblock(tp) 183*7625Ssam register struct tty *tp; 18439Sbill { 185903Sbill register x; 186903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 187903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 188903Sbill flushtty(tp, FREAD|FWRITE); 1895408Swnj tp->t_state &= ~TS_TBLOCK; 190903Sbill } 191903Sbill if (x >= TTYHOG/2) { 192903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 1935408Swnj tp->t_state |= TS_TBLOCK; 194903Sbill tp->t_char++; 195903Sbill ttstart(tp); 196903Sbill } 197903Sbill } 19839Sbill } 19939Sbill 20039Sbill /* 201903Sbill * Restart typewriter output following a delay 202903Sbill * timeout. 203903Sbill * The name of the routine is passed to the timeout 204903Sbill * subroutine and it is called during a clock interrupt. 205121Sbill */ 206903Sbill ttrstrt(tp) 207*7625Ssam register struct tty *tp; 208121Sbill { 209121Sbill 2103351Swnj if (tp == 0) { 2113351Swnj printf("ttrstrt: arg was 0!\n"); 2123351Swnj return; 2133351Swnj } 2145408Swnj tp->t_state &= ~TS_TIMEOUT; 215903Sbill ttstart(tp); 216121Sbill } 217121Sbill 218121Sbill /* 219903Sbill * Start output on the typewriter. It is used from the top half 220903Sbill * after some characters have been put on the output queue, 221903Sbill * from the interrupt routine to transmit the next 222903Sbill * character, and after a timeout has finished. 22339Sbill */ 224903Sbill ttstart(tp) 225*7625Ssam register struct tty *tp; 22639Sbill { 227903Sbill register s; 22839Sbill 229903Sbill s = spl5(); 230*7625Ssam if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2315622Swnj tp->t_oproc) /* kludge for pty */ 232903Sbill (*tp->t_oproc)(tp); 233903Sbill splx(s); 23439Sbill } 23539Sbill 23639Sbill /* 237903Sbill * Common code for tty ioctls. 23839Sbill */ 2391780Sbill /*ARGSUSED*/ 240*7625Ssam ttioctl(tp, com, data, flag) 241*7625Ssam register struct tty *tp; 242*7625Ssam caddr_t data; 24339Sbill { 2441904Swnj int dev; 24539Sbill extern int nldisp; 24639Sbill 247903Sbill /* 248915Sbill * This is especially so that isatty() will 249915Sbill * fail when carrier is gone. 250915Sbill */ 2515408Swnj if ((tp->t_state&TS_CARR_ON) == 0) { 252915Sbill u.u_error = EBADF; 253915Sbill return (1); 254915Sbill } 255915Sbill 2561904Swnj dev = tp->t_dev; 257915Sbill /* 258903Sbill * If the ioctl involves modification, 259903Sbill * insist on being able to write the device, 260903Sbill * and hang if in the background. 261903Sbill */ 262*7625Ssam switch (com) { 26339Sbill 264915Sbill case TIOCSETD: 265915Sbill case TIOCSETP: 266915Sbill case TIOCSETN: 267903Sbill case TIOCFLUSH: 268903Sbill case TIOCSETC: 269903Sbill case TIOCSLTC: 270903Sbill case TIOCSPGRP: 271903Sbill case TIOCLBIS: 272903Sbill case TIOCLBIC: 273903Sbill case TIOCLSET: 274915Sbill /* this is reasonable, but impractical... 275903Sbill if ((flag & FWRITE) == 0) { 276903Sbill u.u_error = EBADF; 277903Sbill return (1); 278903Sbill } 279915Sbill */ 280903Sbill while (tp->t_line == NTTYDISC && 281903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 282903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 283903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2845626Swnj u.u_signal[SIGTTOU] != SIG_HOLD 2855626Swnj /* 2865626Swnj && 287903Sbill (u.u_procp->p_flag&SDETACH)==0) { 2885626Swnj */ 2895626Swnj ) { 290903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 291903Sbill sleep((caddr_t)&lbolt, TTOPRI); 292903Sbill } 293903Sbill break; 294903Sbill } 295903Sbill 29639Sbill /* 297903Sbill * Process the ioctl. 29839Sbill */ 299*7625Ssam switch (com) { 300903Sbill 301903Sbill /* 302903Sbill * Get discipline number 303903Sbill */ 30439Sbill case TIOCGETD: 305*7625Ssam *(int *)data = tp->t_line; 30639Sbill break; 30739Sbill 30839Sbill /* 309903Sbill * Set line discipline 31039Sbill */ 311*7625Ssam case TIOCSETD: { 312*7625Ssam register int t = *(int *)data; 313*7625Ssam 31439Sbill if (t >= nldisp) { 31539Sbill u.u_error = ENXIO; 31639Sbill break; 31739Sbill } 318174Sbill (void) spl5(); 31939Sbill if (tp->t_line) 32039Sbill (*linesw[tp->t_line].l_close)(tp); 32139Sbill if (t) 322*7625Ssam (*linesw[t].l_open)(dev, tp); 32339Sbill if (u.u_error==0) 32439Sbill tp->t_line = t; 325174Sbill (void) spl0(); 32639Sbill break; 327*7625Ssam } 32839Sbill 32939Sbill /* 3305614Swnj * Prevent more opens on channel 3315614Swnj */ 3325614Swnj case TIOCEXCL: 3335614Swnj tp->t_state |= TS_XCLUDE; 3345614Swnj break; 3355614Swnj 3365614Swnj case TIOCNXCL: 3375614Swnj tp->t_state &= ~TS_XCLUDE; 3385614Swnj break; 3395614Swnj 3405614Swnj /* 34139Sbill * Set new parameters 34239Sbill */ 34339Sbill case TIOCSETP: 344*7625Ssam case TIOCSETN: { 345*7625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 346*7625Ssam struct clist tq; 347*7625Ssam 348121Sbill (void) spl5(); 349*7625Ssam if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP) 3504484Swnj wflushtty(tp); 351*7625Ssam else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) { 352*7625Ssam if (sg->sg_flags & CBREAK) { 3534484Swnj catq(&tp->t_rawq, &tp->t_canq); 3544484Swnj tq = tp->t_rawq; 3554484Swnj tp->t_rawq = tp->t_canq; 3564484Swnj tp->t_canq = tq; 3574484Swnj } else { 3584484Swnj tp->t_local |= LPENDIN; 3594484Swnj ttwakeup(tp); 360174Sbill } 361174Sbill } 362*7625Ssam tp->t_ispeed = sg->sg_ispeed; 363*7625Ssam tp->t_ospeed = sg->sg_ospeed; 364*7625Ssam tp->t_erase = sg->sg_erase; 365*7625Ssam tp->t_kill = sg->sg_kill; 366*7625Ssam tp->t_flags = sg->sg_flags; 3673941Sbugs if (tp->t_flags & RAW) { 3685408Swnj tp->t_state &= ~TS_TTSTOP; 3693941Sbugs ttstart(tp); 3703941Sbugs } 371121Sbill (void) spl0(); 37239Sbill break; 373*7625Ssam } 37439Sbill 37539Sbill /* 376903Sbill * Send current parameters to user 37739Sbill */ 378*7625Ssam case TIOCGETP: { 379*7625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 380*7625Ssam 381*7625Ssam sg->sg_ispeed = tp->t_ispeed; 382*7625Ssam sg->sg_ospeed = tp->t_ospeed; 383*7625Ssam sg->sg_erase = tp->t_erase; 384*7625Ssam sg->sg_kill = tp->t_kill; 385*7625Ssam sg->sg_flags = tp->t_flags; 38639Sbill break; 387*7625Ssam } 38839Sbill 38939Sbill /* 39039Sbill * Hang up line on last close 39139Sbill */ 39239Sbill case TIOCHPCL: 3935408Swnj tp->t_state |= TS_HUPCLS; 39439Sbill break; 39539Sbill 3963942Sbugs case TIOCFLUSH: { 397*7625Ssam register int flags = *(int *)data; 398*7625Ssam 399*7625Ssam if (flags == 0) 4003942Sbugs flags = FREAD|FWRITE; 401*7625Ssam else 402*7625Ssam flags &= FREAD|FWRITE; 4033942Sbugs flushtty(tp, flags); 40439Sbill break; 4053944Sbugs } 40639Sbill 407*7625Ssam case FIONBIO: 408*7625Ssam if (*(int *)data) 4095408Swnj tp->t_state |= TS_NBIO; 4105408Swnj else 4115408Swnj tp->t_state &= ~TS_NBIO; 4125408Swnj break; 4135408Swnj 414*7625Ssam case FIOASYNC: 415*7625Ssam if (*(int *)data) 4166216Swnj tp->t_state |= TS_ASYNC; 4176216Swnj else 4186216Swnj tp->t_state &= ~TS_ASYNC; 4196216Swnj break; 4206216Swnj 42139Sbill /* 422903Sbill * Set and fetch special characters 42339Sbill */ 42439Sbill case TIOCSETC: 425*7625Ssam bcopy(data, (caddr_t)&tun, sizeof (struct tchars)); 42639Sbill break; 42739Sbill 42839Sbill case TIOCGETC: 429*7625Ssam bcopy((caddr_t)&tun, data, sizeof (struct tchars)); 43039Sbill break; 43139Sbill 432174Sbill /* local ioctls */ 433903Sbill /* 434903Sbill * Set/get local special characters. 435903Sbill */ 436174Sbill case TIOCSLTC: 437*7625Ssam bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars)); 438174Sbill break; 439174Sbill 440174Sbill case TIOCGLTC: 441*7625Ssam bcopy((caddr_t)&tlun, data, sizeof (struct ltchars)); 442174Sbill break; 443174Sbill 444903Sbill /* 445903Sbill * Return number of characters immediately available. 446903Sbill */ 447*7625Ssam case FIONREAD: 448*7625Ssam *(off_t *)data = ttnread(tp); 449174Sbill break; 450174Sbill 451174Sbill /* 452174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 453174Sbill */ 454174Sbill case TIOCSPGRP: 455*7625Ssam tp->t_pgrp = *(int *)data; 456174Sbill break; 457174Sbill 458174Sbill case TIOCGPGRP: 459*7625Ssam *(int *)data = tp->t_pgrp; 460174Sbill break; 461174Sbill 462174Sbill /* 463174Sbill * Modify local mode word. 464174Sbill */ 465174Sbill case TIOCLBIS: 466*7625Ssam tp->t_local |= *(int *)data; 467174Sbill break; 468174Sbill 469174Sbill case TIOCLBIC: 470*7625Ssam tp->t_local &= ~(*(int *)data); 471174Sbill break; 472174Sbill 473174Sbill case TIOCLSET: 474*7625Ssam tp->t_local = *(int *)data; 475174Sbill break; 476174Sbill 477174Sbill case TIOCLGET: 478*7625Ssam *(int *)data = tp->t_local; 479174Sbill break; 480174Sbill 481*7625Ssam case TIOCSTOP: { 482*7625Ssam int s = spl5(); 483213Sbill 4845573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4855573Swnj tp->t_state |= TS_TTSTOP; 4865573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4875573Swnj } 488*7625Ssam splx(s); 4895573Swnj break; 490*7625Ssam } 4915573Swnj 492*7625Ssam case TIOCSTART: { 493*7625Ssam int s = spl5(); 494*7625Ssam 4955573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4965573Swnj tp->t_state &= ~TS_TTSTOP; 4975573Swnj tp->t_local &= ~LFLUSHO; 4985573Swnj ttstart(tp); 4995573Swnj } 500*7625Ssam splx(s); 5015573Swnj break; 502*7625Ssam } 5035573Swnj 504174Sbill /* end of locals */ 505887Sbill 50639Sbill default: 507*7625Ssam return (0); 50839Sbill } 509*7625Ssam return (1); 51039Sbill } 5114484Swnj 5124484Swnj ttnread(tp) 5134484Swnj struct tty *tp; 5144484Swnj { 5154484Swnj int nread = 0; 5164484Swnj 5174484Swnj if (tp->t_local & LPENDIN) 5184484Swnj ttypend(tp); 5194484Swnj nread = tp->t_canq.c_cc; 5204484Swnj if (tp->t_flags & (RAW|CBREAK)) 5214484Swnj nread += tp->t_rawq.c_cc; 5224484Swnj return (nread); 5234484Swnj } 5244484Swnj 5255408Swnj ttselect(dev, rw) 5264484Swnj dev_t dev; 5275408Swnj int rw; 5284484Swnj { 5294484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5304484Swnj int nread; 5315408Swnj int s = spl5(); 5324484Swnj 5335408Swnj switch (rw) { 5344484Swnj 5354484Swnj case FREAD: 5364484Swnj nread = ttnread(tp); 5374484Swnj if (nread > 0) 5385408Swnj goto win; 5394938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5405408Swnj tp->t_state |= TS_RCOLL; 5414484Swnj else 5424484Swnj tp->t_rsel = u.u_procp; 5435408Swnj break; 5444484Swnj 5455408Swnj case FWRITE: 5465408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5475408Swnj goto win; 5485408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5495408Swnj tp->t_state |= TS_WCOLL; 5505408Swnj else 5515408Swnj tp->t_wsel = u.u_procp; 5525408Swnj break; 5534484Swnj } 5545408Swnj splx(s); 5555408Swnj return (0); 5565408Swnj win: 5575408Swnj splx(s); 5585408Swnj return (1); 5594484Swnj } 5607436Skre 5617502Sroot #define OBUFSIZ 100 5627502Sroot 5637502Sroot /* 5647502Sroot * routine called on opens while tp->t_line == NTTYDISC 5657502Sroot * establishes a process group for distribution of 5667502Sroot * quits and interrupts from the tty. 5677502Sroot * (actually, pp->p_pgrp can't be 0 when this routine 5687502Sroot * is called since NTTYDISC is not the default discipline) 5697502Sroot */ 5707502Sroot ttyopen(dev, tp) 571*7625Ssam dev_t dev; 572*7625Ssam register struct tty *tp; 5737502Sroot { 5747502Sroot register struct proc *pp; 5757502Sroot 5767502Sroot pp = u.u_procp; 5777502Sroot tp->t_dev = dev; 578*7625Ssam if (pp->p_pgrp == 0) { 5797502Sroot u.u_ttyp = tp; 5807502Sroot u.u_ttyd = dev; 5817502Sroot if (tp->t_pgrp == 0) 5827502Sroot tp->t_pgrp = pp->p_pid; 5837502Sroot pp->p_pgrp = tp->t_pgrp; 5847502Sroot } 5857502Sroot tp->t_state &= ~TS_WOPEN; 5867502Sroot tp->t_state |= TS_ISOPEN; 5877502Sroot if (tp->t_line != NTTYDISC) 5887502Sroot wflushtty(tp); 5897502Sroot } 5907502Sroot 5917502Sroot /* 5927502Sroot * clean tp on last close 5937502Sroot */ 5947502Sroot ttyclose(tp) 595*7625Ssam register struct tty *tp; 5967502Sroot { 5977502Sroot 5987502Sroot if (tp->t_line) { 5997502Sroot wflushtty(tp); 6007502Sroot tp->t_line = 0; 6017502Sroot return; 6027502Sroot } 6037502Sroot tp->t_pgrp = 0; 6047502Sroot wflushtty(tp); 6057502Sroot tp->t_state = 0; 6067502Sroot } 6077502Sroot 6087502Sroot /* 6097502Sroot * reinput pending characters after state switch 6107502Sroot * call at spl5(). 6117502Sroot */ 6127502Sroot ttypend(tp) 613*7625Ssam register struct tty *tp; 6147502Sroot { 6157502Sroot struct clist tq; 6167502Sroot register c; 6177502Sroot 6187502Sroot tp->t_local &= ~LPENDIN; 6197502Sroot tp->t_lstate |= LSTYPEN; 6207502Sroot tq = tp->t_rawq; 6217502Sroot tp->t_rawq.c_cc = 0; 6227502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6237502Sroot while ((c = getc(&tq)) >= 0) 6247502Sroot ttyinput(c, tp); 6257502Sroot tp->t_lstate &= ~LSTYPEN; 6267502Sroot } 6277502Sroot 6287502Sroot /* 6297502Sroot * Place a character on raw TTY input queue, putting in delimiters 6307502Sroot * and waking up top half as needed. 6317502Sroot * Also echo if required. 6327502Sroot * The arguments are the character and the appropriate 6337502Sroot * tty structure. 6347502Sroot */ 6357502Sroot ttyinput(c, tp) 636*7625Ssam register c; 637*7625Ssam register struct tty *tp; 6387502Sroot { 6397502Sroot register int t_flags; 6407502Sroot int i; 6417502Sroot 6427502Sroot if (tp->t_local&LPENDIN) 6437502Sroot ttypend(tp); 6447502Sroot tk_nin++; 6457502Sroot c &= 0377; 6467502Sroot t_flags = tp->t_flags; 6477502Sroot if (t_flags&TANDEM) 6487502Sroot ttyblock(tp); 6497502Sroot if ((t_flags&RAW)==0) { 6507502Sroot if ((tp->t_lstate&LSTYPEN) == 0) 6517502Sroot c &= 0177; 6527502Sroot /* check for literal nexting very first */ 6537502Sroot if (tp->t_lstate&LSLNCH) { 6547502Sroot c |= 0200; 6557502Sroot tp->t_lstate &= ~LSLNCH; 6567502Sroot } 6577502Sroot if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) { 6587502Sroot if (tp->t_flags&ECHO) 6597502Sroot ttyout("^\b", tp); 6607502Sroot tp->t_lstate |= LSLNCH; 6617502Sroot /* check for output control functions */ 6627502Sroot } else if (c==tun.t_stopc) { 6637502Sroot if ((tp->t_state&TS_TTSTOP)==0) { 6647502Sroot tp->t_state |= TS_TTSTOP; 6657502Sroot (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6667502Sroot return; 6677502Sroot } 6687502Sroot if (c!=tun.t_startc) 6697502Sroot return; 6707502Sroot } else if (c==tun.t_startc) { 6717502Sroot tp->t_state &= ~TS_TTSTOP; 6727502Sroot tp->t_local &= ~LFLUSHO; 6737502Sroot ttstart(tp); 6747502Sroot return; 6757502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) { 6767502Sroot if (tp->t_local & LFLUSHO) 6777502Sroot tp->t_local &= ~LFLUSHO; 6787502Sroot else { 6797502Sroot flushtty(tp, FWRITE); 6807502Sroot ttyecho(c, tp); 6817502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc) 6827502Sroot ttyretype(tp); 6837502Sroot tp->t_local |= LFLUSHO; 6847502Sroot } 6857502Sroot ttstart(tp); 6867502Sroot return; 6877502Sroot } else if (c==tun.t_intrc || c==tun.t_quitc || 6887502Sroot (tp->t_line == NTTYDISC && c==tlun.t_suspc)) { 6897502Sroot if ((tp->t_local & LNOFLSH) == 0) 6907502Sroot flushtty(tp, 6917502Sroot c==tlun.t_suspc ? FREAD : FREAD|FWRITE); 6927502Sroot ttyecho(c, tp); 6937502Sroot c = c==tun.t_intrc ? SIGINT : 6947502Sroot ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP); 6957502Sroot ttsignal(tp, c); 6967502Sroot /* check for buffer editing functions - cooked mode */ 6977502Sroot } else if ((t_flags&CBREAK) == 0) { 6987502Sroot if ((tp->t_lstate&LSQUOT) && 6997502Sroot (c==tp->t_erase||c==tp->t_kill)) { 7007502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7017502Sroot c |= 0200; 7027502Sroot } 7037502Sroot if (c==tp->t_erase) { 7047502Sroot if (tp->t_rawq.c_cc) 7057502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7067502Sroot } else if (c==tp->t_kill) { 7077502Sroot if (tp->t_local&LCRTKIL && 7087502Sroot tp->t_rawq.c_cc == tp->t_rocount) { 7097502Sroot while (tp->t_rawq.c_cc) 7107502Sroot ttyrub(unputc(&tp->t_rawq), tp); 7117502Sroot } else { 7127502Sroot ttyecho(c, tp); 7137502Sroot ttyecho('\n', tp); 7147502Sroot while (getc(&tp->t_rawq) > 0) 7157502Sroot ; 7167502Sroot tp->t_rocount = 0; 7177502Sroot } 7187502Sroot tp->t_lstate = 0; 7197502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) { 7207502Sroot if (tp->t_rawq.c_cc == 0) 7217502Sroot goto out; 7227502Sroot do { 7237502Sroot c = unputc(&tp->t_rawq); 7247502Sroot if (c != ' ' && c != '\t') 7257502Sroot goto erasenb; 7267502Sroot ttyrub(c, tp); 7277502Sroot } while (tp->t_rawq.c_cc); 7287502Sroot goto out; 7297502Sroot erasenb: 7307502Sroot do { 7317502Sroot ttyrub(c, tp); 7327502Sroot if (tp->t_rawq.c_cc == 0) 7337502Sroot goto out; 7347502Sroot c = unputc(&tp->t_rawq); 7357502Sroot } while (c != ' ' && c != '\t'); 7367502Sroot (void) putc(c, &tp->t_rawq); 7377502Sroot } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) { 7387502Sroot ttyretype(tp); 7397502Sroot /* check for cooked mode input buffer overflow */ 7407502Sroot } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 7417502Sroot ; 7427502Sroot /* put data char in q for user and wakeup if a break char */ 7437502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7447502Sroot if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG 7457502Sroot && tp->t_line == NTTYDISC) 7467502Sroot (void) ttyoutput(CTRL(g), tp); 7477502Sroot if (!ttbreakc(c, tp)) { 7487502Sroot if (tp->t_rocount++ == 0) 7497502Sroot tp->t_rocol = tp->t_col; 7507502Sroot } else { 7517502Sroot tp->t_rocount = 0; 7527502Sroot catq(&tp->t_rawq, &tp->t_canq); 7537502Sroot /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */ 7547502Sroot ttwakeup(tp); 7557502Sroot } 7567502Sroot tp->t_lstate &= ~LSQUOT; 7577502Sroot if (c == '\\') 7587502Sroot tp->t_lstate |= LSQUOT; 7597502Sroot if (tp->t_lstate&LSERASE) { 7607502Sroot tp->t_lstate &= ~LSERASE; 7617502Sroot (void) ttyoutput('/', tp); 7627502Sroot } 7637502Sroot i = tp->t_col; 7647502Sroot ttyecho(c, tp); 7657502Sroot if (c==tun.t_eofc && tp->t_flags&ECHO) { 7667502Sroot i = MIN(2, tp->t_col - i); 7677502Sroot while (i > 0) { 7687502Sroot (void) ttyoutput('\b', tp); 7697502Sroot i--; 7707502Sroot } 7717502Sroot } 7727502Sroot } 7737502Sroot /* CBREAK mode */ 7747502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) { 7757502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7767502Sroot tp->t_line == NTTYDISC) 7777502Sroot (void) ttyoutput(CTRL(g), tp); 7787502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7797502Sroot ttwakeup(tp); 7807502Sroot ttyecho(c, tp); 7817502Sroot } 7827502Sroot /* RAW mode */ 7837502Sroot } else if (tp->t_rawq.c_cc > TTYHOG) 7847502Sroot flushtty(tp, FREAD|FWRITE); 7857502Sroot else { 7867502Sroot if (putc(c, &tp->t_rawq) >= 0) 7877502Sroot ttwakeup(tp); 7887502Sroot ttyecho(c, tp); 7897502Sroot } 7907502Sroot out: 7917502Sroot if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP && 7927502Sroot tun.t_startc != tun.t_stopc) 7937502Sroot return; 7947502Sroot tp->t_state &= ~TS_TTSTOP; 7957502Sroot tp->t_local &= ~LFLUSHO; 7967502Sroot ttstart(tp); 7977502Sroot } 7987502Sroot 7997502Sroot /* 8007502Sroot * put character on TTY output queue, adding delays, 8017502Sroot * expanding tabs, and handling the CR/NL bit. 8027502Sroot * It is called both from the top half for output, and from 8037502Sroot * interrupt level for echoing. 8047502Sroot * The arguments are the character and the tty structure. 8057502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8067502Sroot * Must be recursive. 8077502Sroot */ 8087502Sroot ttyoutput(c, tp) 8097502Sroot register c; 8107502Sroot register struct tty *tp; 8117502Sroot { 8127502Sroot register char *colp; 8137502Sroot register ctype; 8147502Sroot 8157502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) { 8167502Sroot if (tp->t_local&LFLUSHO) 8177502Sroot return (-1); 8187502Sroot if (putc(c, &tp->t_outq)) 819*7625Ssam return (c); 8207502Sroot tk_nout++; 8217502Sroot return (-1); 8227502Sroot } 8237502Sroot /* 8247502Sroot * Ignore EOT in normal mode to avoid hanging up 8257502Sroot * certain terminals. 8267502Sroot */ 8277502Sroot c &= 0177; 8287502Sroot if (c==CEOT && (tp->t_flags&CBREAK)==0) 8297502Sroot return (-1); 8307502Sroot /* 8317502Sroot * Turn tabs to spaces as required 8327502Sroot */ 8337502Sroot if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 8347502Sroot register int s; 8357502Sroot 8367502Sroot c = 8 - (tp->t_col&7); 8377502Sroot if ((tp->t_local&LFLUSHO) == 0) { 8387502Sroot s = spl5(); /* don't interrupt tabs */ 8397502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8407502Sroot tk_nout += c; 8417502Sroot splx(s); 8427502Sroot } 8437502Sroot tp->t_col += c; 8447502Sroot return (c ? -1 : '\t'); 8457502Sroot } 8467502Sroot tk_nout++; 8477502Sroot /* 8487502Sroot * for upper-case-only terminals, 8497502Sroot * generate escapes. 8507502Sroot */ 8517502Sroot if (tp->t_flags&LCASE) { 8527502Sroot colp = "({)}!|^~'`"; 853*7625Ssam while (*colp++) 854*7625Ssam if (c == *colp++) { 8557502Sroot if (ttyoutput('\\', tp) >= 0) 8567502Sroot return (c); 8577502Sroot c = colp[-2]; 8587502Sroot break; 8597502Sroot } 8607502Sroot if ('A'<=c && c<='Z') { 8617502Sroot if (ttyoutput('\\', tp) >= 0) 8627502Sroot return (c); 8637502Sroot } else if ('a'<=c && c<='z') 8647502Sroot c += 'A' - 'a'; 8657502Sroot } 8667502Sroot /* 8677502Sroot * turn <nl> to <cr><lf> if desired. 8687502Sroot */ 8697502Sroot if (c=='\n' && tp->t_flags&CRMOD) 8707502Sroot if (ttyoutput('\r', tp) >= 0) 8717502Sroot return (c); 8727502Sroot if (c=='~' && tp->t_local<ILDE) 8737502Sroot c = '`'; 8747502Sroot if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq)) 8757502Sroot return (c); 8767502Sroot /* 8777502Sroot * Calculate delays. 8787502Sroot * The numbers here represent clock ticks 8797502Sroot * and are not necessarily optimal for all terminals. 8807502Sroot * The delays are indicated by characters above 0200. 8817502Sroot * In raw mode there are no delays and the 8827502Sroot * transmission path is 8 bits wide. 8837502Sroot */ 8847502Sroot colp = &tp->t_col; 8857502Sroot ctype = partab[c]; 8867502Sroot c = 0; 8877502Sroot switch (ctype&077) { 8887502Sroot 8897502Sroot case ORDINARY: 8907502Sroot (*colp)++; 8917502Sroot 8927502Sroot case CONTROL: 8937502Sroot break; 8947502Sroot 8957502Sroot case BACKSPACE: 8967502Sroot if (*colp) 8977502Sroot (*colp)--; 8987502Sroot break; 8997502Sroot 9007502Sroot case NEWLINE: 9017502Sroot ctype = (tp->t_flags >> 8) & 03; 902*7625Ssam if (ctype == 1) { /* tty 37 */ 9037502Sroot if (*colp) 9047502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9057502Sroot } else 906*7625Ssam if (ctype == 2) { /* vt05 */ 9077502Sroot c = 6; 9087502Sroot } 9097502Sroot *colp = 0; 9107502Sroot break; 9117502Sroot 9127502Sroot case TAB: 9137502Sroot ctype = (tp->t_flags >> 10) & 03; 914*7625Ssam if (ctype == 1) { /* tty 37 */ 9157502Sroot c = 1 - (*colp | ~07); 916*7625Ssam if (c < 5) 9177502Sroot c = 0; 9187502Sroot } 9197502Sroot *colp |= 07; 9207502Sroot (*colp)++; 9217502Sroot break; 9227502Sroot 9237502Sroot case VTAB: 924*7625Ssam if (tp->t_flags & VTDELAY) /* tty 37 */ 9257502Sroot c = 0177; 9267502Sroot break; 9277502Sroot 9287502Sroot case RETURN: 9297502Sroot ctype = (tp->t_flags >> 12) & 03; 930*7625Ssam if (ctype == 1) { /* tn 300 */ 9317502Sroot c = 5; 932*7625Ssam } else if (ctype == 2) { /* ti 700 */ 9337502Sroot c = 10; 934*7625Ssam } else if (ctype == 3) { /* concept 100 */ 9357502Sroot int i; 9367502Sroot if ((i = *colp) >= 0) 9377502Sroot for (; i<9; i++) 9387502Sroot (void) putc(0177, &tp->t_outq); 9397502Sroot } 9407502Sroot *colp = 0; 9417502Sroot } 942*7625Ssam if (c && (tp->t_local&LFLUSHO) == 0) 9437502Sroot (void) putc(c|0200, &tp->t_outq); 9447502Sroot return (-1); 9457502Sroot } 9467502Sroot 9477502Sroot /* 9487502Sroot * Called from device's read routine after it has 9497502Sroot * calculated the tty-structure given as argument. 9507502Sroot */ 9517502Sroot ttread(tp) 952*7625Ssam register struct tty *tp; 9537502Sroot { 9547502Sroot register struct clist *qp; 9557502Sroot register c, first; 9567502Sroot 9577502Sroot if ((tp->t_state&TS_CARR_ON)==0) 958*7625Ssam return (0); 9597502Sroot loop: 9607502Sroot (void) spl5(); 9617502Sroot if (tp->t_local&LPENDIN) 9627502Sroot ttypend(tp); 9637502Sroot (void) spl0(); 9647502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9657502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9667502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9677502Sroot /* 9687502Sroot (u.u_procp->p_flag&SDETACH) || 9697502Sroot */ 9707502Sroot u.u_procp->p_flag&SVFORK) 9717502Sroot return (0); 9727502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 9737502Sroot sleep((caddr_t)&lbolt, TTIPRI); 9747502Sroot } 9757502Sroot if (tp->t_flags&RAW) { 9767502Sroot (void) spl5(); 9777502Sroot if (tp->t_rawq.c_cc <= 0) { 9787502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9797502Sroot (tp->t_state&TS_NBIO)) { 9807502Sroot (void) spl0(); 9817502Sroot return (0); 9827502Sroot } 9837502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 9847502Sroot (void) spl0(); 9857502Sroot goto loop; 9867502Sroot } 9877502Sroot (void) spl0(); 9887502Sroot while (tp->t_rawq.c_cc && passc(getc(&tp->t_rawq))>=0) 9897502Sroot ; 9907502Sroot return (0); 9917502Sroot } else { 9927502Sroot qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq; 9937502Sroot (void) spl5(); 9947502Sroot if (qp->c_cc <= 0) { 9957502Sroot if ((tp->t_state&TS_CARR_ON)==0 || 9967502Sroot (tp->t_state&TS_NBIO)) { 9977502Sroot (void) spl0(); 9987502Sroot return (0); 9997502Sroot } 10007502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10017502Sroot (void) spl0(); 10027502Sroot goto loop; 10037502Sroot } 10047502Sroot (void) spl0(); 10057502Sroot first = 1; 10067502Sroot while ((c = getc(qp)) >= 0) { 10077502Sroot if (tp->t_flags&CRMOD && c == '\r') 10087502Sroot c = '\n'; 10097502Sroot if (tp->t_flags&LCASE && c <= 0177) 10107502Sroot if (tp->t_lstate&LSBKSL) { 10117502Sroot if (maptab[c]) 10127502Sroot c = maptab[c]; 10137502Sroot tp->t_lstate &= ~LSBKSL; 10147502Sroot } else if (c >= 'A' && c <= 'Z') 10157502Sroot c += 'a' - 'A'; 10167502Sroot else if (c == '\\') { 10177502Sroot tp->t_lstate |= LSBKSL; 10187502Sroot continue; 10197502Sroot } 10207502Sroot if (c == tlun.t_dsuspc) { 10217502Sroot ttsignal(tp, SIGTSTP); 10227502Sroot if (first) { 10237502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10247502Sroot goto loop; 10257502Sroot } 10267502Sroot break; 10277502Sroot } 10287502Sroot if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0) 10297502Sroot break; 10307502Sroot if (passc(c & 0177) < 0) 10317502Sroot break; 10327502Sroot if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp)) 10337502Sroot break; 10347502Sroot first = 0; 10357502Sroot } 10367502Sroot tp->t_lstate &= ~LSBKSL; 10377502Sroot } 10387502Sroot 10397502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 10407502Sroot if (putc(tun.t_startc, &tp->t_outq)==0) { 10417502Sroot tp->t_state &= ~TS_TBLOCK; 10427502Sroot ttstart(tp); 10437502Sroot } 10447502Sroot tp->t_char = 0; 10457502Sroot } 10467502Sroot 10477502Sroot return (tp->t_rawq.c_cc + tp->t_canq.c_cc); 10487502Sroot } 10497502Sroot 10507502Sroot /* 10517502Sroot * Called from the device's write routine after it has 10527502Sroot * calculated the tty-structure given as argument. 10537502Sroot */ 10547502Sroot caddr_t 10557502Sroot ttwrite(tp) 1056*7625Ssam register struct tty *tp; 10577502Sroot { 10587502Sroot #ifdef vax 10597502Sroot /* 10607502Sroot * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 10617502Sroot * AND MUST NOT BE CHANGED WITHOUT PATCHING 10627502Sroot * THE 'ASM' INLINES BELOW. WATCH OUT. 10637502Sroot */ 10647502Sroot #endif 10657502Sroot register char *cp; 10667502Sroot register int cc, ce; 10677502Sroot register i; 10687502Sroot char obuf[OBUFSIZ]; 10697502Sroot register c; 10707502Sroot int hiwat = TTHIWAT(tp); 10717502Sroot int cnt = u.u_count; 10727502Sroot 10737502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10747502Sroot return (NULL); 10757502Sroot loop: 10767502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 10777502Sroot (tp->t_local<OSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 10787502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 10797502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 10807502Sroot /* 10817502Sroot && 10827502Sroot (u.u_procp->p_flag&SDETACH)==0) { 10837502Sroot */ 10847502Sroot ) { 10857502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 10867502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10877502Sroot } 10887502Sroot while (u.u_count) { 10897502Sroot cc = MIN(u.u_count, OBUFSIZ); 10907502Sroot cp = obuf; 10917502Sroot iomove(cp, (unsigned)cc, B_WRITE); 10927502Sroot if (u.u_error) 10937502Sroot break; 10947502Sroot if (tp->t_outq.c_cc > hiwat) 10957502Sroot goto ovhiwat; 10967502Sroot if (tp->t_local&LFLUSHO) 10977502Sroot continue; 10987502Sroot if (tp->t_flags&LCASE || tp->t_local<ILDE) { 10997502Sroot while (cc) { 11007502Sroot c = *cp++; 11017502Sroot tp->t_rocount = 0; 1102*7625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 11037502Sroot /* out of clists, wait a bit */ 11047502Sroot ttstart(tp); 11057502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11067502Sroot tp->t_rocount = 0; 11077502Sroot } 11087502Sroot --cc; 11097502Sroot if (tp->t_outq.c_cc > hiwat) 11107502Sroot goto ovhiwat; 11117502Sroot } 11127502Sroot continue; 11137502Sroot } 11147502Sroot while (cc) { 11157502Sroot if (tp->t_flags&RAW || tp->t_local&LLITOUT) 11167502Sroot ce = cc; 11177502Sroot else { 11187502Sroot #ifdef vax 11197502Sroot asm(" scanc r9,(r10),_partab,$077"); 11207502Sroot asm(" subl3 r0,r9,r8"); 11217502Sroot #else 11227502Sroot ce=0; 1123*7625Ssam while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc)) 11247502Sroot ce++; 11257502Sroot #endif 11267502Sroot if (ce==0) { 11277502Sroot tp->t_rocount = 0; 11287502Sroot if (ttyoutput(*cp, tp) >= 0) { 11297502Sroot ttstart(tp); 11307502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11317502Sroot continue; 11327502Sroot } 11337502Sroot cp++; 11347502Sroot cc--; 11357502Sroot if (tp->t_outq.c_cc > hiwat) 11367502Sroot goto ovhiwat; 11377502Sroot } 11387502Sroot } 11397502Sroot tp->t_rocount = 0; 11407502Sroot i=b_to_q(cp,ce,&tp->t_outq); 11417502Sroot ce-=i; 11427502Sroot tk_nout+=ce; 11437502Sroot tp->t_col+=ce; 11447502Sroot cp+=ce; 11457502Sroot cc-=ce; 11467502Sroot if (i) { 11477502Sroot ttstart(tp); 11487502Sroot sleep((caddr_t)&lbolt, TTOPRI); 11497502Sroot } 11507502Sroot if (ce || tp->t_outq.c_cc > hiwat) 11517502Sroot goto ovhiwat; 11527502Sroot } 11537502Sroot } 11547502Sroot ttstart(tp); 1155*7625Ssam return (NULL); 11567502Sroot 11577502Sroot ovhiwat: 11587502Sroot (void) spl5(); 11597502Sroot u.u_base -= cc; 11607502Sroot u.u_offset -= cc; 11617502Sroot u.u_count += cc; 11627502Sroot if (tp->t_outq.c_cc <= hiwat) { 11637502Sroot (void) spl0(); 11647502Sroot goto loop; 11657502Sroot } 11667502Sroot ttstart(tp); 11677502Sroot if (tp->t_state & TS_NBIO) { 11687502Sroot if (u.u_count == cnt) 11697502Sroot u.u_error = EWOULDBLOCK; 11707502Sroot return (NULL); 11717502Sroot } 11727502Sroot tp->t_state |= TS_ASLEEP; 11737502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 11747502Sroot (void) spl0(); 11757502Sroot goto loop; 11767502Sroot } 11777502Sroot 11787502Sroot /* 11797502Sroot * Rubout one character from the rawq of tp 11807502Sroot * as cleanly as possible. 11817502Sroot */ 11827502Sroot ttyrub(c, tp) 1183*7625Ssam register c; 1184*7625Ssam register struct tty *tp; 11857502Sroot { 11867502Sroot register char *cp; 11877502Sroot register int savecol; 11887502Sroot int s; 11897502Sroot char *nextc(); 11907502Sroot 11917502Sroot if ((tp->t_flags&ECHO)==0) 11927502Sroot return; 11937502Sroot tp->t_local &= ~LFLUSHO; 11947502Sroot c &= 0377; 11957502Sroot if (tp->t_local&LCRTBS) { 11967502Sroot if (tp->t_rocount == 0) { 11977502Sroot /* 11987502Sroot * Screwed by ttwrite; retype 11997502Sroot */ 12007502Sroot ttyretype(tp); 12017502Sroot return; 12027502Sroot } 12037502Sroot if (c==('\t'|0200) || c==('\n'|0200)) 12047502Sroot ttyrubo(tp, 2); 1205*7625Ssam else switch (partab[c&=0177] & 0177) { 12067502Sroot 12077502Sroot case ORDINARY: 12087502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 12097502Sroot ttyrubo(tp, 2); 12107502Sroot else 12117502Sroot ttyrubo(tp, 1); 12127502Sroot break; 12137502Sroot 12147502Sroot case VTAB: 12157502Sroot case BACKSPACE: 12167502Sroot case CONTROL: 12177502Sroot case RETURN: 12187502Sroot if (tp->t_local & LCTLECH) 12197502Sroot ttyrubo(tp, 2); 12207502Sroot break; 12217502Sroot 12227502Sroot case TAB: 12237502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 12247502Sroot ttyretype(tp); 12257502Sroot return; 12267502Sroot } 12277502Sroot s = spl5(); 12287502Sroot savecol = tp->t_col; 12297502Sroot tp->t_lstate |= LSCNTTB; 12307502Sroot tp->t_local |= LFLUSHO; 12317502Sroot tp->t_col = tp->t_rocol; 12327502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12337502Sroot ttyecho(*cp, tp); 12347502Sroot tp->t_local &= ~LFLUSHO; 12357502Sroot tp->t_lstate &= ~LSCNTTB; 12367502Sroot splx(s); 12377502Sroot /* 12387502Sroot * savecol will now be length of the tab 12397502Sroot */ 12407502Sroot savecol -= tp->t_col; 12417502Sroot tp->t_col += savecol; 12427502Sroot if (savecol > 8) 12437502Sroot savecol = 8; /* overflow screw */ 12447502Sroot while (--savecol >= 0) 12457502Sroot (void) ttyoutput('\b', tp); 12467502Sroot break; 12477502Sroot 12487502Sroot default: 12497502Sroot panic("ttyrub"); 12507502Sroot } 12517502Sroot } else if (tp->t_local&LPRTERA) { 12527502Sroot if ((tp->t_lstate&LSERASE) == 0) { 12537502Sroot (void) ttyoutput('\\', tp); 12547502Sroot tp->t_lstate |= LSERASE; 12557502Sroot } 12567502Sroot ttyecho(c, tp); 12577502Sroot } else 12587502Sroot ttyecho(tp->t_erase, tp); 12597502Sroot tp->t_rocount--; 12607502Sroot } 12617502Sroot 12627502Sroot /* 12637502Sroot * Crt back over cnt chars perhaps 12647502Sroot * erasing them. 12657502Sroot */ 12667502Sroot ttyrubo(tp, cnt) 1267*7625Ssam register struct tty *tp; 1268*7625Ssam int cnt; 12697502Sroot { 12707502Sroot 12717502Sroot while (--cnt >= 0) 12727502Sroot ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp); 12737502Sroot } 12747502Sroot 12757502Sroot /* 12767502Sroot * Reprint the rawq line. 12777502Sroot * We assume c_cc has already been checked. 12787502Sroot */ 12797502Sroot ttyretype(tp) 1280*7625Ssam register struct tty *tp; 12817502Sroot { 12827502Sroot register char *cp; 12837502Sroot char *nextc(); 12847502Sroot int s; 12857502Sroot 12867502Sroot if (tlun.t_rprntc != 0377) 12877502Sroot ttyecho(tlun.t_rprntc, tp); 12887502Sroot (void) ttyoutput('\n', tp); 12897502Sroot s = spl5(); 12907502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 12917502Sroot ttyecho(*cp, tp); 12927502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 12937502Sroot ttyecho(*cp, tp); 12947502Sroot tp->t_lstate &= ~LSERASE; 12957502Sroot splx(s); 12967502Sroot tp->t_rocount = tp->t_rawq.c_cc; 12977502Sroot tp->t_rocol = 0; 12987502Sroot } 12997502Sroot 13007502Sroot /* 13017502Sroot * Echo a typed character to the terminal 13027502Sroot */ 13037502Sroot ttyecho(c, tp) 1304*7625Ssam register c; 1305*7625Ssam register struct tty *tp; 13067502Sroot { 13077502Sroot 13087502Sroot if ((tp->t_lstate & LSCNTTB) == 0) 13097502Sroot tp->t_local &= ~LFLUSHO; 13107502Sroot if ((tp->t_flags&ECHO) == 0) 13117502Sroot return; 13127502Sroot c &= 0377; 13137502Sroot if (tp->t_flags&RAW) { 13147502Sroot (void) ttyoutput(c, tp); 13157502Sroot return; 13167502Sroot } 13177502Sroot if (c == '\r' && tp->t_flags&CRMOD) 13187502Sroot c = '\n'; 13197502Sroot if (tp->t_local&LCTLECH) { 13207502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 13217502Sroot (void) ttyoutput('^', tp); 13227502Sroot c &= 0177; 13237502Sroot if (c == 0177) 13247502Sroot c = '?'; 13257502Sroot else if (tp->t_flags&LCASE) 13267502Sroot c += 'a' - 1; 13277502Sroot else 13287502Sroot c += 'A' - 1; 13297502Sroot } 13307502Sroot } 13317502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 13327502Sroot c += 'a' - 'A'; 13337502Sroot (void) ttyoutput(c & 0177, tp); 13347502Sroot } 13357502Sroot 13367502Sroot /* 13377502Sroot * Is c a break char for tp? 13387502Sroot */ 13397502Sroot ttbreakc(c, tp) 1340*7625Ssam register c; 1341*7625Ssam register struct tty *tp; 13427502Sroot { 13437502Sroot return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc || 13447502Sroot c == '\r' && (tp->t_flags&CRMOD)); 13457502Sroot } 13467502Sroot 13477502Sroot /* 13487502Sroot * send string cp to tp 13497502Sroot */ 13507502Sroot ttyout(cp, tp) 1351*7625Ssam register char *cp; 1352*7625Ssam register struct tty *tp; 13537502Sroot { 13547502Sroot register char c; 13557502Sroot 13567502Sroot while (c = *cp++) 13577502Sroot (void) ttyoutput(c, tp); 13587502Sroot } 13597502Sroot 13607502Sroot ttwakeup(tp) 13617502Sroot struct tty *tp; 13627502Sroot { 13637502Sroot 13647502Sroot if (tp->t_rsel) { 13657502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 13667502Sroot tp->t_state &= ~TS_RCOLL; 13677502Sroot tp->t_rsel = 0; 13687502Sroot } 13697502Sroot wakeup((caddr_t)&tp->t_rawq); 13707502Sroot } 13717502Sroot 13727502Sroot ttsignal(tp, signo) 13737502Sroot struct tty *tp; 13747502Sroot int signo; 13757502Sroot { 13767502Sroot 13777502Sroot gsignal(tp->t_pgrp, signo); 13787502Sroot } 1379