1*728Sbill /* tty.c 3.13 08/27/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; 227*728Sbill 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: 34139Sbill flushtty(tp); 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: 405*728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 406*728Sbill 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: 418*728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 419*728Sbill u.u_error = EFAULT; 420*728Sbill else 421*728Sbill tp->t_local |= temp; 422174Sbill break; 423174Sbill 424174Sbill case TIOCLBIC: 425*728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 426*728Sbill u.u_error = EFAULT; 427*728Sbill else 428*728Sbill tp->t_local &= ~temp; 429174Sbill break; 430174Sbill 431174Sbill case TIOCLSET: 432*728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 433*728Sbill u.u_error = EFAULT; 434*728Sbill else 435*728Sbill 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 } 46839Sbill flushtty(tp); 469121Sbill (void) spl0(); 47039Sbill } 47139Sbill 47239Sbill /* 47339Sbill * flush all TTY queues 47439Sbill */ 47539Sbill flushtty(tp) 47639Sbill register struct tty *tp; 47739Sbill { 47839Sbill register s; 47939Sbill 480340Sbill if (tp->t_line == NETLDISC) 481340Sbill return; 482121Sbill s = spl6(); 48339Sbill while (getc(&tp->t_canq) >= 0) 48439Sbill ; 48539Sbill wakeup((caddr_t)&tp->t_rawq); 48639Sbill wakeup((caddr_t)&tp->t_outq); 48739Sbill tp->t_state &= ~TTSTOP; 48839Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 48939Sbill while (getc(&tp->t_outq) >= 0) 49039Sbill ; 49139Sbill while (getc(&tp->t_rawq) >= 0) 49239Sbill ; 49339Sbill tp->t_delct = 0; 494174Sbill tp->t_rocount = 0; /* local */ 495208Sbill tp->t_lstate = 0; 49639Sbill splx(s); 49739Sbill } 49839Sbill 49939Sbill 50039Sbill 50139Sbill /* 50239Sbill * transfer raw input list to canonical list, 50339Sbill * doing erase-kill processing and handling escapes. 50439Sbill * It waits until a full line has been typed in cooked mode, 50539Sbill * or until any character has been typed in raw mode. 50639Sbill */ 50739Sbill canon(tp) 50839Sbill register struct tty *tp; 50939Sbill { 51039Sbill register char *bp; 51139Sbill char *bp1; 51239Sbill register int c; 51339Sbill int mc; 51439Sbill int s; 51539Sbill 51639Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 51739Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 51839Sbill return(-1); 51939Sbill } 52039Sbill s = spl0(); 52139Sbill loop: 52239Sbill bp = &canonb[2]; 52339Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 52439Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 52539Sbill if (c==0377) { 52639Sbill tp->t_delct--; 52739Sbill break; 52839Sbill } 52939Sbill if (bp[-1]!='\\') { 53039Sbill if (c==tp->t_erase) { 53139Sbill if (bp > &canonb[2]) 53239Sbill bp--; 53339Sbill continue; 53439Sbill } 53539Sbill if (c==tp->t_kill) 53639Sbill goto loop; 53739Sbill if (c==tun.t_eofc) 53839Sbill continue; 53939Sbill } else { 54039Sbill mc = maptab[c]; 54139Sbill if (c==tp->t_erase || c==tp->t_kill) 54239Sbill mc = c; 54339Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 54439Sbill if (bp[-2] != '\\') 54539Sbill c = mc; 54639Sbill bp--; 54739Sbill } 54839Sbill } 54939Sbill } 55039Sbill *bp++ = c; 55139Sbill if (bp>=canonb+CANBSIZ) 55239Sbill break; 55339Sbill } 55439Sbill bp1 = &canonb[2]; 555121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 55639Sbill 55739Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 55839Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 55939Sbill tp->t_state &= ~TBLOCK; 56039Sbill ttstart(tp); 56139Sbill } 56239Sbill tp->t_char = 0; 56339Sbill } 56439Sbill 56539Sbill splx(s); 56639Sbill return(0); 56739Sbill } 56839Sbill 56939Sbill 57039Sbill /* 57139Sbill * block transfer input handler. 57239Sbill */ 57339Sbill ttyrend(tp, pb, pe) 57439Sbill register struct tty *tp; 57539Sbill register char *pb, *pe; 57639Sbill { 57739Sbill int tandem; 57839Sbill 57939Sbill tandem = tp->t_flags&TANDEM; 58039Sbill if (tp->t_flags&RAW) { 581121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 58239Sbill if (tp->t_chan) 583121Sbill (void) sdata(tp->t_chan); else 58439Sbill wakeup((caddr_t)&tp->t_rawq); 58539Sbill } else { 58639Sbill tp->t_flags &= ~TANDEM; 58739Sbill while (pb < pe) 58839Sbill ttyinput(*pb++, tp); 58939Sbill tp->t_flags |= tandem; 59039Sbill } 59139Sbill if (tandem) 59239Sbill ttyblock(tp); 59339Sbill } 59439Sbill 59539Sbill /* 59639Sbill * Place a character on raw TTY input queue, putting in delimiters 59739Sbill * and waking up top half as needed. 59839Sbill * Also echo if required. 59939Sbill * The arguments are the character and the appropriate 60039Sbill * tty structure. 60139Sbill */ 60239Sbill ttyinput(c, tp) 60339Sbill register c; 60439Sbill register struct tty *tp; 60539Sbill { 60639Sbill register int t_flags; 60739Sbill register struct chan *cp; 60839Sbill 60939Sbill tk_nin += 1; 61039Sbill c &= 0377; 61139Sbill t_flags = tp->t_flags; 61239Sbill if (t_flags&TANDEM) 61339Sbill ttyblock(tp); 61439Sbill if ((t_flags&RAW)==0) { 61539Sbill c &= 0177; 61639Sbill if (tp->t_state&TTSTOP) { 61739Sbill if (c==tun.t_startc) { 61839Sbill tp->t_state &= ~TTSTOP; 61939Sbill ttstart(tp); 62039Sbill return; 62139Sbill } 62239Sbill if (c==tun.t_stopc) 62339Sbill return; 62439Sbill tp->t_state &= ~TTSTOP; 62539Sbill ttstart(tp); 62639Sbill } else { 62739Sbill if (c==tun.t_stopc) { 62839Sbill tp->t_state |= TTSTOP; 62939Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 63039Sbill return; 63139Sbill } 63239Sbill if (c==tun.t_startc) 63339Sbill return; 63439Sbill } 63539Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 63639Sbill flushtty(tp); 63739Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 63839Sbill if (tp->t_chan) 63939Sbill scontrol(tp->t_chan, M_SIG, c); 64039Sbill else 641174Sbill gsignal(tp->t_pgrp, c); 64239Sbill return; 64339Sbill } 64439Sbill if (c=='\r' && t_flags&CRMOD) 64539Sbill c = '\n'; 64639Sbill } 64739Sbill if (tp->t_rawq.c_cc>TTYHOG) { 64839Sbill flushtty(tp); 64939Sbill return; 65039Sbill } 65139Sbill if (t_flags&LCASE && c>='A' && c<='Z') 65239Sbill c += 'a'-'A'; 653121Sbill (void) putc(c, &tp->t_rawq); 65439Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 65539Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 65639Sbill tp->t_delct++; 65739Sbill if ((cp=tp->t_chan)!=NULL) 658121Sbill (void) sdata(cp); else 65939Sbill wakeup((caddr_t)&tp->t_rawq); 66039Sbill } 66139Sbill if (t_flags&ECHO) { 66239Sbill ttyoutput(c, tp); 66339Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 66439Sbill ttyoutput('\n', tp); 66539Sbill ttstart(tp); 66639Sbill } 66739Sbill } 66839Sbill 66939Sbill 67039Sbill /* 67139Sbill * Send stop character on input overflow. 67239Sbill */ 67339Sbill ttyblock(tp) 67439Sbill register struct tty *tp; 67539Sbill { 67639Sbill register x; 67739Sbill x = q1.c_cc + q2.c_cc; 67839Sbill if (q1.c_cc > TTYHOG) { 67939Sbill flushtty(tp); 68039Sbill tp->t_state &= ~TBLOCK; 68139Sbill } 68239Sbill if (x >= TTYHOG/2) { 68339Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 68439Sbill tp->t_state |= TBLOCK; 68539Sbill tp->t_char++; 68639Sbill ttstart(tp); 68739Sbill } 68839Sbill } 68939Sbill } 69039Sbill 69139Sbill /* 69239Sbill * put character on TTY output queue, adding delays, 69339Sbill * expanding tabs, and handling the CR/NL bit. 69439Sbill * It is called both from the top half for output, and from 69539Sbill * interrupt level for echoing. 69639Sbill * The arguments are the character and the tty structure. 69739Sbill */ 69839Sbill ttyoutput(c, tp) 69939Sbill register c; 70039Sbill register struct tty *tp; 70139Sbill { 70239Sbill register char *colp; 70339Sbill register ctype; 70439Sbill 70539Sbill /* 70639Sbill * Ignore EOT in normal mode to avoid hanging up 70739Sbill * certain terminals. 70839Sbill * In raw mode dump the char unchanged. 70939Sbill */ 71039Sbill if ((tp->t_flags&RAW)==0) { 71139Sbill c &= 0177; 71239Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 71339Sbill return; 71439Sbill } else { 715121Sbill tk_nout++; 716121Sbill (void) putc(c, &tp->t_outq); 71739Sbill return; 71839Sbill } 71939Sbill 72039Sbill /* 72139Sbill * Turn tabs to spaces as required 72239Sbill */ 72339Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 724121Sbill c = 8 - (tp->t_col & 7); 725121Sbill (void) b_to_q(" ", c, &tp->t_outq); 726121Sbill tp->t_col += c; 727121Sbill tk_nout += c; 72839Sbill return; 72939Sbill } 730121Sbill tk_nout++; 73139Sbill /* 73239Sbill * for upper-case-only terminals, 73339Sbill * generate escapes. 73439Sbill */ 73539Sbill if (tp->t_flags&LCASE) { 73639Sbill colp = "({)}!|^~'`"; 73739Sbill while(*colp++) 73839Sbill if(c == *colp++) { 73939Sbill ttyoutput('\\', tp); 74039Sbill c = colp[-2]; 74139Sbill break; 74239Sbill } 74339Sbill if ('a'<=c && c<='z') 74439Sbill c += 'A' - 'a'; 74539Sbill } 74639Sbill /* 74739Sbill * turn <nl> to <cr><lf> if desired. 74839Sbill */ 74939Sbill if (c=='\n' && tp->t_flags&CRMOD) 75039Sbill ttyoutput('\r', tp); 751121Sbill (void) putc(c, &tp->t_outq); 75239Sbill /* 75339Sbill * Calculate delays. 75439Sbill * The numbers here represent clock ticks 75539Sbill * and are not necessarily optimal for all terminals. 75639Sbill * The delays are indicated by characters above 0200. 75739Sbill * In raw mode there are no delays and the 75839Sbill * transmission path is 8 bits wide. 75939Sbill */ 76039Sbill colp = &tp->t_col; 76139Sbill ctype = partab[c]; 76239Sbill c = 0; 76339Sbill switch (ctype&077) { 76439Sbill 76539Sbill /* ordinary */ 76639Sbill case 0: 76739Sbill (*colp)++; 76839Sbill 76939Sbill /* non-printing */ 77039Sbill case 1: 77139Sbill break; 77239Sbill 77339Sbill /* backspace */ 77439Sbill case 2: 77539Sbill if (*colp) 77639Sbill (*colp)--; 77739Sbill break; 77839Sbill 77939Sbill /* newline */ 78039Sbill case 3: 78139Sbill ctype = (tp->t_flags >> 8) & 03; 78239Sbill if(ctype == 1) { /* tty 37 */ 78339Sbill if (*colp) 78439Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 78539Sbill } else 78639Sbill if(ctype == 2) { /* vt05 */ 78739Sbill c = 6; 78839Sbill } 78939Sbill *colp = 0; 79039Sbill break; 79139Sbill 79239Sbill /* tab */ 79339Sbill case 4: 79439Sbill ctype = (tp->t_flags >> 10) & 03; 79539Sbill if(ctype == 1) { /* tty 37 */ 79639Sbill c = 1 - (*colp | ~07); 79739Sbill if(c < 5) 79839Sbill c = 0; 79939Sbill } 80039Sbill *colp |= 07; 80139Sbill (*colp)++; 80239Sbill break; 80339Sbill 80439Sbill /* vertical motion */ 80539Sbill case 5: 80639Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 80739Sbill c = 0177; 80839Sbill break; 80939Sbill 81039Sbill /* carriage return */ 81139Sbill case 6: 81239Sbill ctype = (tp->t_flags >> 12) & 03; 81339Sbill if(ctype == 1) { /* tn 300 */ 81439Sbill c = 5; 81539Sbill } else if(ctype == 2) { /* ti 700 */ 81639Sbill c = 10; 81739Sbill } else if(ctype == 3) { /* concept 100 */ 81839Sbill int i; 819720Sbill if ((i = *colp) >= 0) 820720Sbill for (; i<9; i++) 821720Sbill (void) putc(0177, &tp->t_outq); 82239Sbill } 82339Sbill *colp = 0; 82439Sbill } 82539Sbill if(c) 826121Sbill (void) putc(c|0200, &tp->t_outq); 82739Sbill } 82839Sbill 82939Sbill /* 83039Sbill * Restart typewriter output following a delay 83139Sbill * timeout. 83239Sbill * The name of the routine is passed to the timeout 83339Sbill * subroutine and it is called during a clock interrupt. 83439Sbill */ 83539Sbill ttrstrt(tp) 83639Sbill register struct tty *tp; 83739Sbill { 83839Sbill 83939Sbill tp->t_state &= ~TIMEOUT; 84039Sbill ttstart(tp); 84139Sbill } 84239Sbill 84339Sbill /* 84439Sbill * Start output on the typewriter. It is used from the top half 84539Sbill * after some characters have been put on the output queue, 84639Sbill * from the interrupt routine to transmit the next 84739Sbill * character, and after a timeout has finished. 84839Sbill */ 84939Sbill ttstart(tp) 85039Sbill register struct tty *tp; 85139Sbill { 85239Sbill register s; 85339Sbill 85439Sbill s = spl5(); 85539Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 85639Sbill (*tp->t_oproc)(tp); 85739Sbill splx(s); 85839Sbill } 85939Sbill 86039Sbill /* 86139Sbill * Called from device's read routine after it has 86239Sbill * calculated the tty-structure given as argument. 86339Sbill */ 86439Sbill ttread(tp) 86539Sbill register struct tty *tp; 86639Sbill { 86739Sbill register s; 86839Sbill 86939Sbill if ((tp->t_state&CARR_ON)==0) 87039Sbill return(-1); 87139Sbill s = spl5(); 87239Sbill if (tp->t_canq.c_cc==0) 87339Sbill while (canon(tp)<0) 87439Sbill if (tp->t_chan==NULL) { 87539Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 87639Sbill } else { 87739Sbill splx(s); 87839Sbill return(0); 87939Sbill } 88039Sbill splx(s); 88139Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 88239Sbill ; 88339Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 88439Sbill } 88539Sbill 88639Sbill /* 88739Sbill * Called from the device's write routine after it has 88839Sbill * calculated the tty-structure given as argument. 88939Sbill */ 89039Sbill caddr_t 89139Sbill ttwrite(tp) 89239Sbill register struct tty *tp; 89339Sbill { 89439Sbill /* 89539Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 89639Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 89739Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 89839Sbill */ 89939Sbill register char *cp; 90039Sbill register int cc, ce; 90139Sbill register i; 90239Sbill char obuf[OBUFSIZ]; 90339Sbill 90439Sbill if ((tp->t_state&CARR_ON)==0) 90539Sbill return(NULL); 90639Sbill while (u.u_count) { 90739Sbill cc = MIN(u.u_count, OBUFSIZ); 90839Sbill cp = obuf; 90939Sbill iomove(cp, (unsigned)cc, B_WRITE); 91039Sbill if (u.u_error) 91139Sbill break; 912121Sbill (void) spl5(); 91339Sbill while (tp->t_outq.c_cc > TTHIWAT) { 91439Sbill ttstart(tp); 91539Sbill tp->t_state |= ASLEEP; 91639Sbill if (tp->t_chan) { 91739Sbill u.u_base -= cc; 91839Sbill u.u_offset -= cc; 91939Sbill u.u_count += cc; 920121Sbill (void) spl0(); 92139Sbill return((caddr_t)&tp->t_outq); 92239Sbill } 92339Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 92439Sbill } 925121Sbill (void) spl0(); 92639Sbill if (tp->t_flags&LCASE) { 92739Sbill while (cc--) 92839Sbill ttyoutput(*cp++,tp); 92939Sbill continue; 93039Sbill } 93139Sbill while (cc) { 93239Sbill if (tp->t_flags&RAW) 93339Sbill ce=cc; 93439Sbill else { 93539Sbill #ifdef VAX 93639Sbill asm(" scanc r9,(r10),_partab,$077"); 93739Sbill asm(" subl3 r0,r9,r8"); 93839Sbill #else 93939Sbill ce=0; 94039Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 94139Sbill ce++; 94239Sbill #endif 94339Sbill if (ce==0) { 94439Sbill ttyoutput(*cp++,tp); 94539Sbill cc--; 946121Sbill goto check; 94739Sbill } 94839Sbill } 94939Sbill i=b_to_q(cp,ce,&tp->t_outq); 95039Sbill ce-=i; 95139Sbill tk_nout+=ce; 95239Sbill tp->t_col+=ce; 95339Sbill cp+=ce; 95439Sbill cc-=ce; 955121Sbill check: 956121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 957121Sbill (void) spl5(); 95839Sbill while (tp->t_outq.c_cc > TTHIWAT) { 95939Sbill ttstart(tp); 96039Sbill tp->t_state |= ASLEEP; 96139Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 96239Sbill } 963121Sbill (void) spl0(); 96439Sbill } 96539Sbill } 96639Sbill } 96739Sbill ttstart(tp); 96839Sbill return(NULL); 96939Sbill } 970