1*9578Ssam /* tty.c 4.35 82/12/07 */ 239Sbill 339Sbill #include "../h/param.h" 439Sbill #include "../h/systm.h" 539Sbill #include "../h/dir.h" 639Sbill #include "../h/user.h" 7*9578Ssam #include "../h/ioctl.h" 839Sbill #include "../h/tty.h" 939Sbill #include "../h/proc.h" 1039Sbill #include "../h/inode.h" 1139Sbill #include "../h/file.h" 1239Sbill #include "../h/reg.h" 1339Sbill #include "../h/conf.h" 1439Sbill #include "../h/buf.h" 15340Sbill #include "../h/dk.h" 167722Swnj #include "../h/uio.h" 178154Sroot #include "../h/kernel.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 char maptab[] ={ 7639Sbill 000,000,000,000,000,000,000,000, 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,'`', 8139Sbill '{','}',000,000,000,000,000,000, 8239Sbill 000,000,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, 8839Sbill 000,'A','B','C','D','E','F','G', 8939Sbill 'H','I','J','K','L','M','N','O', 9039Sbill 'P','Q','R','S','T','U','V','W', 9139Sbill 'X','Y','Z',000,000,000,000,000, 9239Sbill }; 9339Sbill 94925Sbill short tthiwat[16] = 958954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 96925Sbill short ttlowat[16] = 97925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 98925Sbill 99*9578Ssam struct ttychars ttydefaults = { 100*9578Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 101*9578Ssam CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 102*9578Ssam }; 10339Sbill 10439Sbill ttychars(tp) 105*9578Ssam struct tty *tp; 10639Sbill { 107174Sbill 108*9578Ssam tp->t_chars = ttydefaults; 10939Sbill } 11039Sbill 11139Sbill /* 112903Sbill * Wait for output to drain, then flush input waiting. 11339Sbill */ 114903Sbill wflushtty(tp) 1155408Swnj register struct tty *tp; 11639Sbill { 11739Sbill 118903Sbill (void) spl5(); 1195622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1205622Swnj && tp->t_oproc) { /* kludge for pty */ 121903Sbill (*tp->t_oproc)(tp); 1225408Swnj tp->t_state |= TS_ASLEEP; 123903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 124903Sbill } 1255426Swnj flushtty(tp, FREAD); 126903Sbill (void) spl0(); 12739Sbill } 12839Sbill 12939Sbill /* 130*9578Ssam * Flush all TTY queues 13139Sbill */ 132903Sbill flushtty(tp, rw) 1337625Ssam register struct tty *tp; 13439Sbill { 135903Sbill register s; 136903Sbill 137903Sbill s = spl6(); 138903Sbill if (rw & FREAD) { 139903Sbill while (getc(&tp->t_canq) >= 0) 140903Sbill ; 141903Sbill wakeup((caddr_t)&tp->t_rawq); 142903Sbill } 143903Sbill if (rw & FWRITE) { 144903Sbill wakeup((caddr_t)&tp->t_outq); 1455408Swnj tp->t_state &= ~TS_TTSTOP; 1465426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 147903Sbill while (getc(&tp->t_outq) >= 0) 148903Sbill ; 149903Sbill } 150903Sbill if (rw & FREAD) { 151903Sbill while (getc(&tp->t_rawq) >= 0) 152903Sbill ; 153903Sbill tp->t_delct = 0; 154*9578Ssam tp->t_rocount = 0; 155903Sbill tp->t_rocol = 0; 156*9578Ssam tp->t_state &= ~TS_LOCAL; 157903Sbill } 158903Sbill splx(s); 15939Sbill } 16039Sbill 161903Sbill /* 162903Sbill * Send stop character on input overflow. 163903Sbill */ 164903Sbill ttyblock(tp) 1657625Ssam register struct tty *tp; 16639Sbill { 167903Sbill register x; 168*9578Ssam 169903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 170903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 171903Sbill flushtty(tp, FREAD|FWRITE); 1725408Swnj tp->t_state &= ~TS_TBLOCK; 173903Sbill } 174*9578Ssam if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) { 175*9578Ssam tp->t_state |= TS_TBLOCK; 176*9578Ssam tp->t_char++; 177*9578Ssam ttstart(tp); 178903Sbill } 17939Sbill } 18039Sbill 18139Sbill /* 182903Sbill * Restart typewriter output following a delay 183903Sbill * timeout. 184903Sbill * The name of the routine is passed to the timeout 185903Sbill * subroutine and it is called during a clock interrupt. 186121Sbill */ 187903Sbill ttrstrt(tp) 1887625Ssam register struct tty *tp; 189121Sbill { 190121Sbill 191*9578Ssam if (tp == 0) 192*9578Ssam panic("ttrstrt"); 1935408Swnj tp->t_state &= ~TS_TIMEOUT; 194903Sbill ttstart(tp); 195121Sbill } 196121Sbill 197121Sbill /* 198903Sbill * Start output on the typewriter. It is used from the top half 199903Sbill * after some characters have been put on the output queue, 200903Sbill * from the interrupt routine to transmit the next 201903Sbill * character, and after a timeout has finished. 20239Sbill */ 203903Sbill ttstart(tp) 2047625Ssam register struct tty *tp; 20539Sbill { 206903Sbill register s; 20739Sbill 208903Sbill s = spl5(); 209*9578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2105622Swnj tp->t_oproc) /* kludge for pty */ 211903Sbill (*tp->t_oproc)(tp); 212903Sbill splx(s); 21339Sbill } 21439Sbill 21539Sbill /* 216903Sbill * Common code for tty ioctls. 21739Sbill */ 2181780Sbill /*ARGSUSED*/ 2197625Ssam ttioctl(tp, com, data, flag) 2207625Ssam register struct tty *tp; 2217625Ssam caddr_t data; 22239Sbill { 2238520Sroot int dev = tp->t_dev; 22439Sbill extern int nldisp; 2258556Sroot int s; 22639Sbill 227903Sbill /* 228903Sbill * If the ioctl involves modification, 229903Sbill * insist on being able to write the device, 230903Sbill * and hang if in the background. 231903Sbill */ 2327625Ssam switch (com) { 23339Sbill 234915Sbill case TIOCSETD: 235915Sbill case TIOCSETP: 236915Sbill case TIOCSETN: 237903Sbill case TIOCFLUSH: 238903Sbill case TIOCSETC: 239903Sbill case TIOCSLTC: 240903Sbill case TIOCSPGRP: 241903Sbill case TIOCLBIS: 242903Sbill case TIOCLBIC: 243903Sbill case TIOCLSET: 2449325Ssam case TIOCSTI: 245903Sbill while (tp->t_line == NTTYDISC && 246903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 247903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 248903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2498556Sroot u.u_signal[SIGTTOU] != SIG_HOLD) { 250903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 251903Sbill sleep((caddr_t)&lbolt, TTOPRI); 252903Sbill } 253903Sbill break; 254903Sbill } 255903Sbill 256*9578Ssam /* 257*9578Ssam * Process the ioctl. 258*9578Ssam */ 2597625Ssam switch (com) { 260903Sbill 2618556Sroot /* get discipline number */ 26239Sbill case TIOCGETD: 2637625Ssam *(int *)data = tp->t_line; 26439Sbill break; 26539Sbill 2668556Sroot /* set line discipline */ 2677625Ssam case TIOCSETD: { 2687625Ssam register int t = *(int *)data; 269*9578Ssam int error = 0; 2707625Ssam 271*9578Ssam if (t >= nldisp) { 272*9578Ssam u.u_error = ENXIO; 273*9578Ssam break; 274*9578Ssam } 2758556Sroot s = spl5(); 27639Sbill if (tp->t_line) 27739Sbill (*linesw[tp->t_line].l_close)(tp); 27839Sbill if (t) 2798556Sroot error = (*linesw[t].l_open)(dev, tp); 2808556Sroot splx(s); 2818556Sroot if (error) 2828556Sroot return (error); 2838556Sroot tp->t_line = t; 28439Sbill break; 2857625Ssam } 28639Sbill 2878556Sroot /* prevent more opens on channel */ 2885614Swnj case TIOCEXCL: 2895614Swnj tp->t_state |= TS_XCLUDE; 2905614Swnj break; 2915614Swnj 2925614Swnj case TIOCNXCL: 2935614Swnj tp->t_state &= ~TS_XCLUDE; 2945614Swnj break; 2955614Swnj 2968556Sroot /* set new parameters */ 29739Sbill case TIOCSETP: 2987625Ssam case TIOCSETN: { 2997625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3007625Ssam struct clist tq; 3017625Ssam 302121Sbill (void) spl5(); 3037625Ssam if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP) 3044484Swnj wflushtty(tp); 3057625Ssam else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) { 306*9578Ssam if (sg->sg_flags&CBREAK) { 3074484Swnj catq(&tp->t_rawq, &tp->t_canq); 3084484Swnj tq = tp->t_rawq; 3094484Swnj tp->t_rawq = tp->t_canq; 3104484Swnj tp->t_canq = tq; 3114484Swnj } else { 312*9578Ssam tp->t_flags |= PENDIN; 3134484Swnj ttwakeup(tp); 314174Sbill } 315174Sbill } 3167625Ssam tp->t_ispeed = sg->sg_ispeed; 3177625Ssam tp->t_ospeed = sg->sg_ospeed; 3187625Ssam tp->t_erase = sg->sg_erase; 3197625Ssam tp->t_kill = sg->sg_kill; 320*9578Ssam tp->t_flags &= ~0xffff; 321*9578Ssam tp->t_flags |= sg->sg_flags; 322*9578Ssam if (tp->t_flags&RAW) { 3235408Swnj tp->t_state &= ~TS_TTSTOP; 3243941Sbugs ttstart(tp); 3253941Sbugs } 326121Sbill (void) spl0(); 32739Sbill break; 3287625Ssam } 32939Sbill 3308556Sroot /* send current parameters to user */ 3317625Ssam case TIOCGETP: { 3327625Ssam register struct sgttyb *sg = (struct sgttyb *)data; 3337625Ssam 3347625Ssam sg->sg_ispeed = tp->t_ispeed; 3357625Ssam sg->sg_ospeed = tp->t_ospeed; 3367625Ssam sg->sg_erase = tp->t_erase; 3377625Ssam sg->sg_kill = tp->t_kill; 3387625Ssam sg->sg_flags = tp->t_flags; 33939Sbill break; 3407625Ssam } 34139Sbill 3428556Sroot /* hang up line on last close */ 34339Sbill case TIOCHPCL: 3445408Swnj tp->t_state |= TS_HUPCLS; 34539Sbill break; 34639Sbill 3473942Sbugs case TIOCFLUSH: { 3487625Ssam register int flags = *(int *)data; 3497625Ssam 3507625Ssam if (flags == 0) 3513942Sbugs flags = FREAD|FWRITE; 3527625Ssam else 3537625Ssam flags &= FREAD|FWRITE; 3543942Sbugs flushtty(tp, flags); 35539Sbill break; 3563944Sbugs } 35739Sbill 358*9578Ssam /* set and fetch special characters */ 359*9578Ssam /* THIS SHOULD USE struct ttychars */ 360*9578Ssam case TIOCSETC: 361*9578Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 362*9578Ssam break; 363*9578Ssam 364*9578Ssam case TIOCGETC: 365*9578Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 366*9578Ssam break; 367*9578Ssam 368*9578Ssam /* BEGIN DEFUNCT */ 3697625Ssam case FIONBIO: 3707625Ssam if (*(int *)data) 3715408Swnj tp->t_state |= TS_NBIO; 3725408Swnj else 3735408Swnj tp->t_state &= ~TS_NBIO; 3745408Swnj break; 3755408Swnj 376*9578Ssam /* set/get local special characters */ 377*9578Ssam case TIOCSLTC: 378*9578Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 3796216Swnj break; 3806216Swnj 381*9578Ssam case TIOCGLTC: 382*9578Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 38339Sbill break; 38439Sbill 385*9578Ssam /* 386*9578Ssam * Modify local mode word. 387*9578Ssam */ 388*9578Ssam case TIOCLBIS: 389*9578Ssam tp->t_flags |= *(int *)data << 16; 39039Sbill break; 39139Sbill 392*9578Ssam case TIOCLBIC: 393*9578Ssam tp->t_flags &= ~(*(int *)data << 16); 394174Sbill break; 395174Sbill 396*9578Ssam case TIOCLSET: 397*9578Ssam tp->t_flags &= 0xffff; 398*9578Ssam tp->t_flags |= *(int *)data << 16; 399174Sbill break; 400174Sbill 401*9578Ssam case TIOCLGET: 402*9578Ssam *(int *)data = tp->t_flags >> 16; 403*9578Ssam break; 404*9578Ssam /* END DEFUNCT */ 405*9578Ssam 4068556Sroot /* return number of characters immediately available */ 4077625Ssam case FIONREAD: 4087625Ssam *(off_t *)data = ttnread(tp); 409174Sbill break; 410174Sbill 4118556Sroot /* should allow SPGRP and GPGRP only if tty open for reading */ 412174Sbill case TIOCSPGRP: 4137625Ssam tp->t_pgrp = *(int *)data; 414174Sbill break; 415174Sbill 416174Sbill case TIOCGPGRP: 4177625Ssam *(int *)data = tp->t_pgrp; 418174Sbill break; 419174Sbill 4208589Sroot case TIOCSTOP: 4218589Sroot s = spl5(); 422*9578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 4235573Swnj tp->t_state |= TS_TTSTOP; 4245573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4255573Swnj } 4267625Ssam splx(s); 4275573Swnj break; 4285573Swnj 4298589Sroot case TIOCSTART: 4308589Sroot s = spl5(); 431*9578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 4325573Swnj tp->t_state &= ~TS_TTSTOP; 433*9578Ssam tp->t_flags &= ~FLUSHO; 4345573Swnj ttstart(tp); 4355573Swnj } 4367625Ssam splx(s); 4375573Swnj break; 4385573Swnj 4399325Ssam /* 4409325Ssam * Simulate typing of a character at the terminal. 4419325Ssam */ 4429325Ssam case TIOCSTI: 4439325Ssam if (u.u_uid && u.u_ttyp != tp) 4449325Ssam return (EACCES); 445*9578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4469325Ssam break; 4479325Ssam 44839Sbill default: 4498556Sroot return (-1); 45039Sbill } 4518556Sroot return (0); 45239Sbill } 4534484Swnj 4544484Swnj ttnread(tp) 4554484Swnj struct tty *tp; 4564484Swnj { 4574484Swnj int nread = 0; 4584484Swnj 459*9578Ssam if (tp->t_flags & PENDIN) 4604484Swnj ttypend(tp); 4614484Swnj nread = tp->t_canq.c_cc; 4624484Swnj if (tp->t_flags & (RAW|CBREAK)) 4634484Swnj nread += tp->t_rawq.c_cc; 4644484Swnj return (nread); 4654484Swnj } 4664484Swnj 4675408Swnj ttselect(dev, rw) 4684484Swnj dev_t dev; 4695408Swnj int rw; 4704484Swnj { 4714484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4724484Swnj int nread; 4735408Swnj int s = spl5(); 4744484Swnj 4755408Swnj switch (rw) { 4764484Swnj 4774484Swnj case FREAD: 4784484Swnj nread = ttnread(tp); 4794484Swnj if (nread > 0) 4805408Swnj goto win; 4814938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 4825408Swnj tp->t_state |= TS_RCOLL; 4834484Swnj else 4844484Swnj tp->t_rsel = u.u_procp; 4855408Swnj break; 4864484Swnj 4875408Swnj case FWRITE: 4885408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 4895408Swnj goto win; 4905408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 4915408Swnj tp->t_state |= TS_WCOLL; 4925408Swnj else 4935408Swnj tp->t_wsel = u.u_procp; 4945408Swnj break; 4954484Swnj } 4965408Swnj splx(s); 4975408Swnj return (0); 4985408Swnj win: 4995408Swnj splx(s); 5005408Swnj return (1); 5014484Swnj } 5027436Skre 5037502Sroot /* 504*9578Ssam * Establish a process group for distribution of 5057502Sroot * quits and interrupts from the tty. 5067502Sroot */ 5077502Sroot ttyopen(dev, tp) 5087625Ssam dev_t dev; 5097625Ssam register struct tty *tp; 5107502Sroot { 5117502Sroot register struct proc *pp; 5127502Sroot 5137502Sroot pp = u.u_procp; 5147502Sroot tp->t_dev = dev; 5157625Ssam if (pp->p_pgrp == 0) { 5167502Sroot u.u_ttyp = tp; 5177502Sroot u.u_ttyd = dev; 5187502Sroot if (tp->t_pgrp == 0) 5197502Sroot tp->t_pgrp = pp->p_pid; 5207502Sroot pp->p_pgrp = tp->t_pgrp; 5217502Sroot } 5227502Sroot tp->t_state &= ~TS_WOPEN; 5237502Sroot tp->t_state |= TS_ISOPEN; 5247502Sroot if (tp->t_line != NTTYDISC) 5257502Sroot wflushtty(tp); 5268556Sroot return (0); 5277502Sroot } 5287502Sroot 5297502Sroot /* 5307502Sroot * clean tp on last close 5317502Sroot */ 5327502Sroot ttyclose(tp) 5337625Ssam register struct tty *tp; 5347502Sroot { 5357502Sroot 5367502Sroot if (tp->t_line) { 5377502Sroot wflushtty(tp); 5387502Sroot tp->t_line = 0; 5397502Sroot return; 5407502Sroot } 5417502Sroot tp->t_pgrp = 0; 5427502Sroot wflushtty(tp); 5437502Sroot tp->t_state = 0; 5447502Sroot } 5457502Sroot 5467502Sroot /* 5477502Sroot * reinput pending characters after state switch 5487502Sroot * call at spl5(). 5497502Sroot */ 5507502Sroot ttypend(tp) 5517625Ssam register struct tty *tp; 5527502Sroot { 5537502Sroot struct clist tq; 5547502Sroot register c; 5557502Sroot 556*9578Ssam tp->t_flags &= ~PENDIN; 557*9578Ssam tp->t_state |= TS_TYPEN; 5587502Sroot tq = tp->t_rawq; 5597502Sroot tp->t_rawq.c_cc = 0; 5607502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5617502Sroot while ((c = getc(&tq)) >= 0) 5627502Sroot ttyinput(c, tp); 563*9578Ssam tp->t_state &= ~TS_TYPEN; 5647502Sroot } 5657502Sroot 5667502Sroot /* 567*9578Ssam * Place a character on raw TTY input queue, 568*9578Ssam * putting in delimiters and waking up top 569*9578Ssam * half as needed. Also echo if required. 570*9578Ssam * The arguments are the character and the 571*9578Ssam * appropriate tty structure. 5727502Sroot */ 5737502Sroot ttyinput(c, tp) 5747625Ssam register c; 5757625Ssam register struct tty *tp; 5767502Sroot { 577*9578Ssam register int t_flags = tp->t_flags; 5787502Sroot int i; 5797502Sroot 580*9578Ssam /* 581*9578Ssam * If input is pending take it first. 582*9578Ssam */ 583*9578Ssam if (t_flags&PENDIN) 5847502Sroot ttypend(tp); 5857502Sroot tk_nin++; 5867502Sroot c &= 0377; 587*9578Ssam 588*9578Ssam /* 589*9578Ssam * In tandem mode, check high water mark. 590*9578Ssam */ 5917502Sroot if (t_flags&TANDEM) 5927502Sroot ttyblock(tp); 593*9578Ssam 594*9578Ssam if (t_flags&RAW) { 595*9578Ssam /* 596*9578Ssam * Raw mode, just put character 597*9578Ssam * in input q w/o interpretation. 598*9578Ssam */ 599*9578Ssam if (tp->t_rawq.c_cc > TTYHOG) 600*9578Ssam flushtty(tp, FREAD|FWRITE); 601*9578Ssam else { 602*9578Ssam if (putc(c, &tp->t_rawq) >= 0) 603*9578Ssam ttwakeup(tp); 604*9578Ssam ttyecho(c, tp); 6057502Sroot } 606*9578Ssam goto endcase; 607*9578Ssam } 608*9578Ssam 609*9578Ssam /* 610*9578Ssam * Ignore any high bit added during 611*9578Ssam * previous ttyinput processing. 612*9578Ssam */ 613*9578Ssam if ((tp->t_state&TS_TYPEN) == 0) 614*9578Ssam c &= 0177; 615*9578Ssam /* 616*9578Ssam * Check for literal nexting very first 617*9578Ssam */ 618*9578Ssam if (tp->t_state&TS_LNCH) { 619*9578Ssam c |= 0200; 620*9578Ssam tp->t_state &= ~TS_LNCH; 621*9578Ssam } 622*9578Ssam 623*9578Ssam /* 624*9578Ssam * Scan for special characters. This code 625*9578Ssam * is really just a big case statement with 626*9578Ssam * non-constant cases. The bottom of the 627*9578Ssam * case statement is labeled ``endcase'', so goto 628*9578Ssam * it after a case match, or similar. 629*9578Ssam */ 630*9578Ssam if (tp->t_line == NTTYDISC) { 631*9578Ssam if (c == tp->t_lnextc) { 6327502Sroot if (tp->t_flags&ECHO) 6337502Sroot ttyout("^\b", tp); 634*9578Ssam tp->t_state |= TS_LNCH; 635*9578Ssam goto endcase; 636*9578Ssam } 637*9578Ssam if (c == tp->t_flushc) { 638*9578Ssam if (tp->t_flags&FLUSHO) 639*9578Ssam tp->t_flags &= ~FLUSHO; 6407502Sroot else { 6417502Sroot flushtty(tp, FWRITE); 6427502Sroot ttyecho(c, tp); 643*9578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6447502Sroot ttyretype(tp); 645*9578Ssam tp->t_flags |= FLUSHO; 6467502Sroot } 647*9578Ssam goto startoutput; 648*9578Ssam } 649*9578Ssam if (c == tp->t_suspc) { 650*9578Ssam if ((tp->t_flags&NOFLSH) == 0) 651*9578Ssam flushtty(tp, FREAD); 652*9578Ssam ttyecho(c, tp); 653*9578Ssam gsignal(tp->t_pgrp, SIGTSTP); 654*9578Ssam goto endcase; 655*9578Ssam } 656*9578Ssam } 657*9578Ssam 658*9578Ssam /* 659*9578Ssam * Handle start/stop characters. 660*9578Ssam */ 661*9578Ssam if (c == tp->t_stopc) { 662*9578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 663*9578Ssam tp->t_state |= TS_TTSTOP; 664*9578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6657502Sroot return; 666*9578Ssam } 667*9578Ssam if (c != tp->t_startc) 668*9578Ssam return; 669*9578Ssam goto endcase; 670*9578Ssam } 671*9578Ssam if (c == tp->t_startc) 672*9578Ssam goto restartoutput; 673*9578Ssam 674*9578Ssam /* 675*9578Ssam * Look for interrupt/quit chars. 676*9578Ssam */ 677*9578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 678*9578Ssam if ((tp->t_flags&NOFLSH) == 0) 679*9578Ssam flushtty(tp, FREAD|FWRITE); 680*9578Ssam ttyecho(c, tp); 681*9578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 682*9578Ssam goto endcase; 683*9578Ssam } 684*9578Ssam 685*9578Ssam /* 686*9578Ssam * Cbreak mode, don't process line editing 687*9578Ssam * characters; check high water mark for wakeup. 688*9578Ssam */ 689*9578Ssam if (t_flags&CBREAK) { 690*9578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 6917502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 6927502Sroot tp->t_line == NTTYDISC) 6937502Sroot (void) ttyoutput(CTRL(g), tp); 6947502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 6957502Sroot ttwakeup(tp); 6967502Sroot ttyecho(c, tp); 6977502Sroot } 698*9578Ssam goto endcase; 699*9578Ssam } 700*9578Ssam 701*9578Ssam /* 702*9578Ssam * From here on down cooked mode character 703*9578Ssam * processing takes place. 704*9578Ssam */ 705*9578Ssam if ((tp->t_state&TS_QUOT) && 706*9578Ssam (c == tp->t_erase || c == tp->t_kill)) { 707*9578Ssam ttyrub(unputc(&tp->t_rawq), tp); 708*9578Ssam c |= 0200; 709*9578Ssam } 710*9578Ssam if (c == tp->t_erase) { 711*9578Ssam if (tp->t_rawq.c_cc) 712*9578Ssam ttyrub(unputc(&tp->t_rawq), tp); 713*9578Ssam goto endcase; 714*9578Ssam } 715*9578Ssam if (c == tp->t_kill) { 716*9578Ssam if (tp->t_flags&CRTKIL && 717*9578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 718*9578Ssam while (tp->t_rawq.c_cc) 719*9578Ssam ttyrub(unputc(&tp->t_rawq), tp); 720*9578Ssam } else { 721*9578Ssam ttyecho(c, tp); 722*9578Ssam ttyecho('\n', tp); 723*9578Ssam while (getc(&tp->t_rawq) > 0) 724*9578Ssam ; 725*9578Ssam tp->t_rocount = 0; 726*9578Ssam } 727*9578Ssam tp->t_state &= ~TS_LOCAL; 728*9578Ssam goto endcase; 729*9578Ssam } 730*9578Ssam 731*9578Ssam /* 732*9578Ssam * New line discipline, 733*9578Ssam * check word erase/reprint line. 734*9578Ssam */ 735*9578Ssam if (tp->t_line == NTTYDISC) { 736*9578Ssam if (c == tp->t_werasc) { 737*9578Ssam if (tp->t_rawq.c_cc == 0) 738*9578Ssam goto endcase; 739*9578Ssam do { 740*9578Ssam c = unputc(&tp->t_rawq); 741*9578Ssam if (c != ' ' && c != '\t') 742*9578Ssam goto erasenb; 743*9578Ssam ttyrub(c, tp); 744*9578Ssam } while (tp->t_rawq.c_cc); 745*9578Ssam goto endcase; 746*9578Ssam erasenb: 747*9578Ssam do { 748*9578Ssam ttyrub(c, tp); 749*9578Ssam if (tp->t_rawq.c_cc == 0) 750*9578Ssam goto endcase; 751*9578Ssam c = unputc(&tp->t_rawq); 752*9578Ssam } while (c != ' ' && c != '\t'); 753*9578Ssam (void) putc(c, &tp->t_rawq); 754*9578Ssam goto endcase; 755*9578Ssam } 756*9578Ssam if (c == tp->t_rprntc) { 757*9578Ssam ttyretype(tp); 758*9578Ssam goto endcase; 759*9578Ssam } 760*9578Ssam } 761*9578Ssam 762*9578Ssam /* 763*9578Ssam * Check for input buffer overflow 764*9578Ssam */ 765*9578Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) 766*9578Ssam goto endcase; 767*9578Ssam 768*9578Ssam /* 769*9578Ssam * Put data char in q for user and 770*9578Ssam * wakeup on seeing a line delimiter. 771*9578Ssam */ 772*9578Ssam if (putc(c, &tp->t_rawq) >= 0) { 773*9578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc == TTYHOG 774*9578Ssam && tp->t_line == NTTYDISC) 775*9578Ssam (void) ttyoutput(CTRL(g), tp); 776*9578Ssam if (ttbreakc(c, tp)) { 777*9578Ssam tp->t_rocount = 0; 778*9578Ssam catq(&tp->t_rawq, &tp->t_canq); 7797502Sroot ttwakeup(tp); 780*9578Ssam } else if (tp->t_rocount++ == 0) 781*9578Ssam tp->t_rocol = tp->t_col; 782*9578Ssam tp->t_state &= ~TS_QUOT; 783*9578Ssam if (c == '\\') 784*9578Ssam tp->t_state |= TS_QUOT; 785*9578Ssam if (tp->t_state&TS_ERASE) { 786*9578Ssam tp->t_state &= ~TS_ERASE; 787*9578Ssam (void) ttyoutput('/', tp); 788*9578Ssam } 789*9578Ssam i = tp->t_col; 7907502Sroot ttyecho(c, tp); 791*9578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 792*9578Ssam i = MIN(2, tp->t_col - i); 793*9578Ssam while (i > 0) { 794*9578Ssam (void) ttyoutput('\b', tp); 795*9578Ssam i--; 796*9578Ssam } 797*9578Ssam } 7987502Sroot } 799*9578Ssam 800*9578Ssam endcase: 801*9578Ssam /* 802*9578Ssam * If DEC-style start/stop is enabled don't restart 803*9578Ssam * output until seeing the start character. 804*9578Ssam */ 805*9578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 806*9578Ssam tp->t_startc != tp->t_stopc) 8077502Sroot return; 808*9578Ssam 809*9578Ssam restartoutput: 8107502Sroot tp->t_state &= ~TS_TTSTOP; 811*9578Ssam tp->t_flags &= ~FLUSHO; 812*9578Ssam 813*9578Ssam startoutput: 8147502Sroot ttstart(tp); 8157502Sroot } 8167502Sroot 8177502Sroot /* 818*9578Ssam * Put character on TTY output queue, adding delays, 8197502Sroot * expanding tabs, and handling the CR/NL bit. 820*9578Ssam * This is called both from the top half for output, 821*9578Ssam * and from interrupt level for echoing. 8227502Sroot * The arguments are the character and the tty structure. 8237502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8247502Sroot * Must be recursive. 8257502Sroot */ 8267502Sroot ttyoutput(c, tp) 8277502Sroot register c; 8287502Sroot register struct tty *tp; 8297502Sroot { 8307502Sroot register char *colp; 8317502Sroot register ctype; 8327502Sroot 833*9578Ssam if (tp->t_flags & (RAW|LITOUT)) { 834*9578Ssam if (tp->t_flags&FLUSHO) 8357502Sroot return (-1); 8367502Sroot if (putc(c, &tp->t_outq)) 8377625Ssam return (c); 8387502Sroot tk_nout++; 8397502Sroot return (-1); 8407502Sroot } 841*9578Ssam 8427502Sroot /* 843*9578Ssam * Ignore EOT in normal mode to avoid 844*9578Ssam * hanging up certain terminals. 8457502Sroot */ 8467502Sroot c &= 0177; 847*9578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8487502Sroot return (-1); 8497502Sroot /* 8507502Sroot * Turn tabs to spaces as required 8517502Sroot */ 852*9578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8537502Sroot register int s; 8547502Sroot 8557502Sroot c = 8 - (tp->t_col&7); 856*9578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8577502Sroot s = spl5(); /* don't interrupt tabs */ 8587502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8597502Sroot tk_nout += c; 8607502Sroot splx(s); 8617502Sroot } 8627502Sroot tp->t_col += c; 8637502Sroot return (c ? -1 : '\t'); 8647502Sroot } 8657502Sroot tk_nout++; 8667502Sroot /* 8677502Sroot * for upper-case-only terminals, 8687502Sroot * generate escapes. 8697502Sroot */ 8707502Sroot if (tp->t_flags&LCASE) { 8717502Sroot colp = "({)}!|^~'`"; 8727625Ssam while (*colp++) 8737625Ssam if (c == *colp++) { 8747502Sroot if (ttyoutput('\\', tp) >= 0) 8757502Sroot return (c); 8767502Sroot c = colp[-2]; 8777502Sroot break; 8787502Sroot } 879*9578Ssam if ('A' <= c && c <= 'Z') { 8807502Sroot if (ttyoutput('\\', tp) >= 0) 8817502Sroot return (c); 882*9578Ssam } else if ('a' <= c && c <= 'z') 8837502Sroot c += 'A' - 'a'; 8847502Sroot } 885*9578Ssam 8867502Sroot /* 8877502Sroot * turn <nl> to <cr><lf> if desired. 8887502Sroot */ 889*9578Ssam if (c == '\n' && tp->t_flags&CRMOD) 8907502Sroot if (ttyoutput('\r', tp) >= 0) 8917502Sroot return (c); 892*9578Ssam if (c == '~' && tp->t_flags&TILDE) 8937502Sroot c = '`'; 894*9578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 8957502Sroot return (c); 8967502Sroot /* 8977502Sroot * Calculate delays. 8987502Sroot * The numbers here represent clock ticks 8997502Sroot * and are not necessarily optimal for all terminals. 9007502Sroot * The delays are indicated by characters above 0200. 9017502Sroot * In raw mode there are no delays and the 9027502Sroot * transmission path is 8 bits wide. 903*9578Ssam * 904*9578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9057502Sroot */ 9067502Sroot colp = &tp->t_col; 9077502Sroot ctype = partab[c]; 9087502Sroot c = 0; 9097502Sroot switch (ctype&077) { 9107502Sroot 9117502Sroot case ORDINARY: 9127502Sroot (*colp)++; 9137502Sroot 9147502Sroot case CONTROL: 9157502Sroot break; 9167502Sroot 9177502Sroot case BACKSPACE: 9187502Sroot if (*colp) 9197502Sroot (*colp)--; 9207502Sroot break; 9217502Sroot 9227502Sroot case NEWLINE: 9237502Sroot ctype = (tp->t_flags >> 8) & 03; 9247625Ssam if (ctype == 1) { /* tty 37 */ 9257502Sroot if (*colp) 9267502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 927*9578Ssam } else if (ctype == 2) /* vt05 */ 9287502Sroot c = 6; 9297502Sroot *colp = 0; 9307502Sroot break; 9317502Sroot 9327502Sroot case TAB: 9337502Sroot ctype = (tp->t_flags >> 10) & 03; 9347625Ssam if (ctype == 1) { /* tty 37 */ 9357502Sroot c = 1 - (*colp | ~07); 9367625Ssam if (c < 5) 9377502Sroot c = 0; 9387502Sroot } 9397502Sroot *colp |= 07; 9407502Sroot (*colp)++; 9417502Sroot break; 9427502Sroot 9437502Sroot case VTAB: 944*9578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9457502Sroot c = 0177; 9467502Sroot break; 9477502Sroot 9487502Sroot case RETURN: 9497502Sroot ctype = (tp->t_flags >> 12) & 03; 950*9578Ssam if (ctype == 1) /* tn 300 */ 9517502Sroot c = 5; 952*9578Ssam else if (ctype == 2) /* ti 700 */ 9537502Sroot c = 10; 954*9578Ssam else if (ctype == 3) { /* concept 100 */ 9557502Sroot int i; 956*9578Ssam 9577502Sroot if ((i = *colp) >= 0) 958*9578Ssam for (; i < 9; i++) 9597502Sroot (void) putc(0177, &tp->t_outq); 9607502Sroot } 9617502Sroot *colp = 0; 9627502Sroot } 963*9578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9647502Sroot (void) putc(c|0200, &tp->t_outq); 9657502Sroot return (-1); 9667502Sroot } 9677502Sroot 9687502Sroot /* 9697502Sroot * Called from device's read routine after it has 9707502Sroot * calculated the tty-structure given as argument. 9717502Sroot */ 9727722Swnj ttread(tp, uio) 9737625Ssam register struct tty *tp; 9747722Swnj struct uio *uio; 9757502Sroot { 9767502Sroot register struct clist *qp; 977*9578Ssam register c, t_flags; 978*9578Ssam int first, error = 0; 9797502Sroot 9807502Sroot if ((tp->t_state&TS_CARR_ON)==0) 9818520Sroot return (EIO); 9827502Sroot loop: 983*9578Ssam /* 984*9578Ssam * Take any pending input first. 985*9578Ssam */ 9867502Sroot (void) spl5(); 987*9578Ssam if (tp->t_flags&PENDIN) 9887502Sroot ttypend(tp); 9897502Sroot (void) spl0(); 990*9578Ssam 991*9578Ssam /* 992*9578Ssam * Hang process if it's in the background. 993*9578Ssam */ 9947502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9957502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 9967502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 9977502Sroot /* 9987502Sroot (u.u_procp->p_flag&SDETACH) || 9997502Sroot */ 10007502Sroot u.u_procp->p_flag&SVFORK) 10018520Sroot return (EIO); 10027502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10037502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10047502Sroot } 1005*9578Ssam t_flags = tp->t_flags; 1006*9578Ssam 1007*9578Ssam /* 1008*9578Ssam * In raw mode take characters directly from the 1009*9578Ssam * raw queue w/o processing. Interlock against 1010*9578Ssam * device interrupts when interrogating rawq. 1011*9578Ssam */ 1012*9578Ssam if (t_flags&RAW) { 10137502Sroot (void) spl5(); 10147502Sroot if (tp->t_rawq.c_cc <= 0) { 1015*9578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10167502Sroot (tp->t_state&TS_NBIO)) { 10177502Sroot (void) spl0(); 1018*9578Ssam return (0); 10197502Sroot } 10207502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10217502Sroot (void) spl0(); 10227502Sroot goto loop; 10237502Sroot } 10247502Sroot (void) spl0(); 10257722Swnj while (tp->t_rawq.c_cc && uio->uio_iovcnt) { 10268520Sroot error = passuc(getc(&tp->t_rawq), uio); 10278520Sroot if (error) 10287722Swnj break; 10297722Swnj } 10308520Sroot return (error); 1031*9578Ssam } 1032*9578Ssam 1033*9578Ssam /* 1034*9578Ssam * In cbreak mode use the rawq, otherwise 1035*9578Ssam * take characters from the canonicalized q. 1036*9578Ssam */ 1037*9578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 1038*9578Ssam 1039*9578Ssam /* 1040*9578Ssam * No input, sleep on rawq awaiting hardware 1041*9578Ssam * receipt and notification. 1042*9578Ssam */ 1043*9578Ssam (void) spl5(); 1044*9578Ssam if (qp->c_cc <= 0) { 1045*9578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 1046*9578Ssam (tp->t_state&TS_NBIO)) { 10477502Sroot (void) spl0(); 1048*9578Ssam return (EWOULDBLOCK); 10497502Sroot } 1050*9578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10517502Sroot (void) spl0(); 1052*9578Ssam goto loop; 1053*9578Ssam } 1054*9578Ssam (void) spl0(); 1055*9578Ssam 1056*9578Ssam /* 1057*9578Ssam * Input present, perform input mapping 1058*9578Ssam * and processing (we're not in raw mode). 1059*9578Ssam */ 1060*9578Ssam first = 1; 1061*9578Ssam while ((c = getc(qp)) >= 0) { 1062*9578Ssam if (t_flags&CRMOD && c == '\r') 1063*9578Ssam c = '\n'; 1064*9578Ssam /* 1065*9578Ssam * Hack lower case simulation on 1066*9578Ssam * upper case only terminals. 1067*9578Ssam */ 1068*9578Ssam if (t_flags&LCASE && c <= 0177) 1069*9578Ssam if (tp->t_state&TS_BKSL) { 1070*9578Ssam if (maptab[c]) 1071*9578Ssam c = maptab[c]; 1072*9578Ssam tp->t_state &= ~TS_BKSL; 1073*9578Ssam } else if (c >= 'A' && c <= 'Z') 1074*9578Ssam c += 'a' - 'A'; 1075*9578Ssam else if (c == '\\') { 1076*9578Ssam tp->t_state |= TS_BKSL; 1077*9578Ssam continue; 10787502Sroot } 1079*9578Ssam /* 1080*9578Ssam * Check for delayed suspend character. 1081*9578Ssam */ 1082*9578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 1083*9578Ssam gsignal(tp->t_pgrp, SIGTSTP); 1084*9578Ssam if (first) { 1085*9578Ssam sleep((caddr_t)&lbolt, TTIPRI); 1086*9578Ssam goto loop; 1087*9578Ssam } 1088*9578Ssam break; 10897502Sroot } 1090*9578Ssam /* 1091*9578Ssam * Interpret EOF only in cooked mode. 1092*9578Ssam */ 1093*9578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 1094*9578Ssam break; 1095*9578Ssam /* 1096*9578Ssam * Give user character. 1097*9578Ssam */ 1098*9578Ssam error = passuc(c & 0177, uio); 1099*9578Ssam if (error) 1100*9578Ssam break; 1101*9578Ssam if (uio->uio_iovcnt == 0) 1102*9578Ssam break; 1103*9578Ssam /* 1104*9578Ssam * In cooked mode check for a "break character" 1105*9578Ssam * marking the end of a "line of input". 1106*9578Ssam */ 1107*9578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 1108*9578Ssam break; 1109*9578Ssam first = 0; 11107502Sroot } 1111*9578Ssam tp->t_state &= ~TS_BKSL; 1112*9578Ssam 1113*9578Ssam /* 1114*9578Ssam * Look to unblock output now that (presumably) 1115*9578Ssam * the input queue has gone down. 1116*9578Ssam */ 11177502Sroot if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 1118*9578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11197502Sroot tp->t_state &= ~TS_TBLOCK; 11207502Sroot ttstart(tp); 11217502Sroot } 11227502Sroot tp->t_char = 0; 11237502Sroot } 11248520Sroot return (error); 11257502Sroot } 11267502Sroot 11277502Sroot /* 11287502Sroot * Called from the device's write routine after it has 11297502Sroot * calculated the tty-structure given as argument. 11307502Sroot */ 11317822Sroot ttwrite(tp, uio) 11327625Ssam register struct tty *tp; 1133*9578Ssam register struct uio *uio; 11347502Sroot { 11357502Sroot register char *cp; 1136*9578Ssam register int cc, ce, c; 1137*9578Ssam int i, hiwat, cnt, error, s; 11387502Sroot char obuf[OBUFSIZ]; 11397502Sroot 1140*9578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11418520Sroot return (EIO); 1142*9578Ssam hiwat = TTHIWAT(tp); 1143*9578Ssam cnt = uio->uio_resid; 1144*9578Ssam error = 0; 11457502Sroot loop: 1146*9578Ssam /* 1147*9578Ssam * Hang the process if it's in the background. 1148*9578Ssam */ 11497502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 1150*9578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11517502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11527502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11537502Sroot /* 11547502Sroot && 11557502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11567502Sroot */ 11577502Sroot ) { 11587502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11597502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11607502Sroot } 1161*9578Ssam 1162*9578Ssam /* 1163*9578Ssam * Process the user's data in at most OBUFSIZ 1164*9578Ssam * chunks. Perform lower case simulation and 1165*9578Ssam * similar hacks. Keep track of high water 1166*9578Ssam * mark, sleep on overflow awaiting device aid 1167*9578Ssam * in acquiring new space. 1168*9578Ssam */ 11697822Sroot while (uio->uio_resid > 0) { 1170*9578Ssam /* 1171*9578Ssam * Grab a hunk of data from the user. 1172*9578Ssam */ 11737822Sroot cc = uio->uio_iov->iov_len; 11747822Sroot if (cc == 0) { 11757822Sroot uio->uio_iovcnt--; 11767822Sroot uio->uio_iov++; 11777822Sroot if (uio->uio_iovcnt < 0) 11787822Sroot panic("ttwrite"); 11797822Sroot continue; 11807822Sroot } 11817822Sroot if (cc > OBUFSIZ) 11827822Sroot cc = OBUFSIZ; 11837502Sroot cp = obuf; 1184*9578Ssam error = uiomove(cp, (unsigned)cc, UIO_WRITE, uio); 11858520Sroot if (error) 11867502Sroot break; 11877502Sroot if (tp->t_outq.c_cc > hiwat) 11887502Sroot goto ovhiwat; 1189*9578Ssam if (tp->t_flags&FLUSHO) 11907502Sroot continue; 1191*9578Ssam /* 1192*9578Ssam * If we're mapping lower case or kludging tildes, 1193*9578Ssam * then we've got to look at each character, so 1194*9578Ssam * just feed the stuff to ttyoutput... 1195*9578Ssam */ 1196*9578Ssam if (tp->t_flags & (LCASE|TILDE)) { 1197*9578Ssam while (cc > 0) { 11987502Sroot c = *cp++; 11997502Sroot tp->t_rocount = 0; 12007625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12017502Sroot /* out of clists, wait a bit */ 12027502Sroot ttstart(tp); 12037502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12047502Sroot tp->t_rocount = 0; 12057502Sroot } 12067502Sroot --cc; 12077502Sroot if (tp->t_outq.c_cc > hiwat) 12087502Sroot goto ovhiwat; 12097502Sroot } 12107502Sroot continue; 12117502Sroot } 1212*9578Ssam /* 1213*9578Ssam * If nothing fancy need be done, grab those characters we 1214*9578Ssam * can handle without any of ttyoutput's processing and 1215*9578Ssam * just transfer them to the output q. For those chars 1216*9578Ssam * which require special processing (as indicated by the 1217*9578Ssam * bits in partab), call ttyoutput. After processing 1218*9578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 1219*9578Ssam * immediately. 1220*9578Ssam */ 1221*9578Ssam while (cc > 0) { 1222*9578Ssam if (tp->t_flags & (RAW|LITOUT)) 12237502Sroot ce = cc; 12247502Sroot else { 1225*9578Ssam ce = cc - scanc(cc, cp, partab, 077); 1226*9578Ssam /* 1227*9578Ssam * If ce is zero, then we're processing 1228*9578Ssam * a special character through ttyoutput. 1229*9578Ssam */ 1230*9578Ssam if (ce == 0) { 12317502Sroot tp->t_rocount = 0; 12327502Sroot if (ttyoutput(*cp, tp) >= 0) { 1233*9578Ssam /* no c-lists, wait a bit */ 12347502Sroot ttstart(tp); 12357502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12367502Sroot continue; 12377502Sroot } 1238*9578Ssam cp++, cc--; 1239*9578Ssam if (tp->t_flags&FLUSHO || 1240*9578Ssam tp->t_outq.c_cc > hiwat) 12417502Sroot goto ovhiwat; 1242*9578Ssam continue; 12437502Sroot } 12447502Sroot } 1245*9578Ssam /* 1246*9578Ssam * A bunch of normal characters have been found, 1247*9578Ssam * transfer them en masse to the output queue and 1248*9578Ssam * continue processing at the top of the loop. 1249*9578Ssam * If there are any further characters in this 1250*9578Ssam * <= OBUFSIZ chunk, the first should be a character 1251*9578Ssam * requiring special handling by ttyoutput. 1252*9578Ssam */ 12537502Sroot tp->t_rocount = 0; 1254*9578Ssam i = b_to_q(cp, ce, &tp->t_outq); 1255*9578Ssam ce -= i; 1256*9578Ssam tp->t_col += ce; 1257*9578Ssam cp += ce, cc -= ce, tk_nout += ce; 1258*9578Ssam if (i > 0) { 1259*9578Ssam /* out of c-lists, wait a bit */ 12607502Sroot ttstart(tp); 12617502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12627502Sroot } 1263*9578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12647502Sroot goto ovhiwat; 12657502Sroot } 12667502Sroot } 12677502Sroot ttstart(tp); 12688520Sroot return (error); 12697502Sroot 12707502Sroot ovhiwat: 1271*9578Ssam s = spl5(); 1272*9578Ssam if (cc != 0) { 1273*9578Ssam uio->uio_iov->iov_base -= cc; 1274*9578Ssam uio->uio_iov->iov_len += cc; 1275*9578Ssam uio->uio_resid += cc; 1276*9578Ssam uio->uio_offset -= cc; 1277*9578Ssam } 1278*9578Ssam /* 1279*9578Ssam * This can only occur if FLUSHO 1280*9578Ssam * is also set in t_flags. 1281*9578Ssam */ 12827502Sroot if (tp->t_outq.c_cc <= hiwat) { 1283*9578Ssam splx(s); 12847502Sroot goto loop; 12857502Sroot } 12867502Sroot ttstart(tp); 1287*9578Ssam if (tp->t_state&TS_NBIO) { 12887822Sroot if (uio->uio_resid == cnt) 12898520Sroot return (EWOULDBLOCK); 12908520Sroot return (0); 12917502Sroot } 12927502Sroot tp->t_state |= TS_ASLEEP; 12937502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 1294*9578Ssam splx(s); 12957502Sroot goto loop; 12967502Sroot } 12977502Sroot 12987502Sroot /* 12997502Sroot * Rubout one character from the rawq of tp 13007502Sroot * as cleanly as possible. 13017502Sroot */ 13027502Sroot ttyrub(c, tp) 13037625Ssam register c; 13047625Ssam register struct tty *tp; 13057502Sroot { 13067502Sroot register char *cp; 13077502Sroot register int savecol; 13087502Sroot int s; 13097502Sroot char *nextc(); 13107502Sroot 1311*9578Ssam if ((tp->t_flags&ECHO) == 0) 13127502Sroot return; 1313*9578Ssam tp->t_flags &= ~FLUSHO; 13147502Sroot c &= 0377; 1315*9578Ssam if (tp->t_flags&CRTBS) { 13167502Sroot if (tp->t_rocount == 0) { 13177502Sroot /* 13187502Sroot * Screwed by ttwrite; retype 13197502Sroot */ 13207502Sroot ttyretype(tp); 13217502Sroot return; 13227502Sroot } 1323*9578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13247502Sroot ttyrubo(tp, 2); 1325*9578Ssam else switch (partab[c&=0177]&0177) { 13267502Sroot 13277502Sroot case ORDINARY: 13287502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13297502Sroot ttyrubo(tp, 2); 13307502Sroot else 13317502Sroot ttyrubo(tp, 1); 13327502Sroot break; 13337502Sroot 13347502Sroot case VTAB: 13357502Sroot case BACKSPACE: 13367502Sroot case CONTROL: 13377502Sroot case RETURN: 1338*9578Ssam if (tp->t_flags&CTLECH) 13397502Sroot ttyrubo(tp, 2); 13407502Sroot break; 13417502Sroot 13427502Sroot case TAB: 13437502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13447502Sroot ttyretype(tp); 13457502Sroot return; 13467502Sroot } 13477502Sroot s = spl5(); 13487502Sroot savecol = tp->t_col; 1349*9578Ssam tp->t_state |= TS_CNTTB; 1350*9578Ssam tp->t_flags |= FLUSHO; 13517502Sroot tp->t_col = tp->t_rocol; 1352*9578Ssam cp = tp->t_rawq.c_cf; 1353*9578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13547502Sroot ttyecho(*cp, tp); 1355*9578Ssam tp->t_flags &= ~FLUSHO; 1356*9578Ssam tp->t_state &= ~TS_CNTTB; 13577502Sroot splx(s); 13587502Sroot /* 13597502Sroot * savecol will now be length of the tab 13607502Sroot */ 13617502Sroot savecol -= tp->t_col; 13627502Sroot tp->t_col += savecol; 13637502Sroot if (savecol > 8) 13647502Sroot savecol = 8; /* overflow screw */ 13657502Sroot while (--savecol >= 0) 13667502Sroot (void) ttyoutput('\b', tp); 13677502Sroot break; 13687502Sroot 13697502Sroot default: 13707502Sroot panic("ttyrub"); 13717502Sroot } 1372*9578Ssam } else if (tp->t_flags&PRTERA) { 1373*9578Ssam if ((tp->t_state&TS_ERASE) == 0) { 13747502Sroot (void) ttyoutput('\\', tp); 1375*9578Ssam tp->t_state |= TS_ERASE; 13767502Sroot } 13777502Sroot ttyecho(c, tp); 13787502Sroot } else 13797502Sroot ttyecho(tp->t_erase, tp); 13807502Sroot tp->t_rocount--; 13817502Sroot } 13827502Sroot 13837502Sroot /* 13847502Sroot * Crt back over cnt chars perhaps 13857502Sroot * erasing them. 13867502Sroot */ 13877502Sroot ttyrubo(tp, cnt) 13887625Ssam register struct tty *tp; 13897625Ssam int cnt; 13907502Sroot { 1391*9578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 13927502Sroot 13937502Sroot while (--cnt >= 0) 1394*9578Ssam ttyout(rubostring, tp); 13957502Sroot } 13967502Sroot 13977502Sroot /* 13987502Sroot * Reprint the rawq line. 13997502Sroot * We assume c_cc has already been checked. 14007502Sroot */ 14017502Sroot ttyretype(tp) 14027625Ssam register struct tty *tp; 14037502Sroot { 14047502Sroot register char *cp; 14057502Sroot char *nextc(); 14067502Sroot int s; 14077502Sroot 1408*9578Ssam if (tp->t_rprntc != 0377) 1409*9578Ssam ttyecho(tp->t_rprntc, tp); 14107502Sroot (void) ttyoutput('\n', tp); 14117502Sroot s = spl5(); 14127502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14137502Sroot ttyecho(*cp, tp); 14147502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14157502Sroot ttyecho(*cp, tp); 1416*9578Ssam tp->t_state &= ~TS_ERASE; 14177502Sroot splx(s); 14187502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14197502Sroot tp->t_rocol = 0; 14207502Sroot } 14217502Sroot 14227502Sroot /* 14237502Sroot * Echo a typed character to the terminal 14247502Sroot */ 14257502Sroot ttyecho(c, tp) 14267625Ssam register c; 14277625Ssam register struct tty *tp; 14287502Sroot { 14297502Sroot 1430*9578Ssam if ((tp->t_state&TS_CNTTB) == 0) 1431*9578Ssam tp->t_flags &= ~FLUSHO; 14327502Sroot if ((tp->t_flags&ECHO) == 0) 14337502Sroot return; 14347502Sroot c &= 0377; 14357502Sroot if (tp->t_flags&RAW) { 14367502Sroot (void) ttyoutput(c, tp); 14377502Sroot return; 14387502Sroot } 14397502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14407502Sroot c = '\n'; 1441*9578Ssam if (tp->t_flags&CTLECH) { 14427502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14437502Sroot (void) ttyoutput('^', tp); 14447502Sroot c &= 0177; 14457502Sroot if (c == 0177) 14467502Sroot c = '?'; 14477502Sroot else if (tp->t_flags&LCASE) 14487502Sroot c += 'a' - 1; 14497502Sroot else 14507502Sroot c += 'A' - 1; 14517502Sroot } 14527502Sroot } 14537502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14547502Sroot c += 'a' - 'A'; 1455*9578Ssam (void) ttyoutput(c&0177, tp); 14567502Sroot } 14577502Sroot 14587502Sroot /* 14597502Sroot * Is c a break char for tp? 14607502Sroot */ 14617502Sroot ttbreakc(c, tp) 14627625Ssam register c; 14637625Ssam register struct tty *tp; 14647502Sroot { 1465*9578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14667502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14677502Sroot } 14687502Sroot 14697502Sroot /* 14707502Sroot * send string cp to tp 14717502Sroot */ 14727502Sroot ttyout(cp, tp) 14737625Ssam register char *cp; 14747625Ssam register struct tty *tp; 14757502Sroot { 14767502Sroot register char c; 14777502Sroot 14787502Sroot while (c = *cp++) 14797502Sroot (void) ttyoutput(c, tp); 14807502Sroot } 14817502Sroot 14827502Sroot ttwakeup(tp) 14837502Sroot struct tty *tp; 14847502Sroot { 14857502Sroot 14867502Sroot if (tp->t_rsel) { 14877502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 14887502Sroot tp->t_state &= ~TS_RCOLL; 14897502Sroot tp->t_rsel = 0; 14907502Sroot } 14917502Sroot wakeup((caddr_t)&tp->t_rawq); 14927502Sroot } 14937502Sroot 1494*9578Ssam #ifndef vax 1495*9578Ssam scanc(size, cp, table, mask) 1496*9578Ssam register int size; 1497*9578Ssam register char *cp, table[]; 1498*9578Ssam register int mask; 14997502Sroot { 1500*9578Ssam register int i = 0; 15017502Sroot 1502*9578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 1503*9578Ssam i++; 1504*9578Ssam return (i); 15057502Sroot } 1506*9578Ssam #endif 1507