1*872Sbill /* tty.c 3.14 09/14/80 */ 239Sbill 339Sbill /* 439Sbill * general TTY subroutines 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/mx.h" 1339Sbill #include "../h/inode.h" 1439Sbill #include "../h/file.h" 1539Sbill #include "../h/reg.h" 1639Sbill #include "../h/conf.h" 1739Sbill #include "../h/buf.h" 18340Sbill #include "../h/dk.h" 1939Sbill 2039Sbill char partab[]; 2139Sbill 22146Sbill /* 23146Sbill * When running dz's using only SAE (silo alarm) on input 24146Sbill * it is necessary to call dzrint() at clock interrupt time. 25146Sbill * This is unsafe unless spl5()s in tty code are changed to 26146Sbill * spl6()s to block clock interrupts. Note that the dh driver 27146Sbill * currently in use works the same way as the dz, even though 28146Sbill * we could try to more intelligently manage its silo. 29146Sbill * Thus don't take this out if you have no dz's unless you 30146Sbill * change clock.c and dhtimer(). 31146Sbill */ 32146Sbill #define spl5 spl6 3339Sbill 3439Sbill /* 3539Sbill * Input mapping table-- if an entry is non-zero, when the 3639Sbill * corresponding character is typed preceded by "\" the escape 3739Sbill * sequence is replaced by the table value. Mostly used for 3839Sbill * upper-case only terminals. 3939Sbill */ 4039Sbill 4139Sbill char maptab[] ={ 4239Sbill 000,000,000,000,000,000,000,000, 4339Sbill 000,000,000,000,000,000,000,000, 4439Sbill 000,000,000,000,000,000,000,000, 4539Sbill 000,000,000,000,000,000,000,000, 4639Sbill 000,'|',000,000,000,000,000,'`', 4739Sbill '{','}',000,000,000,000,000,000, 4839Sbill 000,000,000,000,000,000,000,000, 4939Sbill 000,000,000,000,000,000,000,000, 5039Sbill 000,000,000,000,000,000,000,000, 5139Sbill 000,000,000,000,000,000,000,000, 5239Sbill 000,000,000,000,000,000,000,000, 5339Sbill 000,000,000,000,000,000,'~',000, 5439Sbill 000,'A','B','C','D','E','F','G', 5539Sbill 'H','I','J','K','L','M','N','O', 5639Sbill 'P','Q','R','S','T','U','V','W', 5739Sbill 'X','Y','Z',000,000,000,000,000, 5839Sbill }; 5939Sbill 6039Sbill 6139Sbill /* 6239Sbill * shorthand 6339Sbill */ 6439Sbill #define q1 tp->t_rawq 6539Sbill #define q2 tp->t_canq 6639Sbill #define q3 tp->t_outq 6739Sbill #define q4 tp->t_un.t_ctlq 6839Sbill 6939Sbill #define OBUFSIZ 100 7039Sbill 7139Sbill /* 7239Sbill * routine called on first teletype open. 7339Sbill * establishes a process group for distribution 7439Sbill * of quits and interrupts from the tty. 7539Sbill */ 7639Sbill ttyopen(dev, tp) 7739Sbill dev_t dev; 7839Sbill register struct tty *tp; 7939Sbill { 8039Sbill register struct proc *pp; 8139Sbill 8239Sbill pp = u.u_procp; 8339Sbill tp->t_dev = dev; 8439Sbill if(pp->p_pgrp == 0) { 8539Sbill u.u_ttyp = tp; 8639Sbill u.u_ttyd = dev; 87208Sbill if (tp->t_pgrp == 0) 88208Sbill tp->t_pgrp = pp->p_pid; 8939Sbill pp->p_pgrp = tp->t_pgrp; 9039Sbill } 9139Sbill tp->t_state &= ~WOPEN; 9239Sbill tp->t_state |= ISOPEN; 93384Sbill tp->t_line = 0; /* conservative */ 9439Sbill } 9539Sbill 9639Sbill /* 9739Sbill * set default control characters. 9839Sbill */ 9939Sbill ttychars(tp) 10039Sbill register struct tty *tp; 10139Sbill { 102174Sbill 10339Sbill tun.t_intrc = CINTR; 10439Sbill tun.t_quitc = CQUIT; 10539Sbill tun.t_startc = CSTART; 10639Sbill tun.t_stopc = CSTOP; 10739Sbill tun.t_eofc = CEOT; 10839Sbill tun.t_brkc = CBRK; 10939Sbill tp->t_erase = CERASE; 11039Sbill tp->t_kill = CKILL; 111174Sbill /* begin local */ 112208Sbill tlun.t_suspc = CTRL(z); 113208Sbill tlun.t_dsuspc = CTRL(y); 114174Sbill tlun.t_rprntc = CTRL(r); 115174Sbill tlun.t_flushc = CTRL(o); 116174Sbill tlun.t_werasc = CTRL(w); 117174Sbill tlun.t_lnextc = CTRL(v); 118174Sbill tlun.t_lintr = CTRL(c); 119174Sbill tlun.t_lerase = CTRL(h); 120174Sbill tlun.t_lkill = CTRL(u); 121174Sbill tp->t_local = 0; 122174Sbill tp->t_lstate = 0; 123174Sbill /* end local */ 12439Sbill } 12539Sbill 12639Sbill /* 12739Sbill * clean tp on last close 12839Sbill */ 12939Sbill ttyclose(tp) 13039Sbill register struct tty *tp; 13139Sbill { 13239Sbill 13339Sbill tp->t_pgrp = 0; 13439Sbill wflushtty(tp); 13539Sbill tp->t_state = 0; 136384Sbill tp->t_line = 0; 13739Sbill } 13839Sbill 13939Sbill /* 14039Sbill * stty/gtty writearound 14139Sbill */ 14239Sbill stty() 14339Sbill { 14439Sbill u.u_arg[2] = u.u_arg[1]; 14539Sbill u.u_arg[1] = TIOCSETP; 14639Sbill ioctl(); 14739Sbill } 14839Sbill 14939Sbill gtty() 15039Sbill { 15139Sbill u.u_arg[2] = u.u_arg[1]; 15239Sbill u.u_arg[1] = TIOCGETP; 15339Sbill ioctl(); 15439Sbill } 15539Sbill 15639Sbill /* 157121Sbill * Do nothing specific version of line 158121Sbill * discipline specific ioctl command. 159121Sbill */ 160191Sbill /*ARGSUSED*/ 161121Sbill nullioctl(tp, cmd, addr) 162121Sbill register struct tty *tp; 163121Sbill caddr_t addr; 164121Sbill { 165121Sbill 166121Sbill return (cmd); 167121Sbill } 168121Sbill 169121Sbill /* 17039Sbill * ioctl system call 17139Sbill * Check legality, execute common code, and switch out to individual 17239Sbill * device routine. 17339Sbill */ 17439Sbill ioctl() 17539Sbill { 17639Sbill register struct file *fp; 17739Sbill register struct inode *ip; 17839Sbill register struct a { 17939Sbill int fdes; 18039Sbill int cmd; 18139Sbill caddr_t cmarg; 18239Sbill } *uap; 18339Sbill register dev_t dev; 18439Sbill register fmt; 18539Sbill 18639Sbill uap = (struct a *)u.u_ap; 18739Sbill if ((fp = getf(uap->fdes)) == NULL) 18839Sbill return; 18939Sbill if (uap->cmd==FIOCLEX) { 19039Sbill u.u_pofile[uap->fdes] |= EXCLOSE; 19139Sbill return; 19239Sbill } 19339Sbill if (uap->cmd==FIONCLEX) { 19439Sbill u.u_pofile[uap->fdes] &= ~EXCLOSE; 19539Sbill return; 19639Sbill } 19739Sbill ip = fp->f_inode; 19839Sbill fmt = ip->i_mode & IFMT; 19939Sbill if (fmt != IFCHR && fmt != IFMPC) { 200174Sbill /* begin local */ 201174Sbill if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 202174Sbill off_t nread = ip->i_size - fp->f_un.f_offset; 203174Sbill 204174Sbill if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t))) 205174Sbill u.u_error = EFAULT; 206174Sbill } else 207174Sbill /* end local */ 208174Sbill u.u_error = ENOTTY; 20939Sbill return; 21039Sbill } 21139Sbill dev = ip->i_un.i_rdev; 21239Sbill u.u_r.r_val1 = 0; 21339Sbill (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); 21439Sbill } 21539Sbill 21639Sbill /* 21739Sbill * Common code for several tty ioctl commands 21839Sbill */ 21939Sbill ttioccomm(com, tp, addr, dev) 22039Sbill register struct tty *tp; 22139Sbill caddr_t addr; 22239Sbill { 22339Sbill unsigned t; 224174Sbill struct sgttyb iocb; 225191Sbill struct clist tq; 22639Sbill extern int nldisp; 227728Sbill int temp; 22839Sbill 22939Sbill switch(com) { 23039Sbill 23139Sbill /* 23239Sbill * get discipline number 23339Sbill */ 23439Sbill case TIOCGETD: 23539Sbill t = tp->t_line; 23639Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 23739Sbill u.u_error = EFAULT; 23839Sbill break; 23939Sbill 24039Sbill /* 24139Sbill * set line discipline 24239Sbill */ 24339Sbill case TIOCSETD: 24439Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 24539Sbill u.u_error = EFAULT; 24639Sbill break; 24739Sbill } 24839Sbill if (t >= nldisp) { 24939Sbill u.u_error = ENXIO; 25039Sbill break; 25139Sbill } 252174Sbill (void) spl5(); 25339Sbill if (tp->t_line) 25439Sbill (*linesw[tp->t_line].l_close)(tp); 25539Sbill if (t) 25639Sbill (*linesw[t].l_open)(dev, tp, addr); 25739Sbill if (u.u_error==0) 25839Sbill tp->t_line = t; 259174Sbill (void) spl0(); 26039Sbill break; 26139Sbill 26239Sbill /* 26339Sbill * prevent more opens on channel 26439Sbill */ 26539Sbill case TIOCEXCL: 26639Sbill tp->t_state |= XCLUDE; 26739Sbill break; 26839Sbill 26939Sbill case TIOCNXCL: 27039Sbill tp->t_state &= ~XCLUDE; 27139Sbill break; 27239Sbill 27339Sbill /* 27439Sbill * Set new parameters 27539Sbill */ 27639Sbill case TIOCSETP: 277191Sbill case TIOCSETN: 27839Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 27939Sbill u.u_error = EFAULT; 28039Sbill return(1); 28139Sbill } 282121Sbill (void) spl5(); 283174Sbill if (tp->t_line == 0) { 284174Sbill if (com == TIOCSETP) 285174Sbill wflushtty(tp); 286174Sbill while (canon(tp)>=0) 287174Sbill ; 288174Sbill } else if (tp->t_line == NTTYDISC) { 289174Sbill if (tp->t_flags&RAW || iocb.sg_flags&RAW || 290174Sbill com == TIOCSETP) 291174Sbill wflushtty(tp); 292174Sbill else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 293174Sbill if (iocb.sg_flags & CBREAK) { 294174Sbill catq(&tp->t_rawq, &tp->t_canq); 295174Sbill tq = tp->t_rawq; 296174Sbill tp->t_rawq = tp->t_canq; 297174Sbill tp->t_canq = tq; 298174Sbill } else { 299174Sbill tp->t_local |= LPENDIN; 300174Sbill if (tp->t_canq.c_cc) 301174Sbill panic("ioccom canq"); 302174Sbill if (tp->t_chan) 303174Sbill (void) sdata(tp->t_chan); 304174Sbill else 305174Sbill wakeup((caddr_t)&tp->t_rawq); 306174Sbill } 307174Sbill } 308174Sbill } 30939Sbill if ((tp->t_state&SPEEDS)==0) { 310174Sbill tp->t_ispeed = iocb.sg_ispeed; 311174Sbill tp->t_ospeed = iocb.sg_ospeed; 31239Sbill } 313174Sbill tp->t_erase = iocb.sg_erase; 314174Sbill tp->t_kill = iocb.sg_kill; 315174Sbill tp->t_flags = iocb.sg_flags; 316121Sbill (void) spl0(); 31739Sbill break; 31839Sbill 31939Sbill /* 32039Sbill * send current parameters to user 32139Sbill */ 32239Sbill case TIOCGETP: 323174Sbill iocb.sg_ispeed = tp->t_ispeed; 324174Sbill iocb.sg_ospeed = tp->t_ospeed; 325174Sbill iocb.sg_erase = tp->t_erase; 326174Sbill iocb.sg_kill = tp->t_kill; 327174Sbill iocb.sg_flags = tp->t_flags; 32839Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 32939Sbill u.u_error = EFAULT; 33039Sbill break; 33139Sbill 33239Sbill /* 33339Sbill * Hang up line on last close 33439Sbill */ 33539Sbill 33639Sbill case TIOCHPCL: 33739Sbill tp->t_state |= HUPCLS; 33839Sbill break; 33939Sbill 34039Sbill case TIOCFLUSH: 341*872Sbill flushtty(tp, FREAD|FWRITE); 34239Sbill break; 34339Sbill 34439Sbill /* 34539Sbill * ioctl entries to line discipline 34639Sbill */ 34739Sbill case DIOCSETP: 34839Sbill case DIOCGETP: 349121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 350121Sbill u.u_error = ENOTTY; 35139Sbill break; 35239Sbill 35339Sbill /* 35439Sbill * set and fetch special characters 35539Sbill */ 35639Sbill case TIOCSETC: 357174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 35839Sbill u.u_error = EFAULT; 35939Sbill break; 36039Sbill 36139Sbill case TIOCGETC: 362174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 36339Sbill u.u_error = EFAULT; 36439Sbill break; 36539Sbill 366174Sbill /* local ioctls */ 367174Sbill case TIOCSLTC: 368174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 369174Sbill u.u_error = EFAULT; 370174Sbill break; 371174Sbill 372174Sbill case TIOCGLTC: 373174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 374174Sbill u.u_error = EFAULT; 375174Sbill break; 376174Sbill 377174Sbill case FIONREAD: { 378340Sbill off_t nread; 379174Sbill 380340Sbill switch (tp->t_line) { 381340Sbill 382340Sbill case NETLDISC: 383340Sbill nread = tp->t_rec ? tp->t_inbuf : 0; 384340Sbill break; 385340Sbill 386340Sbill case NTTYDISC: 387340Sbill nread = tp->t_canq.c_cc; 388340Sbill if (tp->t_flags & (RAW|CBREAK)) 389340Sbill nread += tp->t_rawq.c_cc; 390340Sbill break; 391340Sbill 392340Sbill case 0: 393340Sbill /* do something here ... */ 394340Sbill ; 395340Sbill } 396174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 397174Sbill u.u_error = EFAULT; 398174Sbill break; 399174Sbill } 400174Sbill 401174Sbill /* 402174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 403174Sbill */ 404174Sbill case TIOCSPGRP: 405728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 406728Sbill u.u_error = EFAULT; 407174Sbill break; 408174Sbill 409174Sbill case TIOCGPGRP: 410174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 411174Sbill u.u_error = EFAULT; 412174Sbill break; 413174Sbill 414174Sbill /* 415174Sbill * Modify local mode word. 416174Sbill */ 417174Sbill case TIOCLBIS: 418728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 419728Sbill u.u_error = EFAULT; 420728Sbill else 421728Sbill tp->t_local |= temp; 422174Sbill break; 423174Sbill 424174Sbill case TIOCLBIC: 425728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 426728Sbill u.u_error = EFAULT; 427728Sbill else 428728Sbill tp->t_local &= ~temp; 429174Sbill break; 430174Sbill 431174Sbill case TIOCLSET: 432728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 433728Sbill u.u_error = EFAULT; 434728Sbill else 435728Sbill tp->t_local = temp; 436174Sbill break; 437174Sbill 438174Sbill case TIOCLGET: 439174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 440174Sbill u.u_error = EFAULT; 441174Sbill break; 442174Sbill 443213Sbill case TIOCOUTQ: 444213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 445213Sbill u.u_error = EFAULT; 446213Sbill break; 447213Sbill 448174Sbill /* end of locals */ 44939Sbill default: 45039Sbill return(0); 45139Sbill } 45239Sbill return(1); 45339Sbill } 45439Sbill 45539Sbill /* 45639Sbill * Wait for output to drain, then flush input waiting. 45739Sbill */ 45839Sbill wflushtty(tp) 45939Sbill register struct tty *tp; 46039Sbill { 46139Sbill 462121Sbill (void) spl5(); 46339Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 46439Sbill (*tp->t_oproc)(tp); 46539Sbill tp->t_state |= ASLEEP; 46639Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 46739Sbill } 468*872Sbill flushtty(tp, FREAD|FWRITE); 469121Sbill (void) spl0(); 47039Sbill } 47139Sbill 47239Sbill /* 47339Sbill * flush all TTY queues 47439Sbill */ 475*872Sbill flushtty(tp, rw) 47639Sbill register struct tty *tp; 47739Sbill { 47839Sbill register s; 47939Sbill 480340Sbill if (tp->t_line == NETLDISC) 481340Sbill return; 482121Sbill s = spl6(); 483*872Sbill if (rw & FREAD) { 484*872Sbill while (getc(&tp->t_canq) >= 0) 485*872Sbill ; 486*872Sbill wakeup((caddr_t)&tp->t_rawq); 487*872Sbill } 488*872Sbill if (rw & FWRITE) { 489*872Sbill wakeup((caddr_t)&tp->t_outq); 490*872Sbill tp->t_state &= ~TTSTOP; 491*872Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 492*872Sbill while (getc(&tp->t_outq) >= 0) 493*872Sbill ; 494*872Sbill } 495*872Sbill if (rw & FREAD) { 496*872Sbill while (getc(&tp->t_rawq) >= 0) 497*872Sbill ; 498*872Sbill tp->t_delct = 0; 499*872Sbill tp->t_rocount = 0; /* local */ 500*872Sbill tp->t_rocol = 0; 501*872Sbill tp->t_lstate = 0; 502*872Sbill } 50339Sbill splx(s); 50439Sbill } 50539Sbill 50639Sbill 50739Sbill 50839Sbill /* 50939Sbill * transfer raw input list to canonical list, 51039Sbill * doing erase-kill processing and handling escapes. 51139Sbill * It waits until a full line has been typed in cooked mode, 51239Sbill * or until any character has been typed in raw mode. 51339Sbill */ 51439Sbill canon(tp) 51539Sbill register struct tty *tp; 51639Sbill { 51739Sbill register char *bp; 51839Sbill char *bp1; 51939Sbill register int c; 52039Sbill int mc; 52139Sbill int s; 52239Sbill 52339Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 52439Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 52539Sbill return(-1); 52639Sbill } 52739Sbill s = spl0(); 52839Sbill loop: 52939Sbill bp = &canonb[2]; 53039Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 53139Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 53239Sbill if (c==0377) { 53339Sbill tp->t_delct--; 53439Sbill break; 53539Sbill } 53639Sbill if (bp[-1]!='\\') { 53739Sbill if (c==tp->t_erase) { 53839Sbill if (bp > &canonb[2]) 53939Sbill bp--; 54039Sbill continue; 54139Sbill } 54239Sbill if (c==tp->t_kill) 54339Sbill goto loop; 54439Sbill if (c==tun.t_eofc) 54539Sbill continue; 54639Sbill } else { 54739Sbill mc = maptab[c]; 54839Sbill if (c==tp->t_erase || c==tp->t_kill) 54939Sbill mc = c; 55039Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 55139Sbill if (bp[-2] != '\\') 55239Sbill c = mc; 55339Sbill bp--; 55439Sbill } 55539Sbill } 55639Sbill } 55739Sbill *bp++ = c; 55839Sbill if (bp>=canonb+CANBSIZ) 55939Sbill break; 56039Sbill } 56139Sbill bp1 = &canonb[2]; 562121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 56339Sbill 56439Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 56539Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 56639Sbill tp->t_state &= ~TBLOCK; 56739Sbill ttstart(tp); 56839Sbill } 56939Sbill tp->t_char = 0; 57039Sbill } 57139Sbill 57239Sbill splx(s); 57339Sbill return(0); 57439Sbill } 57539Sbill 57639Sbill 57739Sbill /* 57839Sbill * block transfer input handler. 57939Sbill */ 58039Sbill ttyrend(tp, pb, pe) 58139Sbill register struct tty *tp; 58239Sbill register char *pb, *pe; 58339Sbill { 58439Sbill int tandem; 58539Sbill 58639Sbill tandem = tp->t_flags&TANDEM; 58739Sbill if (tp->t_flags&RAW) { 588121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 58939Sbill if (tp->t_chan) 590121Sbill (void) sdata(tp->t_chan); else 59139Sbill wakeup((caddr_t)&tp->t_rawq); 59239Sbill } else { 59339Sbill tp->t_flags &= ~TANDEM; 59439Sbill while (pb < pe) 59539Sbill ttyinput(*pb++, tp); 59639Sbill tp->t_flags |= tandem; 59739Sbill } 59839Sbill if (tandem) 59939Sbill ttyblock(tp); 60039Sbill } 60139Sbill 60239Sbill /* 60339Sbill * Place a character on raw TTY input queue, putting in delimiters 60439Sbill * and waking up top half as needed. 60539Sbill * Also echo if required. 60639Sbill * The arguments are the character and the appropriate 60739Sbill * tty structure. 60839Sbill */ 60939Sbill ttyinput(c, tp) 61039Sbill register c; 61139Sbill register struct tty *tp; 61239Sbill { 61339Sbill register int t_flags; 61439Sbill register struct chan *cp; 61539Sbill 61639Sbill tk_nin += 1; 61739Sbill c &= 0377; 61839Sbill t_flags = tp->t_flags; 61939Sbill if (t_flags&TANDEM) 62039Sbill ttyblock(tp); 62139Sbill if ((t_flags&RAW)==0) { 62239Sbill c &= 0177; 62339Sbill if (tp->t_state&TTSTOP) { 62439Sbill if (c==tun.t_startc) { 62539Sbill tp->t_state &= ~TTSTOP; 62639Sbill ttstart(tp); 62739Sbill return; 62839Sbill } 62939Sbill if (c==tun.t_stopc) 63039Sbill return; 63139Sbill tp->t_state &= ~TTSTOP; 63239Sbill ttstart(tp); 63339Sbill } else { 63439Sbill if (c==tun.t_stopc) { 63539Sbill tp->t_state |= TTSTOP; 63639Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 63739Sbill return; 63839Sbill } 63939Sbill if (c==tun.t_startc) 64039Sbill return; 64139Sbill } 64239Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 643*872Sbill flushtty(tp, FREAD|FWRITE); 64439Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 64539Sbill if (tp->t_chan) 64639Sbill scontrol(tp->t_chan, M_SIG, c); 64739Sbill else 648174Sbill gsignal(tp->t_pgrp, c); 64939Sbill return; 65039Sbill } 65139Sbill if (c=='\r' && t_flags&CRMOD) 65239Sbill c = '\n'; 65339Sbill } 65439Sbill if (tp->t_rawq.c_cc>TTYHOG) { 655*872Sbill flushtty(tp, FREAD|FWRITE); 65639Sbill return; 65739Sbill } 65839Sbill if (t_flags&LCASE && c>='A' && c<='Z') 65939Sbill c += 'a'-'A'; 660121Sbill (void) putc(c, &tp->t_rawq); 66139Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 66239Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 66339Sbill tp->t_delct++; 66439Sbill if ((cp=tp->t_chan)!=NULL) 665121Sbill (void) sdata(cp); else 66639Sbill wakeup((caddr_t)&tp->t_rawq); 66739Sbill } 66839Sbill if (t_flags&ECHO) { 66939Sbill ttyoutput(c, tp); 67039Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 67139Sbill ttyoutput('\n', tp); 67239Sbill ttstart(tp); 67339Sbill } 67439Sbill } 67539Sbill 67639Sbill 67739Sbill /* 67839Sbill * Send stop character on input overflow. 67939Sbill */ 68039Sbill ttyblock(tp) 68139Sbill register struct tty *tp; 68239Sbill { 68339Sbill register x; 68439Sbill x = q1.c_cc + q2.c_cc; 68539Sbill if (q1.c_cc > TTYHOG) { 686*872Sbill flushtty(tp, FREAD|FWRITE); 68739Sbill tp->t_state &= ~TBLOCK; 68839Sbill } 68939Sbill if (x >= TTYHOG/2) { 69039Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 69139Sbill tp->t_state |= TBLOCK; 69239Sbill tp->t_char++; 69339Sbill ttstart(tp); 69439Sbill } 69539Sbill } 69639Sbill } 69739Sbill 69839Sbill /* 69939Sbill * put character on TTY output queue, adding delays, 70039Sbill * expanding tabs, and handling the CR/NL bit. 70139Sbill * It is called both from the top half for output, and from 70239Sbill * interrupt level for echoing. 70339Sbill * The arguments are the character and the tty structure. 70439Sbill */ 70539Sbill ttyoutput(c, tp) 70639Sbill register c; 70739Sbill register struct tty *tp; 70839Sbill { 70939Sbill register char *colp; 71039Sbill register ctype; 71139Sbill 71239Sbill /* 71339Sbill * Ignore EOT in normal mode to avoid hanging up 71439Sbill * certain terminals. 71539Sbill * In raw mode dump the char unchanged. 71639Sbill */ 71739Sbill if ((tp->t_flags&RAW)==0) { 71839Sbill c &= 0177; 71939Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 72039Sbill return; 72139Sbill } else { 722121Sbill tk_nout++; 723121Sbill (void) putc(c, &tp->t_outq); 72439Sbill return; 72539Sbill } 72639Sbill 72739Sbill /* 72839Sbill * Turn tabs to spaces as required 72939Sbill */ 73039Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 731121Sbill c = 8 - (tp->t_col & 7); 732121Sbill (void) b_to_q(" ", c, &tp->t_outq); 733121Sbill tp->t_col += c; 734121Sbill tk_nout += c; 73539Sbill return; 73639Sbill } 737121Sbill tk_nout++; 73839Sbill /* 73939Sbill * for upper-case-only terminals, 74039Sbill * generate escapes. 74139Sbill */ 74239Sbill if (tp->t_flags&LCASE) { 74339Sbill colp = "({)}!|^~'`"; 74439Sbill while(*colp++) 74539Sbill if(c == *colp++) { 74639Sbill ttyoutput('\\', tp); 74739Sbill c = colp[-2]; 74839Sbill break; 74939Sbill } 75039Sbill if ('a'<=c && c<='z') 75139Sbill c += 'A' - 'a'; 75239Sbill } 75339Sbill /* 75439Sbill * turn <nl> to <cr><lf> if desired. 75539Sbill */ 75639Sbill if (c=='\n' && tp->t_flags&CRMOD) 75739Sbill ttyoutput('\r', tp); 758121Sbill (void) putc(c, &tp->t_outq); 75939Sbill /* 76039Sbill * Calculate delays. 76139Sbill * The numbers here represent clock ticks 76239Sbill * and are not necessarily optimal for all terminals. 76339Sbill * The delays are indicated by characters above 0200. 76439Sbill * In raw mode there are no delays and the 76539Sbill * transmission path is 8 bits wide. 76639Sbill */ 76739Sbill colp = &tp->t_col; 76839Sbill ctype = partab[c]; 76939Sbill c = 0; 77039Sbill switch (ctype&077) { 77139Sbill 77239Sbill /* ordinary */ 77339Sbill case 0: 77439Sbill (*colp)++; 77539Sbill 77639Sbill /* non-printing */ 77739Sbill case 1: 77839Sbill break; 77939Sbill 78039Sbill /* backspace */ 78139Sbill case 2: 78239Sbill if (*colp) 78339Sbill (*colp)--; 78439Sbill break; 78539Sbill 78639Sbill /* newline */ 78739Sbill case 3: 78839Sbill ctype = (tp->t_flags >> 8) & 03; 78939Sbill if(ctype == 1) { /* tty 37 */ 79039Sbill if (*colp) 79139Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 79239Sbill } else 79339Sbill if(ctype == 2) { /* vt05 */ 79439Sbill c = 6; 79539Sbill } 79639Sbill *colp = 0; 79739Sbill break; 79839Sbill 79939Sbill /* tab */ 80039Sbill case 4: 80139Sbill ctype = (tp->t_flags >> 10) & 03; 80239Sbill if(ctype == 1) { /* tty 37 */ 80339Sbill c = 1 - (*colp | ~07); 80439Sbill if(c < 5) 80539Sbill c = 0; 80639Sbill } 80739Sbill *colp |= 07; 80839Sbill (*colp)++; 80939Sbill break; 81039Sbill 81139Sbill /* vertical motion */ 81239Sbill case 5: 81339Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 81439Sbill c = 0177; 81539Sbill break; 81639Sbill 81739Sbill /* carriage return */ 81839Sbill case 6: 81939Sbill ctype = (tp->t_flags >> 12) & 03; 82039Sbill if(ctype == 1) { /* tn 300 */ 82139Sbill c = 5; 82239Sbill } else if(ctype == 2) { /* ti 700 */ 82339Sbill c = 10; 82439Sbill } else if(ctype == 3) { /* concept 100 */ 82539Sbill int i; 826720Sbill if ((i = *colp) >= 0) 827720Sbill for (; i<9; i++) 828720Sbill (void) putc(0177, &tp->t_outq); 82939Sbill } 83039Sbill *colp = 0; 83139Sbill } 83239Sbill if(c) 833121Sbill (void) putc(c|0200, &tp->t_outq); 83439Sbill } 83539Sbill 83639Sbill /* 83739Sbill * Restart typewriter output following a delay 83839Sbill * timeout. 83939Sbill * The name of the routine is passed to the timeout 84039Sbill * subroutine and it is called during a clock interrupt. 84139Sbill */ 84239Sbill ttrstrt(tp) 84339Sbill register struct tty *tp; 84439Sbill { 84539Sbill 84639Sbill tp->t_state &= ~TIMEOUT; 84739Sbill ttstart(tp); 84839Sbill } 84939Sbill 85039Sbill /* 85139Sbill * Start output on the typewriter. It is used from the top half 85239Sbill * after some characters have been put on the output queue, 85339Sbill * from the interrupt routine to transmit the next 85439Sbill * character, and after a timeout has finished. 85539Sbill */ 85639Sbill ttstart(tp) 85739Sbill register struct tty *tp; 85839Sbill { 85939Sbill register s; 86039Sbill 86139Sbill s = spl5(); 86239Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 86339Sbill (*tp->t_oproc)(tp); 86439Sbill splx(s); 86539Sbill } 86639Sbill 86739Sbill /* 86839Sbill * Called from device's read routine after it has 86939Sbill * calculated the tty-structure given as argument. 87039Sbill */ 87139Sbill ttread(tp) 87239Sbill register struct tty *tp; 87339Sbill { 87439Sbill register s; 87539Sbill 87639Sbill if ((tp->t_state&CARR_ON)==0) 87739Sbill return(-1); 87839Sbill s = spl5(); 87939Sbill if (tp->t_canq.c_cc==0) 88039Sbill while (canon(tp)<0) 88139Sbill if (tp->t_chan==NULL) { 88239Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 88339Sbill } else { 88439Sbill splx(s); 88539Sbill return(0); 88639Sbill } 88739Sbill splx(s); 88839Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 88939Sbill ; 89039Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 89139Sbill } 89239Sbill 89339Sbill /* 89439Sbill * Called from the device's write routine after it has 89539Sbill * calculated the tty-structure given as argument. 89639Sbill */ 89739Sbill caddr_t 89839Sbill ttwrite(tp) 89939Sbill register struct tty *tp; 90039Sbill { 90139Sbill /* 90239Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 90339Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 90439Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 90539Sbill */ 90639Sbill register char *cp; 90739Sbill register int cc, ce; 90839Sbill register i; 90939Sbill char obuf[OBUFSIZ]; 91039Sbill 91139Sbill if ((tp->t_state&CARR_ON)==0) 91239Sbill return(NULL); 91339Sbill while (u.u_count) { 91439Sbill cc = MIN(u.u_count, OBUFSIZ); 91539Sbill cp = obuf; 91639Sbill iomove(cp, (unsigned)cc, B_WRITE); 91739Sbill if (u.u_error) 91839Sbill break; 919121Sbill (void) spl5(); 92039Sbill while (tp->t_outq.c_cc > TTHIWAT) { 92139Sbill ttstart(tp); 92239Sbill tp->t_state |= ASLEEP; 92339Sbill if (tp->t_chan) { 92439Sbill u.u_base -= cc; 92539Sbill u.u_offset -= cc; 92639Sbill u.u_count += cc; 927121Sbill (void) spl0(); 92839Sbill return((caddr_t)&tp->t_outq); 92939Sbill } 93039Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 93139Sbill } 932121Sbill (void) spl0(); 93339Sbill if (tp->t_flags&LCASE) { 93439Sbill while (cc--) 93539Sbill ttyoutput(*cp++,tp); 93639Sbill continue; 93739Sbill } 93839Sbill while (cc) { 93939Sbill if (tp->t_flags&RAW) 94039Sbill ce=cc; 94139Sbill else { 94239Sbill #ifdef VAX 94339Sbill asm(" scanc r9,(r10),_partab,$077"); 94439Sbill asm(" subl3 r0,r9,r8"); 94539Sbill #else 94639Sbill ce=0; 94739Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 94839Sbill ce++; 94939Sbill #endif 95039Sbill if (ce==0) { 95139Sbill ttyoutput(*cp++,tp); 95239Sbill cc--; 953121Sbill goto check; 95439Sbill } 95539Sbill } 95639Sbill i=b_to_q(cp,ce,&tp->t_outq); 95739Sbill ce-=i; 95839Sbill tk_nout+=ce; 95939Sbill tp->t_col+=ce; 96039Sbill cp+=ce; 96139Sbill cc-=ce; 962121Sbill check: 963121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 964121Sbill (void) spl5(); 96539Sbill while (tp->t_outq.c_cc > TTHIWAT) { 96639Sbill ttstart(tp); 96739Sbill tp->t_state |= ASLEEP; 96839Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 96939Sbill } 970121Sbill (void) spl0(); 97139Sbill } 97239Sbill } 97339Sbill } 97439Sbill ttstart(tp); 97539Sbill return(NULL); 97639Sbill } 977