1*887Sbill /* tty.c 3.15 09/16/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*887Sbill register c; 228728Sbill int temp; 22939Sbill 23039Sbill switch(com) { 23139Sbill 23239Sbill /* 23339Sbill * get discipline number 23439Sbill */ 23539Sbill case TIOCGETD: 23639Sbill t = tp->t_line; 23739Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 23839Sbill u.u_error = EFAULT; 23939Sbill break; 24039Sbill 24139Sbill /* 24239Sbill * set line discipline 24339Sbill */ 24439Sbill case TIOCSETD: 24539Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 24639Sbill u.u_error = EFAULT; 24739Sbill break; 24839Sbill } 24939Sbill if (t >= nldisp) { 25039Sbill u.u_error = ENXIO; 25139Sbill break; 25239Sbill } 253174Sbill (void) spl5(); 25439Sbill if (tp->t_line) 25539Sbill (*linesw[tp->t_line].l_close)(tp); 25639Sbill if (t) 25739Sbill (*linesw[t].l_open)(dev, tp, addr); 25839Sbill if (u.u_error==0) 25939Sbill tp->t_line = t; 260174Sbill (void) spl0(); 26139Sbill break; 26239Sbill 26339Sbill /* 26439Sbill * prevent more opens on channel 26539Sbill */ 26639Sbill case TIOCEXCL: 26739Sbill tp->t_state |= XCLUDE; 26839Sbill break; 26939Sbill 27039Sbill case TIOCNXCL: 27139Sbill tp->t_state &= ~XCLUDE; 27239Sbill break; 27339Sbill 27439Sbill /* 27539Sbill * Set new parameters 27639Sbill */ 27739Sbill case TIOCSETP: 278191Sbill case TIOCSETN: 27939Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 28039Sbill u.u_error = EFAULT; 28139Sbill return(1); 28239Sbill } 283121Sbill (void) spl5(); 284174Sbill if (tp->t_line == 0) { 285174Sbill if (com == TIOCSETP) 286174Sbill wflushtty(tp); 287174Sbill while (canon(tp)>=0) 288174Sbill ; 289174Sbill } else if (tp->t_line == NTTYDISC) { 290174Sbill if (tp->t_flags&RAW || iocb.sg_flags&RAW || 291174Sbill com == TIOCSETP) 292174Sbill wflushtty(tp); 293174Sbill else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 294174Sbill if (iocb.sg_flags & CBREAK) { 295174Sbill catq(&tp->t_rawq, &tp->t_canq); 296174Sbill tq = tp->t_rawq; 297174Sbill tp->t_rawq = tp->t_canq; 298174Sbill tp->t_canq = tq; 299174Sbill } else { 300174Sbill tp->t_local |= LPENDIN; 301174Sbill if (tp->t_canq.c_cc) 302174Sbill panic("ioccom canq"); 303174Sbill if (tp->t_chan) 304174Sbill (void) sdata(tp->t_chan); 305174Sbill else 306174Sbill wakeup((caddr_t)&tp->t_rawq); 307174Sbill } 308174Sbill } 309174Sbill } 31039Sbill if ((tp->t_state&SPEEDS)==0) { 311174Sbill tp->t_ispeed = iocb.sg_ispeed; 312174Sbill tp->t_ospeed = iocb.sg_ospeed; 31339Sbill } 314174Sbill tp->t_erase = iocb.sg_erase; 315174Sbill tp->t_kill = iocb.sg_kill; 316174Sbill tp->t_flags = iocb.sg_flags; 317121Sbill (void) spl0(); 31839Sbill break; 31939Sbill 32039Sbill /* 32139Sbill * send current parameters to user 32239Sbill */ 32339Sbill case TIOCGETP: 324174Sbill iocb.sg_ispeed = tp->t_ispeed; 325174Sbill iocb.sg_ospeed = tp->t_ospeed; 326174Sbill iocb.sg_erase = tp->t_erase; 327174Sbill iocb.sg_kill = tp->t_kill; 328174Sbill iocb.sg_flags = tp->t_flags; 32939Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 33039Sbill u.u_error = EFAULT; 33139Sbill break; 33239Sbill 33339Sbill /* 33439Sbill * Hang up line on last close 33539Sbill */ 33639Sbill 33739Sbill case TIOCHPCL: 33839Sbill tp->t_state |= HUPCLS; 33939Sbill break; 34039Sbill 34139Sbill case TIOCFLUSH: 342872Sbill flushtty(tp, FREAD|FWRITE); 34339Sbill break; 34439Sbill 34539Sbill /* 34639Sbill * ioctl entries to line discipline 34739Sbill */ 34839Sbill case DIOCSETP: 34939Sbill case DIOCGETP: 350121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 351121Sbill u.u_error = ENOTTY; 35239Sbill break; 35339Sbill 35439Sbill /* 35539Sbill * set and fetch special characters 35639Sbill */ 35739Sbill case TIOCSETC: 358174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 35939Sbill u.u_error = EFAULT; 36039Sbill break; 36139Sbill 36239Sbill case TIOCGETC: 363174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 36439Sbill u.u_error = EFAULT; 36539Sbill break; 36639Sbill 367174Sbill /* local ioctls */ 368174Sbill case TIOCSLTC: 369174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 370174Sbill u.u_error = EFAULT; 371174Sbill break; 372174Sbill 373174Sbill case TIOCGLTC: 374174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 375174Sbill u.u_error = EFAULT; 376174Sbill break; 377174Sbill 378174Sbill case FIONREAD: { 379340Sbill off_t nread; 380174Sbill 381340Sbill switch (tp->t_line) { 382340Sbill 383340Sbill case NETLDISC: 384340Sbill nread = tp->t_rec ? tp->t_inbuf : 0; 385340Sbill break; 386340Sbill 387340Sbill case NTTYDISC: 388340Sbill nread = tp->t_canq.c_cc; 389340Sbill if (tp->t_flags & (RAW|CBREAK)) 390340Sbill nread += tp->t_rawq.c_cc; 391340Sbill break; 392340Sbill 393340Sbill case 0: 394340Sbill /* do something here ... */ 395340Sbill ; 396340Sbill } 397174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 398174Sbill u.u_error = EFAULT; 399174Sbill break; 400174Sbill } 401174Sbill 402174Sbill /* 403174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 404174Sbill */ 405174Sbill case TIOCSPGRP: 406728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 407728Sbill u.u_error = EFAULT; 408174Sbill break; 409174Sbill 410174Sbill case TIOCGPGRP: 411174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 412174Sbill u.u_error = EFAULT; 413174Sbill break; 414174Sbill 415174Sbill /* 416174Sbill * Modify local mode word. 417174Sbill */ 418174Sbill case TIOCLBIS: 419728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 420728Sbill u.u_error = EFAULT; 421728Sbill else 422728Sbill tp->t_local |= temp; 423174Sbill break; 424174Sbill 425174Sbill case TIOCLBIC: 426728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 427728Sbill u.u_error = EFAULT; 428728Sbill else 429728Sbill tp->t_local &= ~temp; 430174Sbill break; 431174Sbill 432174Sbill case TIOCLSET: 433728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 434728Sbill u.u_error = EFAULT; 435728Sbill else 436728Sbill tp->t_local = temp; 437174Sbill break; 438174Sbill 439174Sbill case TIOCLGET: 440174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 441174Sbill u.u_error = EFAULT; 442174Sbill break; 443174Sbill 444213Sbill case TIOCOUTQ: 445213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 446213Sbill u.u_error = EFAULT; 447213Sbill break; 448213Sbill 449*887Sbill case TIOCSTI: 450*887Sbill c = fubyte(addr); 451*887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 452*887Sbill u.u_error = EFAULT; 453*887Sbill else 454*887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 455*887Sbill break; 456174Sbill /* end of locals */ 457*887Sbill 45839Sbill default: 45939Sbill return(0); 46039Sbill } 46139Sbill return(1); 46239Sbill } 46339Sbill 46439Sbill /* 46539Sbill * Wait for output to drain, then flush input waiting. 46639Sbill */ 46739Sbill wflushtty(tp) 46839Sbill register struct tty *tp; 46939Sbill { 47039Sbill 471121Sbill (void) spl5(); 47239Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 47339Sbill (*tp->t_oproc)(tp); 47439Sbill tp->t_state |= ASLEEP; 47539Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 47639Sbill } 477872Sbill flushtty(tp, FREAD|FWRITE); 478121Sbill (void) spl0(); 47939Sbill } 48039Sbill 48139Sbill /* 48239Sbill * flush all TTY queues 48339Sbill */ 484872Sbill flushtty(tp, rw) 48539Sbill register struct tty *tp; 48639Sbill { 48739Sbill register s; 48839Sbill 489340Sbill if (tp->t_line == NETLDISC) 490340Sbill return; 491121Sbill s = spl6(); 492872Sbill if (rw & FREAD) { 493872Sbill while (getc(&tp->t_canq) >= 0) 494872Sbill ; 495872Sbill wakeup((caddr_t)&tp->t_rawq); 496872Sbill } 497872Sbill if (rw & FWRITE) { 498872Sbill wakeup((caddr_t)&tp->t_outq); 499872Sbill tp->t_state &= ~TTSTOP; 500872Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 501872Sbill while (getc(&tp->t_outq) >= 0) 502872Sbill ; 503872Sbill } 504872Sbill if (rw & FREAD) { 505872Sbill while (getc(&tp->t_rawq) >= 0) 506872Sbill ; 507872Sbill tp->t_delct = 0; 508872Sbill tp->t_rocount = 0; /* local */ 509872Sbill tp->t_rocol = 0; 510872Sbill tp->t_lstate = 0; 511872Sbill } 51239Sbill splx(s); 51339Sbill } 51439Sbill 51539Sbill 51639Sbill 51739Sbill /* 51839Sbill * transfer raw input list to canonical list, 51939Sbill * doing erase-kill processing and handling escapes. 52039Sbill * It waits until a full line has been typed in cooked mode, 52139Sbill * or until any character has been typed in raw mode. 52239Sbill */ 52339Sbill canon(tp) 52439Sbill register struct tty *tp; 52539Sbill { 52639Sbill register char *bp; 52739Sbill char *bp1; 52839Sbill register int c; 52939Sbill int mc; 53039Sbill int s; 53139Sbill 53239Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 53339Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 53439Sbill return(-1); 53539Sbill } 53639Sbill s = spl0(); 53739Sbill loop: 53839Sbill bp = &canonb[2]; 53939Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 54039Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 54139Sbill if (c==0377) { 54239Sbill tp->t_delct--; 54339Sbill break; 54439Sbill } 54539Sbill if (bp[-1]!='\\') { 54639Sbill if (c==tp->t_erase) { 54739Sbill if (bp > &canonb[2]) 54839Sbill bp--; 54939Sbill continue; 55039Sbill } 55139Sbill if (c==tp->t_kill) 55239Sbill goto loop; 55339Sbill if (c==tun.t_eofc) 55439Sbill continue; 55539Sbill } else { 55639Sbill mc = maptab[c]; 55739Sbill if (c==tp->t_erase || c==tp->t_kill) 55839Sbill mc = c; 55939Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 56039Sbill if (bp[-2] != '\\') 56139Sbill c = mc; 56239Sbill bp--; 56339Sbill } 56439Sbill } 56539Sbill } 56639Sbill *bp++ = c; 56739Sbill if (bp>=canonb+CANBSIZ) 56839Sbill break; 56939Sbill } 57039Sbill bp1 = &canonb[2]; 571121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 57239Sbill 57339Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 57439Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 57539Sbill tp->t_state &= ~TBLOCK; 57639Sbill ttstart(tp); 57739Sbill } 57839Sbill tp->t_char = 0; 57939Sbill } 58039Sbill 58139Sbill splx(s); 58239Sbill return(0); 58339Sbill } 58439Sbill 58539Sbill 58639Sbill /* 58739Sbill * block transfer input handler. 58839Sbill */ 58939Sbill ttyrend(tp, pb, pe) 59039Sbill register struct tty *tp; 59139Sbill register char *pb, *pe; 59239Sbill { 59339Sbill int tandem; 59439Sbill 59539Sbill tandem = tp->t_flags&TANDEM; 59639Sbill if (tp->t_flags&RAW) { 597121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 59839Sbill if (tp->t_chan) 599121Sbill (void) sdata(tp->t_chan); else 60039Sbill wakeup((caddr_t)&tp->t_rawq); 60139Sbill } else { 60239Sbill tp->t_flags &= ~TANDEM; 60339Sbill while (pb < pe) 60439Sbill ttyinput(*pb++, tp); 60539Sbill tp->t_flags |= tandem; 60639Sbill } 60739Sbill if (tandem) 60839Sbill ttyblock(tp); 60939Sbill } 61039Sbill 61139Sbill /* 61239Sbill * Place a character on raw TTY input queue, putting in delimiters 61339Sbill * and waking up top half as needed. 61439Sbill * Also echo if required. 61539Sbill * The arguments are the character and the appropriate 61639Sbill * tty structure. 61739Sbill */ 61839Sbill ttyinput(c, tp) 61939Sbill register c; 62039Sbill register struct tty *tp; 62139Sbill { 62239Sbill register int t_flags; 62339Sbill register struct chan *cp; 62439Sbill 62539Sbill tk_nin += 1; 62639Sbill c &= 0377; 62739Sbill t_flags = tp->t_flags; 62839Sbill if (t_flags&TANDEM) 62939Sbill ttyblock(tp); 63039Sbill if ((t_flags&RAW)==0) { 63139Sbill c &= 0177; 63239Sbill if (tp->t_state&TTSTOP) { 63339Sbill if (c==tun.t_startc) { 63439Sbill tp->t_state &= ~TTSTOP; 63539Sbill ttstart(tp); 63639Sbill return; 63739Sbill } 63839Sbill if (c==tun.t_stopc) 63939Sbill return; 64039Sbill tp->t_state &= ~TTSTOP; 64139Sbill ttstart(tp); 64239Sbill } else { 64339Sbill if (c==tun.t_stopc) { 64439Sbill tp->t_state |= TTSTOP; 64539Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 64639Sbill return; 64739Sbill } 64839Sbill if (c==tun.t_startc) 64939Sbill return; 65039Sbill } 65139Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 652872Sbill flushtty(tp, FREAD|FWRITE); 65339Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 65439Sbill if (tp->t_chan) 65539Sbill scontrol(tp->t_chan, M_SIG, c); 65639Sbill else 657174Sbill gsignal(tp->t_pgrp, c); 65839Sbill return; 65939Sbill } 66039Sbill if (c=='\r' && t_flags&CRMOD) 66139Sbill c = '\n'; 66239Sbill } 66339Sbill if (tp->t_rawq.c_cc>TTYHOG) { 664872Sbill flushtty(tp, FREAD|FWRITE); 66539Sbill return; 66639Sbill } 66739Sbill if (t_flags&LCASE && c>='A' && c<='Z') 66839Sbill c += 'a'-'A'; 669121Sbill (void) putc(c, &tp->t_rawq); 67039Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 67139Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 67239Sbill tp->t_delct++; 67339Sbill if ((cp=tp->t_chan)!=NULL) 674121Sbill (void) sdata(cp); else 67539Sbill wakeup((caddr_t)&tp->t_rawq); 67639Sbill } 67739Sbill if (t_flags&ECHO) { 67839Sbill ttyoutput(c, tp); 67939Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 68039Sbill ttyoutput('\n', tp); 68139Sbill ttstart(tp); 68239Sbill } 68339Sbill } 68439Sbill 68539Sbill 68639Sbill /* 68739Sbill * Send stop character on input overflow. 68839Sbill */ 68939Sbill ttyblock(tp) 69039Sbill register struct tty *tp; 69139Sbill { 69239Sbill register x; 69339Sbill x = q1.c_cc + q2.c_cc; 69439Sbill if (q1.c_cc > TTYHOG) { 695872Sbill flushtty(tp, FREAD|FWRITE); 69639Sbill tp->t_state &= ~TBLOCK; 69739Sbill } 69839Sbill if (x >= TTYHOG/2) { 69939Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 70039Sbill tp->t_state |= TBLOCK; 70139Sbill tp->t_char++; 70239Sbill ttstart(tp); 70339Sbill } 70439Sbill } 70539Sbill } 70639Sbill 70739Sbill /* 70839Sbill * put character on TTY output queue, adding delays, 70939Sbill * expanding tabs, and handling the CR/NL bit. 71039Sbill * It is called both from the top half for output, and from 71139Sbill * interrupt level for echoing. 71239Sbill * The arguments are the character and the tty structure. 71339Sbill */ 71439Sbill ttyoutput(c, tp) 71539Sbill register c; 71639Sbill register struct tty *tp; 71739Sbill { 71839Sbill register char *colp; 71939Sbill register ctype; 72039Sbill 72139Sbill /* 72239Sbill * Ignore EOT in normal mode to avoid hanging up 72339Sbill * certain terminals. 72439Sbill * In raw mode dump the char unchanged. 72539Sbill */ 72639Sbill if ((tp->t_flags&RAW)==0) { 72739Sbill c &= 0177; 72839Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 72939Sbill return; 73039Sbill } else { 731121Sbill tk_nout++; 732121Sbill (void) putc(c, &tp->t_outq); 73339Sbill return; 73439Sbill } 73539Sbill 73639Sbill /* 73739Sbill * Turn tabs to spaces as required 73839Sbill */ 73939Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 740121Sbill c = 8 - (tp->t_col & 7); 741121Sbill (void) b_to_q(" ", c, &tp->t_outq); 742121Sbill tp->t_col += c; 743121Sbill tk_nout += c; 74439Sbill return; 74539Sbill } 746121Sbill tk_nout++; 74739Sbill /* 74839Sbill * for upper-case-only terminals, 74939Sbill * generate escapes. 75039Sbill */ 75139Sbill if (tp->t_flags&LCASE) { 75239Sbill colp = "({)}!|^~'`"; 75339Sbill while(*colp++) 75439Sbill if(c == *colp++) { 75539Sbill ttyoutput('\\', tp); 75639Sbill c = colp[-2]; 75739Sbill break; 75839Sbill } 75939Sbill if ('a'<=c && c<='z') 76039Sbill c += 'A' - 'a'; 76139Sbill } 76239Sbill /* 76339Sbill * turn <nl> to <cr><lf> if desired. 76439Sbill */ 76539Sbill if (c=='\n' && tp->t_flags&CRMOD) 76639Sbill ttyoutput('\r', tp); 767121Sbill (void) putc(c, &tp->t_outq); 76839Sbill /* 76939Sbill * Calculate delays. 77039Sbill * The numbers here represent clock ticks 77139Sbill * and are not necessarily optimal for all terminals. 77239Sbill * The delays are indicated by characters above 0200. 77339Sbill * In raw mode there are no delays and the 77439Sbill * transmission path is 8 bits wide. 77539Sbill */ 77639Sbill colp = &tp->t_col; 77739Sbill ctype = partab[c]; 77839Sbill c = 0; 77939Sbill switch (ctype&077) { 78039Sbill 78139Sbill /* ordinary */ 78239Sbill case 0: 78339Sbill (*colp)++; 78439Sbill 78539Sbill /* non-printing */ 78639Sbill case 1: 78739Sbill break; 78839Sbill 78939Sbill /* backspace */ 79039Sbill case 2: 79139Sbill if (*colp) 79239Sbill (*colp)--; 79339Sbill break; 79439Sbill 79539Sbill /* newline */ 79639Sbill case 3: 79739Sbill ctype = (tp->t_flags >> 8) & 03; 79839Sbill if(ctype == 1) { /* tty 37 */ 79939Sbill if (*colp) 80039Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 80139Sbill } else 80239Sbill if(ctype == 2) { /* vt05 */ 80339Sbill c = 6; 80439Sbill } 80539Sbill *colp = 0; 80639Sbill break; 80739Sbill 80839Sbill /* tab */ 80939Sbill case 4: 81039Sbill ctype = (tp->t_flags >> 10) & 03; 81139Sbill if(ctype == 1) { /* tty 37 */ 81239Sbill c = 1 - (*colp | ~07); 81339Sbill if(c < 5) 81439Sbill c = 0; 81539Sbill } 81639Sbill *colp |= 07; 81739Sbill (*colp)++; 81839Sbill break; 81939Sbill 82039Sbill /* vertical motion */ 82139Sbill case 5: 82239Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 82339Sbill c = 0177; 82439Sbill break; 82539Sbill 82639Sbill /* carriage return */ 82739Sbill case 6: 82839Sbill ctype = (tp->t_flags >> 12) & 03; 82939Sbill if(ctype == 1) { /* tn 300 */ 83039Sbill c = 5; 83139Sbill } else if(ctype == 2) { /* ti 700 */ 83239Sbill c = 10; 83339Sbill } else if(ctype == 3) { /* concept 100 */ 83439Sbill int i; 835720Sbill if ((i = *colp) >= 0) 836720Sbill for (; i<9; i++) 837720Sbill (void) putc(0177, &tp->t_outq); 83839Sbill } 83939Sbill *colp = 0; 84039Sbill } 84139Sbill if(c) 842121Sbill (void) putc(c|0200, &tp->t_outq); 84339Sbill } 84439Sbill 84539Sbill /* 84639Sbill * Restart typewriter output following a delay 84739Sbill * timeout. 84839Sbill * The name of the routine is passed to the timeout 84939Sbill * subroutine and it is called during a clock interrupt. 85039Sbill */ 85139Sbill ttrstrt(tp) 85239Sbill register struct tty *tp; 85339Sbill { 85439Sbill 85539Sbill tp->t_state &= ~TIMEOUT; 85639Sbill ttstart(tp); 85739Sbill } 85839Sbill 85939Sbill /* 86039Sbill * Start output on the typewriter. It is used from the top half 86139Sbill * after some characters have been put on the output queue, 86239Sbill * from the interrupt routine to transmit the next 86339Sbill * character, and after a timeout has finished. 86439Sbill */ 86539Sbill ttstart(tp) 86639Sbill register struct tty *tp; 86739Sbill { 86839Sbill register s; 86939Sbill 87039Sbill s = spl5(); 87139Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 87239Sbill (*tp->t_oproc)(tp); 87339Sbill splx(s); 87439Sbill } 87539Sbill 87639Sbill /* 87739Sbill * Called from device's read routine after it has 87839Sbill * calculated the tty-structure given as argument. 87939Sbill */ 88039Sbill ttread(tp) 88139Sbill register struct tty *tp; 88239Sbill { 88339Sbill register s; 88439Sbill 88539Sbill if ((tp->t_state&CARR_ON)==0) 88639Sbill return(-1); 88739Sbill s = spl5(); 88839Sbill if (tp->t_canq.c_cc==0) 88939Sbill while (canon(tp)<0) 89039Sbill if (tp->t_chan==NULL) { 89139Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 89239Sbill } else { 89339Sbill splx(s); 89439Sbill return(0); 89539Sbill } 89639Sbill splx(s); 89739Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 89839Sbill ; 89939Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 90039Sbill } 90139Sbill 90239Sbill /* 90339Sbill * Called from the device's write routine after it has 90439Sbill * calculated the tty-structure given as argument. 90539Sbill */ 90639Sbill caddr_t 90739Sbill ttwrite(tp) 90839Sbill register struct tty *tp; 90939Sbill { 91039Sbill /* 91139Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 91239Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 91339Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 91439Sbill */ 91539Sbill register char *cp; 91639Sbill register int cc, ce; 91739Sbill register i; 91839Sbill char obuf[OBUFSIZ]; 91939Sbill 92039Sbill if ((tp->t_state&CARR_ON)==0) 92139Sbill return(NULL); 92239Sbill while (u.u_count) { 92339Sbill cc = MIN(u.u_count, OBUFSIZ); 92439Sbill cp = obuf; 92539Sbill iomove(cp, (unsigned)cc, B_WRITE); 92639Sbill if (u.u_error) 92739Sbill break; 928121Sbill (void) spl5(); 92939Sbill while (tp->t_outq.c_cc > TTHIWAT) { 93039Sbill ttstart(tp); 93139Sbill tp->t_state |= ASLEEP; 93239Sbill if (tp->t_chan) { 93339Sbill u.u_base -= cc; 93439Sbill u.u_offset -= cc; 93539Sbill u.u_count += cc; 936121Sbill (void) spl0(); 93739Sbill return((caddr_t)&tp->t_outq); 93839Sbill } 93939Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 94039Sbill } 941121Sbill (void) spl0(); 94239Sbill if (tp->t_flags&LCASE) { 94339Sbill while (cc--) 94439Sbill ttyoutput(*cp++,tp); 94539Sbill continue; 94639Sbill } 94739Sbill while (cc) { 94839Sbill if (tp->t_flags&RAW) 94939Sbill ce=cc; 95039Sbill else { 95139Sbill #ifdef VAX 95239Sbill asm(" scanc r9,(r10),_partab,$077"); 95339Sbill asm(" subl3 r0,r9,r8"); 95439Sbill #else 95539Sbill ce=0; 95639Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 95739Sbill ce++; 95839Sbill #endif 95939Sbill if (ce==0) { 96039Sbill ttyoutput(*cp++,tp); 96139Sbill cc--; 962121Sbill goto check; 96339Sbill } 96439Sbill } 96539Sbill i=b_to_q(cp,ce,&tp->t_outq); 96639Sbill ce-=i; 96739Sbill tk_nout+=ce; 96839Sbill tp->t_col+=ce; 96939Sbill cp+=ce; 97039Sbill cc-=ce; 971121Sbill check: 972121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 973121Sbill (void) spl5(); 97439Sbill while (tp->t_outq.c_cc > TTHIWAT) { 97539Sbill ttstart(tp); 97639Sbill tp->t_state |= ASLEEP; 97739Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 97839Sbill } 979121Sbill (void) spl0(); 98039Sbill } 98139Sbill } 98239Sbill } 98339Sbill ttstart(tp); 98439Sbill return(NULL); 98539Sbill } 986