1*213Sbill /* tty.c 3.7 10/14/12 */ 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" 1839Sbill 1939Sbill char partab[]; 2039Sbill 21146Sbill /* 22146Sbill * When running dz's using only SAE (silo alarm) on input 23146Sbill * it is necessary to call dzrint() at clock interrupt time. 24146Sbill * This is unsafe unless spl5()s in tty code are changed to 25146Sbill * spl6()s to block clock interrupts. Note that the dh driver 26146Sbill * currently in use works the same way as the dz, even though 27146Sbill * we could try to more intelligently manage its silo. 28146Sbill * Thus don't take this out if you have no dz's unless you 29146Sbill * change clock.c and dhtimer(). 30146Sbill */ 31146Sbill #define spl5 spl6 3239Sbill 3339Sbill /* 3439Sbill * Input mapping table-- if an entry is non-zero, when the 3539Sbill * corresponding character is typed preceded by "\" the escape 3639Sbill * sequence is replaced by the table value. Mostly used for 3739Sbill * upper-case only terminals. 3839Sbill */ 3939Sbill 4039Sbill char maptab[] ={ 4139Sbill 000,000,000,000,000,000,000,000, 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,'`', 4639Sbill '{','}',000,000,000,000,000,000, 4739Sbill 000,000,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, 5339Sbill 000,'A','B','C','D','E','F','G', 5439Sbill 'H','I','J','K','L','M','N','O', 5539Sbill 'P','Q','R','S','T','U','V','W', 5639Sbill 'X','Y','Z',000,000,000,000,000, 5739Sbill }; 5839Sbill 5939Sbill 6039Sbill /* 6139Sbill * shorthand 6239Sbill */ 6339Sbill #define q1 tp->t_rawq 6439Sbill #define q2 tp->t_canq 6539Sbill #define q3 tp->t_outq 6639Sbill #define q4 tp->t_un.t_ctlq 6739Sbill 6839Sbill #define OBUFSIZ 100 6939Sbill 7039Sbill /* 7139Sbill * routine called on first teletype open. 7239Sbill * establishes a process group for distribution 7339Sbill * of quits and interrupts from the tty. 7439Sbill */ 7539Sbill ttyopen(dev, tp) 7639Sbill dev_t dev; 7739Sbill register struct tty *tp; 7839Sbill { 7939Sbill register struct proc *pp; 8039Sbill 8139Sbill pp = u.u_procp; 8239Sbill tp->t_dev = dev; 8339Sbill if(pp->p_pgrp == 0) { 8439Sbill u.u_ttyp = tp; 8539Sbill u.u_ttyd = dev; 86208Sbill if (tp->t_pgrp == 0) 87208Sbill tp->t_pgrp = pp->p_pid; 8839Sbill pp->p_pgrp = tp->t_pgrp; 8939Sbill } 9039Sbill tp->t_state &= ~WOPEN; 9139Sbill tp->t_state |= ISOPEN; 92174Sbill tp->t_line = 0; /* conservative */ 9339Sbill } 9439Sbill 9539Sbill /* 9639Sbill * set default control characters. 9739Sbill */ 9839Sbill ttychars(tp) 9939Sbill register struct tty *tp; 10039Sbill { 101174Sbill 10239Sbill tun.t_intrc = CINTR; 10339Sbill tun.t_quitc = CQUIT; 10439Sbill tun.t_startc = CSTART; 10539Sbill tun.t_stopc = CSTOP; 10639Sbill tun.t_eofc = CEOT; 10739Sbill tun.t_brkc = CBRK; 10839Sbill tp->t_erase = CERASE; 10939Sbill tp->t_kill = CKILL; 110174Sbill /* begin local */ 111208Sbill tlun.t_suspc = CTRL(z); 112208Sbill tlun.t_dsuspc = CTRL(y); 113174Sbill tlun.t_rprntc = CTRL(r); 114174Sbill tlun.t_flushc = CTRL(o); 115174Sbill tlun.t_werasc = CTRL(w); 116174Sbill tlun.t_lnextc = CTRL(v); 117174Sbill tlun.t_lintr = CTRL(c); 118174Sbill tlun.t_lerase = CTRL(h); 119174Sbill tlun.t_lkill = CTRL(u); 120174Sbill tp->t_local = 0; 121174Sbill tp->t_lstate = 0; 122174Sbill /* end local */ 12339Sbill } 12439Sbill 12539Sbill /* 12639Sbill * clean tp on last close 12739Sbill */ 12839Sbill ttyclose(tp) 12939Sbill register struct tty *tp; 13039Sbill { 13139Sbill 13239Sbill tp->t_pgrp = 0; 13339Sbill wflushtty(tp); 13439Sbill tp->t_state = 0; 135174Sbill tp->t_line = 0; 13639Sbill } 13739Sbill 13839Sbill /* 13939Sbill * stty/gtty writearound 14039Sbill */ 14139Sbill stty() 14239Sbill { 14339Sbill u.u_arg[2] = u.u_arg[1]; 14439Sbill u.u_arg[1] = TIOCSETP; 14539Sbill ioctl(); 14639Sbill } 14739Sbill 14839Sbill gtty() 14939Sbill { 15039Sbill u.u_arg[2] = u.u_arg[1]; 15139Sbill u.u_arg[1] = TIOCGETP; 15239Sbill ioctl(); 15339Sbill } 15439Sbill 15539Sbill /* 156121Sbill * Do nothing specific version of line 157121Sbill * discipline specific ioctl command. 158121Sbill */ 159191Sbill /*ARGSUSED*/ 160121Sbill nullioctl(tp, cmd, addr) 161121Sbill register struct tty *tp; 162121Sbill caddr_t addr; 163121Sbill { 164121Sbill 165121Sbill return (cmd); 166121Sbill } 167121Sbill 168121Sbill /* 16939Sbill * ioctl system call 17039Sbill * Check legality, execute common code, and switch out to individual 17139Sbill * device routine. 17239Sbill */ 17339Sbill ioctl() 17439Sbill { 17539Sbill register struct file *fp; 17639Sbill register struct inode *ip; 17739Sbill register struct a { 17839Sbill int fdes; 17939Sbill int cmd; 18039Sbill caddr_t cmarg; 18139Sbill } *uap; 18239Sbill register dev_t dev; 18339Sbill register fmt; 18439Sbill 18539Sbill uap = (struct a *)u.u_ap; 18639Sbill if ((fp = getf(uap->fdes)) == NULL) 18739Sbill return; 18839Sbill if (uap->cmd==FIOCLEX) { 18939Sbill u.u_pofile[uap->fdes] |= EXCLOSE; 19039Sbill return; 19139Sbill } 19239Sbill if (uap->cmd==FIONCLEX) { 19339Sbill u.u_pofile[uap->fdes] &= ~EXCLOSE; 19439Sbill return; 19539Sbill } 19639Sbill ip = fp->f_inode; 19739Sbill fmt = ip->i_mode & IFMT; 19839Sbill if (fmt != IFCHR && fmt != IFMPC) { 199174Sbill /* begin local */ 200174Sbill if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 201174Sbill off_t nread = ip->i_size - fp->f_un.f_offset; 202174Sbill 203174Sbill if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t))) 204174Sbill u.u_error = EFAULT; 205174Sbill } else 206174Sbill /* end local */ 207174Sbill u.u_error = ENOTTY; 20839Sbill return; 20939Sbill } 21039Sbill dev = ip->i_un.i_rdev; 21139Sbill u.u_r.r_val1 = 0; 21239Sbill (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); 21339Sbill } 21439Sbill 21539Sbill /* 21639Sbill * Common code for several tty ioctl commands 21739Sbill */ 21839Sbill ttioccomm(com, tp, addr, dev) 21939Sbill register struct tty *tp; 22039Sbill caddr_t addr; 22139Sbill { 22239Sbill unsigned t; 223174Sbill struct sgttyb iocb; 224191Sbill struct clist tq; 22539Sbill extern int nldisp; 22639Sbill 22739Sbill switch(com) { 22839Sbill 22939Sbill /* 23039Sbill * get discipline number 23139Sbill */ 23239Sbill case TIOCGETD: 23339Sbill t = tp->t_line; 23439Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 23539Sbill u.u_error = EFAULT; 23639Sbill break; 23739Sbill 23839Sbill /* 23939Sbill * set line discipline 24039Sbill */ 24139Sbill case TIOCSETD: 24239Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 24339Sbill u.u_error = EFAULT; 24439Sbill break; 24539Sbill } 24639Sbill if (t >= nldisp) { 24739Sbill u.u_error = ENXIO; 24839Sbill break; 24939Sbill } 250174Sbill (void) spl5(); 25139Sbill if (tp->t_line) 25239Sbill (*linesw[tp->t_line].l_close)(tp); 25339Sbill if (t) 25439Sbill (*linesw[t].l_open)(dev, tp, addr); 25539Sbill if (u.u_error==0) 25639Sbill tp->t_line = t; 257174Sbill (void) spl0(); 25839Sbill break; 25939Sbill 26039Sbill /* 26139Sbill * prevent more opens on channel 26239Sbill */ 26339Sbill case TIOCEXCL: 26439Sbill tp->t_state |= XCLUDE; 26539Sbill break; 26639Sbill 26739Sbill case TIOCNXCL: 26839Sbill tp->t_state &= ~XCLUDE; 26939Sbill break; 27039Sbill 27139Sbill /* 27239Sbill * Set new parameters 27339Sbill */ 27439Sbill case TIOCSETP: 275191Sbill case TIOCSETN: 27639Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 27739Sbill u.u_error = EFAULT; 27839Sbill return(1); 27939Sbill } 280121Sbill (void) spl5(); 281174Sbill if (tp->t_line == 0) { 282174Sbill if (com == TIOCSETP) 283174Sbill wflushtty(tp); 284174Sbill while (canon(tp)>=0) 285174Sbill ; 286174Sbill } else if (tp->t_line == NTTYDISC) { 287174Sbill if (tp->t_flags&RAW || iocb.sg_flags&RAW || 288174Sbill com == TIOCSETP) 289174Sbill wflushtty(tp); 290174Sbill else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 291174Sbill if (iocb.sg_flags & CBREAK) { 292174Sbill catq(&tp->t_rawq, &tp->t_canq); 293174Sbill tq = tp->t_rawq; 294174Sbill tp->t_rawq = tp->t_canq; 295174Sbill tp->t_canq = tq; 296174Sbill } else { 297174Sbill tp->t_local |= LPENDIN; 298174Sbill if (tp->t_canq.c_cc) 299174Sbill panic("ioccom canq"); 300174Sbill if (tp->t_chan) 301174Sbill (void) sdata(tp->t_chan); 302174Sbill else 303174Sbill wakeup((caddr_t)&tp->t_rawq); 304174Sbill } 305174Sbill } 306174Sbill } 30739Sbill if ((tp->t_state&SPEEDS)==0) { 308174Sbill tp->t_ispeed = iocb.sg_ispeed; 309174Sbill tp->t_ospeed = iocb.sg_ospeed; 31039Sbill } 311174Sbill tp->t_erase = iocb.sg_erase; 312174Sbill tp->t_kill = iocb.sg_kill; 313174Sbill tp->t_flags = iocb.sg_flags; 314121Sbill (void) spl0(); 31539Sbill break; 31639Sbill 31739Sbill /* 31839Sbill * send current parameters to user 31939Sbill */ 32039Sbill case TIOCGETP: 321174Sbill iocb.sg_ispeed = tp->t_ispeed; 322174Sbill iocb.sg_ospeed = tp->t_ospeed; 323174Sbill iocb.sg_erase = tp->t_erase; 324174Sbill iocb.sg_kill = tp->t_kill; 325174Sbill iocb.sg_flags = tp->t_flags; 32639Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 32739Sbill u.u_error = EFAULT; 32839Sbill break; 32939Sbill 33039Sbill /* 33139Sbill * Hang up line on last close 33239Sbill */ 33339Sbill 33439Sbill case TIOCHPCL: 33539Sbill tp->t_state |= HUPCLS; 33639Sbill break; 33739Sbill 33839Sbill case TIOCFLUSH: 33939Sbill flushtty(tp); 34039Sbill break; 34139Sbill 34239Sbill /* 34339Sbill * ioctl entries to line discipline 34439Sbill */ 34539Sbill case DIOCSETP: 34639Sbill case DIOCGETP: 347121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 348121Sbill u.u_error = ENOTTY; 34939Sbill break; 35039Sbill 35139Sbill /* 35239Sbill * set and fetch special characters 35339Sbill */ 35439Sbill case TIOCSETC: 355174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 35639Sbill u.u_error = EFAULT; 35739Sbill break; 35839Sbill 35939Sbill case TIOCGETC: 360174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 36139Sbill u.u_error = EFAULT; 36239Sbill break; 36339Sbill 364174Sbill /* local ioctls */ 365174Sbill case TIOCSLTC: 366174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 367174Sbill u.u_error = EFAULT; 368174Sbill break; 369174Sbill 370174Sbill case TIOCGLTC: 371174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 372174Sbill u.u_error = EFAULT; 373174Sbill break; 374174Sbill 375174Sbill case FIONREAD: { 376174Sbill off_t nread = tp->t_canq.c_cc; 377174Sbill 378174Sbill if (tp->t_flags & (RAW|CBREAK)) 379174Sbill nread += tp->t_rawq.c_cc; 380174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 381174Sbill u.u_error = EFAULT; 382174Sbill break; 383174Sbill } 384174Sbill 385174Sbill /* 386174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 387174Sbill */ 388174Sbill case TIOCSPGRP: 389174Sbill tp->t_pgrp = (int)addr; 390174Sbill break; 391174Sbill 392174Sbill case TIOCGPGRP: 393174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 394174Sbill u.u_error = EFAULT; 395174Sbill break; 396174Sbill 397174Sbill /* 398174Sbill * Modify local mode word. 399174Sbill */ 400174Sbill case TIOCLBIS: 401174Sbill tp->t_local |= (int)addr; 402174Sbill break; 403174Sbill 404174Sbill case TIOCLBIC: 405174Sbill tp->t_local &= ~(int)addr; 406174Sbill break; 407174Sbill 408174Sbill case TIOCLSET: 409174Sbill tp->t_local = (int)addr; 410174Sbill break; 411174Sbill 412174Sbill case TIOCLGET: 413174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 414174Sbill u.u_error = EFAULT; 415174Sbill break; 416174Sbill 417*213Sbill case TIOCOUTQ: 418*213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 419*213Sbill u.u_error = EFAULT; 420*213Sbill break; 421*213Sbill 422174Sbill /* end of locals */ 42339Sbill default: 42439Sbill return(0); 42539Sbill } 42639Sbill return(1); 42739Sbill } 42839Sbill 42939Sbill /* 43039Sbill * Wait for output to drain, then flush input waiting. 43139Sbill */ 43239Sbill wflushtty(tp) 43339Sbill register struct tty *tp; 43439Sbill { 43539Sbill 436121Sbill (void) spl5(); 43739Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 43839Sbill (*tp->t_oproc)(tp); 43939Sbill tp->t_state |= ASLEEP; 44039Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 44139Sbill } 44239Sbill flushtty(tp); 443121Sbill (void) spl0(); 44439Sbill } 44539Sbill 44639Sbill /* 44739Sbill * flush all TTY queues 44839Sbill */ 44939Sbill flushtty(tp) 45039Sbill register struct tty *tp; 45139Sbill { 45239Sbill register s; 45339Sbill 454121Sbill s = spl6(); 45539Sbill while (getc(&tp->t_canq) >= 0) 45639Sbill ; 45739Sbill wakeup((caddr_t)&tp->t_rawq); 45839Sbill wakeup((caddr_t)&tp->t_outq); 45939Sbill tp->t_state &= ~TTSTOP; 46039Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 46139Sbill while (getc(&tp->t_outq) >= 0) 46239Sbill ; 46339Sbill while (getc(&tp->t_rawq) >= 0) 46439Sbill ; 46539Sbill tp->t_delct = 0; 466174Sbill tp->t_rocount = 0; /* local */ 467208Sbill tp->t_lstate = 0; 46839Sbill splx(s); 46939Sbill } 47039Sbill 47139Sbill 47239Sbill 47339Sbill /* 47439Sbill * transfer raw input list to canonical list, 47539Sbill * doing erase-kill processing and handling escapes. 47639Sbill * It waits until a full line has been typed in cooked mode, 47739Sbill * or until any character has been typed in raw mode. 47839Sbill */ 47939Sbill canon(tp) 48039Sbill register struct tty *tp; 48139Sbill { 48239Sbill register char *bp; 48339Sbill char *bp1; 48439Sbill register int c; 48539Sbill int mc; 48639Sbill int s; 48739Sbill 48839Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 48939Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 49039Sbill return(-1); 49139Sbill } 49239Sbill s = spl0(); 49339Sbill loop: 49439Sbill bp = &canonb[2]; 49539Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 49639Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 49739Sbill if (c==0377) { 49839Sbill tp->t_delct--; 49939Sbill break; 50039Sbill } 50139Sbill if (bp[-1]!='\\') { 50239Sbill if (c==tp->t_erase) { 50339Sbill if (bp > &canonb[2]) 50439Sbill bp--; 50539Sbill continue; 50639Sbill } 50739Sbill if (c==tp->t_kill) 50839Sbill goto loop; 50939Sbill if (c==tun.t_eofc) 51039Sbill continue; 51139Sbill } else { 51239Sbill mc = maptab[c]; 51339Sbill if (c==tp->t_erase || c==tp->t_kill) 51439Sbill mc = c; 51539Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 51639Sbill if (bp[-2] != '\\') 51739Sbill c = mc; 51839Sbill bp--; 51939Sbill } 52039Sbill } 52139Sbill } 52239Sbill *bp++ = c; 52339Sbill if (bp>=canonb+CANBSIZ) 52439Sbill break; 52539Sbill } 52639Sbill bp1 = &canonb[2]; 527121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 52839Sbill 52939Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 53039Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 53139Sbill tp->t_state &= ~TBLOCK; 53239Sbill ttstart(tp); 53339Sbill } 53439Sbill tp->t_char = 0; 53539Sbill } 53639Sbill 53739Sbill splx(s); 53839Sbill return(0); 53939Sbill } 54039Sbill 54139Sbill 54239Sbill /* 54339Sbill * block transfer input handler. 54439Sbill */ 54539Sbill ttyrend(tp, pb, pe) 54639Sbill register struct tty *tp; 54739Sbill register char *pb, *pe; 54839Sbill { 54939Sbill int tandem; 55039Sbill 55139Sbill tandem = tp->t_flags&TANDEM; 55239Sbill if (tp->t_flags&RAW) { 553121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 55439Sbill if (tp->t_chan) 555121Sbill (void) sdata(tp->t_chan); else 55639Sbill wakeup((caddr_t)&tp->t_rawq); 55739Sbill } else { 55839Sbill tp->t_flags &= ~TANDEM; 55939Sbill while (pb < pe) 56039Sbill ttyinput(*pb++, tp); 56139Sbill tp->t_flags |= tandem; 56239Sbill } 56339Sbill if (tandem) 56439Sbill ttyblock(tp); 56539Sbill } 56639Sbill 56739Sbill /* 56839Sbill * Place a character on raw TTY input queue, putting in delimiters 56939Sbill * and waking up top half as needed. 57039Sbill * Also echo if required. 57139Sbill * The arguments are the character and the appropriate 57239Sbill * tty structure. 57339Sbill */ 57439Sbill ttyinput(c, tp) 57539Sbill register c; 57639Sbill register struct tty *tp; 57739Sbill { 57839Sbill register int t_flags; 57939Sbill register struct chan *cp; 58039Sbill 58139Sbill tk_nin += 1; 58239Sbill c &= 0377; 58339Sbill t_flags = tp->t_flags; 58439Sbill if (t_flags&TANDEM) 58539Sbill ttyblock(tp); 58639Sbill if ((t_flags&RAW)==0) { 58739Sbill c &= 0177; 58839Sbill if (tp->t_state&TTSTOP) { 58939Sbill if (c==tun.t_startc) { 59039Sbill tp->t_state &= ~TTSTOP; 59139Sbill ttstart(tp); 59239Sbill return; 59339Sbill } 59439Sbill if (c==tun.t_stopc) 59539Sbill return; 59639Sbill tp->t_state &= ~TTSTOP; 59739Sbill ttstart(tp); 59839Sbill } else { 59939Sbill if (c==tun.t_stopc) { 60039Sbill tp->t_state |= TTSTOP; 60139Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 60239Sbill return; 60339Sbill } 60439Sbill if (c==tun.t_startc) 60539Sbill return; 60639Sbill } 60739Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 60839Sbill flushtty(tp); 60939Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 61039Sbill if (tp->t_chan) 61139Sbill scontrol(tp->t_chan, M_SIG, c); 61239Sbill else 613174Sbill gsignal(tp->t_pgrp, c); 61439Sbill return; 61539Sbill } 61639Sbill if (c=='\r' && t_flags&CRMOD) 61739Sbill c = '\n'; 61839Sbill } 61939Sbill if (tp->t_rawq.c_cc>TTYHOG) { 62039Sbill flushtty(tp); 62139Sbill return; 62239Sbill } 62339Sbill if (t_flags&LCASE && c>='A' && c<='Z') 62439Sbill c += 'a'-'A'; 625121Sbill (void) putc(c, &tp->t_rawq); 62639Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 62739Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 62839Sbill tp->t_delct++; 62939Sbill if ((cp=tp->t_chan)!=NULL) 630121Sbill (void) sdata(cp); else 63139Sbill wakeup((caddr_t)&tp->t_rawq); 63239Sbill } 63339Sbill if (t_flags&ECHO) { 63439Sbill ttyoutput(c, tp); 63539Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 63639Sbill ttyoutput('\n', tp); 63739Sbill ttstart(tp); 63839Sbill } 63939Sbill } 64039Sbill 64139Sbill 64239Sbill /* 64339Sbill * Send stop character on input overflow. 64439Sbill */ 64539Sbill ttyblock(tp) 64639Sbill register struct tty *tp; 64739Sbill { 64839Sbill register x; 64939Sbill x = q1.c_cc + q2.c_cc; 65039Sbill if (q1.c_cc > TTYHOG) { 65139Sbill flushtty(tp); 65239Sbill tp->t_state &= ~TBLOCK; 65339Sbill } 65439Sbill if (x >= TTYHOG/2) { 65539Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 65639Sbill tp->t_state |= TBLOCK; 65739Sbill tp->t_char++; 65839Sbill ttstart(tp); 65939Sbill } 66039Sbill } 66139Sbill } 66239Sbill 66339Sbill /* 66439Sbill * put character on TTY output queue, adding delays, 66539Sbill * expanding tabs, and handling the CR/NL bit. 66639Sbill * It is called both from the top half for output, and from 66739Sbill * interrupt level for echoing. 66839Sbill * The arguments are the character and the tty structure. 66939Sbill */ 67039Sbill ttyoutput(c, tp) 67139Sbill register c; 67239Sbill register struct tty *tp; 67339Sbill { 67439Sbill register char *colp; 67539Sbill register ctype; 67639Sbill 67739Sbill /* 67839Sbill * Ignore EOT in normal mode to avoid hanging up 67939Sbill * certain terminals. 68039Sbill * In raw mode dump the char unchanged. 68139Sbill */ 68239Sbill if ((tp->t_flags&RAW)==0) { 68339Sbill c &= 0177; 68439Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 68539Sbill return; 68639Sbill } else { 687121Sbill tk_nout++; 688121Sbill (void) putc(c, &tp->t_outq); 68939Sbill return; 69039Sbill } 69139Sbill 69239Sbill /* 69339Sbill * Turn tabs to spaces as required 69439Sbill */ 69539Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 696121Sbill c = 8 - (tp->t_col & 7); 697121Sbill (void) b_to_q(" ", c, &tp->t_outq); 698121Sbill tp->t_col += c; 699121Sbill tk_nout += c; 70039Sbill return; 70139Sbill } 702121Sbill tk_nout++; 70339Sbill /* 70439Sbill * for upper-case-only terminals, 70539Sbill * generate escapes. 70639Sbill */ 70739Sbill if (tp->t_flags&LCASE) { 70839Sbill colp = "({)}!|^~'`"; 70939Sbill while(*colp++) 71039Sbill if(c == *colp++) { 71139Sbill ttyoutput('\\', tp); 71239Sbill c = colp[-2]; 71339Sbill break; 71439Sbill } 71539Sbill if ('a'<=c && c<='z') 71639Sbill c += 'A' - 'a'; 71739Sbill } 71839Sbill /* 71939Sbill * turn <nl> to <cr><lf> if desired. 72039Sbill */ 72139Sbill if (c=='\n' && tp->t_flags&CRMOD) 72239Sbill ttyoutput('\r', tp); 723121Sbill (void) putc(c, &tp->t_outq); 72439Sbill /* 72539Sbill * Calculate delays. 72639Sbill * The numbers here represent clock ticks 72739Sbill * and are not necessarily optimal for all terminals. 72839Sbill * The delays are indicated by characters above 0200. 72939Sbill * In raw mode there are no delays and the 73039Sbill * transmission path is 8 bits wide. 73139Sbill */ 73239Sbill colp = &tp->t_col; 73339Sbill ctype = partab[c]; 73439Sbill c = 0; 73539Sbill switch (ctype&077) { 73639Sbill 73739Sbill /* ordinary */ 73839Sbill case 0: 73939Sbill (*colp)++; 74039Sbill 74139Sbill /* non-printing */ 74239Sbill case 1: 74339Sbill break; 74439Sbill 74539Sbill /* backspace */ 74639Sbill case 2: 74739Sbill if (*colp) 74839Sbill (*colp)--; 74939Sbill break; 75039Sbill 75139Sbill /* newline */ 75239Sbill case 3: 75339Sbill ctype = (tp->t_flags >> 8) & 03; 75439Sbill if(ctype == 1) { /* tty 37 */ 75539Sbill if (*colp) 75639Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 75739Sbill } else 75839Sbill if(ctype == 2) { /* vt05 */ 75939Sbill c = 6; 76039Sbill } 76139Sbill *colp = 0; 76239Sbill break; 76339Sbill 76439Sbill /* tab */ 76539Sbill case 4: 76639Sbill ctype = (tp->t_flags >> 10) & 03; 76739Sbill if(ctype == 1) { /* tty 37 */ 76839Sbill c = 1 - (*colp | ~07); 76939Sbill if(c < 5) 77039Sbill c = 0; 77139Sbill } 77239Sbill *colp |= 07; 77339Sbill (*colp)++; 77439Sbill break; 77539Sbill 77639Sbill /* vertical motion */ 77739Sbill case 5: 77839Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 77939Sbill c = 0177; 78039Sbill break; 78139Sbill 78239Sbill /* carriage return */ 78339Sbill case 6: 78439Sbill ctype = (tp->t_flags >> 12) & 03; 78539Sbill if(ctype == 1) { /* tn 300 */ 78639Sbill c = 5; 78739Sbill } else if(ctype == 2) { /* ti 700 */ 78839Sbill c = 10; 78939Sbill } else if(ctype == 3) { /* concept 100 */ 79039Sbill int i; 79139Sbill for (i= *colp; i<9; i++) 792121Sbill (void) putc(0177, &tp->t_outq); 79339Sbill } 79439Sbill *colp = 0; 79539Sbill } 79639Sbill if(c) 797121Sbill (void) putc(c|0200, &tp->t_outq); 79839Sbill } 79939Sbill 80039Sbill /* 80139Sbill * Restart typewriter output following a delay 80239Sbill * timeout. 80339Sbill * The name of the routine is passed to the timeout 80439Sbill * subroutine and it is called during a clock interrupt. 80539Sbill */ 80639Sbill ttrstrt(tp) 80739Sbill register struct tty *tp; 80839Sbill { 80939Sbill 81039Sbill tp->t_state &= ~TIMEOUT; 81139Sbill ttstart(tp); 81239Sbill } 81339Sbill 81439Sbill /* 81539Sbill * Start output on the typewriter. It is used from the top half 81639Sbill * after some characters have been put on the output queue, 81739Sbill * from the interrupt routine to transmit the next 81839Sbill * character, and after a timeout has finished. 81939Sbill */ 82039Sbill ttstart(tp) 82139Sbill register struct tty *tp; 82239Sbill { 82339Sbill register s; 82439Sbill 82539Sbill s = spl5(); 82639Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 82739Sbill (*tp->t_oproc)(tp); 82839Sbill splx(s); 82939Sbill } 83039Sbill 83139Sbill /* 83239Sbill * Called from device's read routine after it has 83339Sbill * calculated the tty-structure given as argument. 83439Sbill */ 83539Sbill ttread(tp) 83639Sbill register struct tty *tp; 83739Sbill { 83839Sbill register s; 83939Sbill 84039Sbill if ((tp->t_state&CARR_ON)==0) 84139Sbill return(-1); 84239Sbill s = spl5(); 84339Sbill if (tp->t_canq.c_cc==0) 84439Sbill while (canon(tp)<0) 84539Sbill if (tp->t_chan==NULL) { 84639Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 84739Sbill } else { 84839Sbill splx(s); 84939Sbill return(0); 85039Sbill } 85139Sbill splx(s); 85239Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 85339Sbill ; 85439Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 85539Sbill } 85639Sbill 85739Sbill /* 85839Sbill * Called from the device's write routine after it has 85939Sbill * calculated the tty-structure given as argument. 86039Sbill */ 86139Sbill caddr_t 86239Sbill ttwrite(tp) 86339Sbill register struct tty *tp; 86439Sbill { 86539Sbill /* 86639Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 86739Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 86839Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 86939Sbill */ 87039Sbill register char *cp; 87139Sbill register int cc, ce; 87239Sbill register i; 87339Sbill char obuf[OBUFSIZ]; 87439Sbill 87539Sbill if ((tp->t_state&CARR_ON)==0) 87639Sbill return(NULL); 87739Sbill while (u.u_count) { 87839Sbill cc = MIN(u.u_count, OBUFSIZ); 87939Sbill cp = obuf; 88039Sbill iomove(cp, (unsigned)cc, B_WRITE); 88139Sbill if (u.u_error) 88239Sbill break; 883121Sbill (void) spl5(); 88439Sbill while (tp->t_outq.c_cc > TTHIWAT) { 88539Sbill ttstart(tp); 88639Sbill tp->t_state |= ASLEEP; 88739Sbill if (tp->t_chan) { 88839Sbill u.u_base -= cc; 88939Sbill u.u_offset -= cc; 89039Sbill u.u_count += cc; 891121Sbill (void) spl0(); 89239Sbill return((caddr_t)&tp->t_outq); 89339Sbill } 89439Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 89539Sbill } 896121Sbill (void) spl0(); 89739Sbill if (tp->t_flags&LCASE) { 89839Sbill while (cc--) 89939Sbill ttyoutput(*cp++,tp); 90039Sbill continue; 90139Sbill } 90239Sbill while (cc) { 90339Sbill if (tp->t_flags&RAW) 90439Sbill ce=cc; 90539Sbill else { 90639Sbill #ifdef VAX 90739Sbill asm(" scanc r9,(r10),_partab,$077"); 90839Sbill asm(" subl3 r0,r9,r8"); 90939Sbill #else 91039Sbill ce=0; 91139Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 91239Sbill ce++; 91339Sbill #endif 91439Sbill if (ce==0) { 91539Sbill ttyoutput(*cp++,tp); 91639Sbill cc--; 917121Sbill goto check; 91839Sbill } 91939Sbill } 92039Sbill i=b_to_q(cp,ce,&tp->t_outq); 92139Sbill ce-=i; 92239Sbill tk_nout+=ce; 92339Sbill tp->t_col+=ce; 92439Sbill cp+=ce; 92539Sbill cc-=ce; 926121Sbill check: 927121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 928121Sbill (void) spl5(); 92939Sbill while (tp->t_outq.c_cc > TTHIWAT) { 93039Sbill ttstart(tp); 93139Sbill tp->t_state |= ASLEEP; 93239Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 93339Sbill } 934121Sbill (void) spl0(); 93539Sbill } 93639Sbill } 93739Sbill } 93839Sbill ttstart(tp); 93939Sbill return(NULL); 94039Sbill } 941