1*208Sbill /* tty.c 3.6 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; 86*208Sbill if (tp->t_pgrp == 0) 87*208Sbill 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 */ 111*208Sbill tlun.t_suspc = CTRL(z); 112*208Sbill 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 417174Sbill /* end of locals */ 41839Sbill default: 41939Sbill return(0); 42039Sbill } 42139Sbill return(1); 42239Sbill } 42339Sbill 42439Sbill /* 42539Sbill * Wait for output to drain, then flush input waiting. 42639Sbill */ 42739Sbill wflushtty(tp) 42839Sbill register struct tty *tp; 42939Sbill { 43039Sbill 431121Sbill (void) spl5(); 43239Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 43339Sbill (*tp->t_oproc)(tp); 43439Sbill tp->t_state |= ASLEEP; 43539Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 43639Sbill } 43739Sbill flushtty(tp); 438121Sbill (void) spl0(); 43939Sbill } 44039Sbill 44139Sbill /* 44239Sbill * flush all TTY queues 44339Sbill */ 44439Sbill flushtty(tp) 44539Sbill register struct tty *tp; 44639Sbill { 44739Sbill register s; 44839Sbill 449121Sbill s = spl6(); 45039Sbill while (getc(&tp->t_canq) >= 0) 45139Sbill ; 45239Sbill wakeup((caddr_t)&tp->t_rawq); 45339Sbill wakeup((caddr_t)&tp->t_outq); 45439Sbill tp->t_state &= ~TTSTOP; 45539Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 45639Sbill while (getc(&tp->t_outq) >= 0) 45739Sbill ; 45839Sbill while (getc(&tp->t_rawq) >= 0) 45939Sbill ; 46039Sbill tp->t_delct = 0; 461174Sbill tp->t_rocount = 0; /* local */ 462*208Sbill tp->t_lstate = 0; 46339Sbill splx(s); 46439Sbill } 46539Sbill 46639Sbill 46739Sbill 46839Sbill /* 46939Sbill * transfer raw input list to canonical list, 47039Sbill * doing erase-kill processing and handling escapes. 47139Sbill * It waits until a full line has been typed in cooked mode, 47239Sbill * or until any character has been typed in raw mode. 47339Sbill */ 47439Sbill canon(tp) 47539Sbill register struct tty *tp; 47639Sbill { 47739Sbill register char *bp; 47839Sbill char *bp1; 47939Sbill register int c; 48039Sbill int mc; 48139Sbill int s; 48239Sbill 48339Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 48439Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 48539Sbill return(-1); 48639Sbill } 48739Sbill s = spl0(); 48839Sbill loop: 48939Sbill bp = &canonb[2]; 49039Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 49139Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 49239Sbill if (c==0377) { 49339Sbill tp->t_delct--; 49439Sbill break; 49539Sbill } 49639Sbill if (bp[-1]!='\\') { 49739Sbill if (c==tp->t_erase) { 49839Sbill if (bp > &canonb[2]) 49939Sbill bp--; 50039Sbill continue; 50139Sbill } 50239Sbill if (c==tp->t_kill) 50339Sbill goto loop; 50439Sbill if (c==tun.t_eofc) 50539Sbill continue; 50639Sbill } else { 50739Sbill mc = maptab[c]; 50839Sbill if (c==tp->t_erase || c==tp->t_kill) 50939Sbill mc = c; 51039Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 51139Sbill if (bp[-2] != '\\') 51239Sbill c = mc; 51339Sbill bp--; 51439Sbill } 51539Sbill } 51639Sbill } 51739Sbill *bp++ = c; 51839Sbill if (bp>=canonb+CANBSIZ) 51939Sbill break; 52039Sbill } 52139Sbill bp1 = &canonb[2]; 522121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 52339Sbill 52439Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 52539Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 52639Sbill tp->t_state &= ~TBLOCK; 52739Sbill ttstart(tp); 52839Sbill } 52939Sbill tp->t_char = 0; 53039Sbill } 53139Sbill 53239Sbill splx(s); 53339Sbill return(0); 53439Sbill } 53539Sbill 53639Sbill 53739Sbill /* 53839Sbill * block transfer input handler. 53939Sbill */ 54039Sbill ttyrend(tp, pb, pe) 54139Sbill register struct tty *tp; 54239Sbill register char *pb, *pe; 54339Sbill { 54439Sbill int tandem; 54539Sbill 54639Sbill tandem = tp->t_flags&TANDEM; 54739Sbill if (tp->t_flags&RAW) { 548121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 54939Sbill if (tp->t_chan) 550121Sbill (void) sdata(tp->t_chan); else 55139Sbill wakeup((caddr_t)&tp->t_rawq); 55239Sbill } else { 55339Sbill tp->t_flags &= ~TANDEM; 55439Sbill while (pb < pe) 55539Sbill ttyinput(*pb++, tp); 55639Sbill tp->t_flags |= tandem; 55739Sbill } 55839Sbill if (tandem) 55939Sbill ttyblock(tp); 56039Sbill } 56139Sbill 56239Sbill /* 56339Sbill * Place a character on raw TTY input queue, putting in delimiters 56439Sbill * and waking up top half as needed. 56539Sbill * Also echo if required. 56639Sbill * The arguments are the character and the appropriate 56739Sbill * tty structure. 56839Sbill */ 56939Sbill ttyinput(c, tp) 57039Sbill register c; 57139Sbill register struct tty *tp; 57239Sbill { 57339Sbill register int t_flags; 57439Sbill register struct chan *cp; 57539Sbill 57639Sbill tk_nin += 1; 57739Sbill c &= 0377; 57839Sbill t_flags = tp->t_flags; 57939Sbill if (t_flags&TANDEM) 58039Sbill ttyblock(tp); 58139Sbill if ((t_flags&RAW)==0) { 58239Sbill c &= 0177; 58339Sbill if (tp->t_state&TTSTOP) { 58439Sbill if (c==tun.t_startc) { 58539Sbill tp->t_state &= ~TTSTOP; 58639Sbill ttstart(tp); 58739Sbill return; 58839Sbill } 58939Sbill if (c==tun.t_stopc) 59039Sbill return; 59139Sbill tp->t_state &= ~TTSTOP; 59239Sbill ttstart(tp); 59339Sbill } else { 59439Sbill if (c==tun.t_stopc) { 59539Sbill tp->t_state |= TTSTOP; 59639Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 59739Sbill return; 59839Sbill } 59939Sbill if (c==tun.t_startc) 60039Sbill return; 60139Sbill } 60239Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 60339Sbill flushtty(tp); 60439Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 60539Sbill if (tp->t_chan) 60639Sbill scontrol(tp->t_chan, M_SIG, c); 60739Sbill else 608174Sbill gsignal(tp->t_pgrp, c); 60939Sbill return; 61039Sbill } 61139Sbill if (c=='\r' && t_flags&CRMOD) 61239Sbill c = '\n'; 61339Sbill } 61439Sbill if (tp->t_rawq.c_cc>TTYHOG) { 61539Sbill flushtty(tp); 61639Sbill return; 61739Sbill } 61839Sbill if (t_flags&LCASE && c>='A' && c<='Z') 61939Sbill c += 'a'-'A'; 620121Sbill (void) putc(c, &tp->t_rawq); 62139Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 62239Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 62339Sbill tp->t_delct++; 62439Sbill if ((cp=tp->t_chan)!=NULL) 625121Sbill (void) sdata(cp); else 62639Sbill wakeup((caddr_t)&tp->t_rawq); 62739Sbill } 62839Sbill if (t_flags&ECHO) { 62939Sbill ttyoutput(c, tp); 63039Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 63139Sbill ttyoutput('\n', tp); 63239Sbill ttstart(tp); 63339Sbill } 63439Sbill } 63539Sbill 63639Sbill 63739Sbill /* 63839Sbill * Send stop character on input overflow. 63939Sbill */ 64039Sbill ttyblock(tp) 64139Sbill register struct tty *tp; 64239Sbill { 64339Sbill register x; 64439Sbill x = q1.c_cc + q2.c_cc; 64539Sbill if (q1.c_cc > TTYHOG) { 64639Sbill flushtty(tp); 64739Sbill tp->t_state &= ~TBLOCK; 64839Sbill } 64939Sbill if (x >= TTYHOG/2) { 65039Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 65139Sbill tp->t_state |= TBLOCK; 65239Sbill tp->t_char++; 65339Sbill ttstart(tp); 65439Sbill } 65539Sbill } 65639Sbill } 65739Sbill 65839Sbill /* 65939Sbill * put character on TTY output queue, adding delays, 66039Sbill * expanding tabs, and handling the CR/NL bit. 66139Sbill * It is called both from the top half for output, and from 66239Sbill * interrupt level for echoing. 66339Sbill * The arguments are the character and the tty structure. 66439Sbill */ 66539Sbill ttyoutput(c, tp) 66639Sbill register c; 66739Sbill register struct tty *tp; 66839Sbill { 66939Sbill register char *colp; 67039Sbill register ctype; 67139Sbill 67239Sbill /* 67339Sbill * Ignore EOT in normal mode to avoid hanging up 67439Sbill * certain terminals. 67539Sbill * In raw mode dump the char unchanged. 67639Sbill */ 67739Sbill if ((tp->t_flags&RAW)==0) { 67839Sbill c &= 0177; 67939Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 68039Sbill return; 68139Sbill } else { 682121Sbill tk_nout++; 683121Sbill (void) putc(c, &tp->t_outq); 68439Sbill return; 68539Sbill } 68639Sbill 68739Sbill /* 68839Sbill * Turn tabs to spaces as required 68939Sbill */ 69039Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 691121Sbill c = 8 - (tp->t_col & 7); 692121Sbill (void) b_to_q(" ", c, &tp->t_outq); 693121Sbill tp->t_col += c; 694121Sbill tk_nout += c; 69539Sbill return; 69639Sbill } 697121Sbill tk_nout++; 69839Sbill /* 69939Sbill * for upper-case-only terminals, 70039Sbill * generate escapes. 70139Sbill */ 70239Sbill if (tp->t_flags&LCASE) { 70339Sbill colp = "({)}!|^~'`"; 70439Sbill while(*colp++) 70539Sbill if(c == *colp++) { 70639Sbill ttyoutput('\\', tp); 70739Sbill c = colp[-2]; 70839Sbill break; 70939Sbill } 71039Sbill if ('a'<=c && c<='z') 71139Sbill c += 'A' - 'a'; 71239Sbill } 71339Sbill /* 71439Sbill * turn <nl> to <cr><lf> if desired. 71539Sbill */ 71639Sbill if (c=='\n' && tp->t_flags&CRMOD) 71739Sbill ttyoutput('\r', tp); 718121Sbill (void) putc(c, &tp->t_outq); 71939Sbill /* 72039Sbill * Calculate delays. 72139Sbill * The numbers here represent clock ticks 72239Sbill * and are not necessarily optimal for all terminals. 72339Sbill * The delays are indicated by characters above 0200. 72439Sbill * In raw mode there are no delays and the 72539Sbill * transmission path is 8 bits wide. 72639Sbill */ 72739Sbill colp = &tp->t_col; 72839Sbill ctype = partab[c]; 72939Sbill c = 0; 73039Sbill switch (ctype&077) { 73139Sbill 73239Sbill /* ordinary */ 73339Sbill case 0: 73439Sbill (*colp)++; 73539Sbill 73639Sbill /* non-printing */ 73739Sbill case 1: 73839Sbill break; 73939Sbill 74039Sbill /* backspace */ 74139Sbill case 2: 74239Sbill if (*colp) 74339Sbill (*colp)--; 74439Sbill break; 74539Sbill 74639Sbill /* newline */ 74739Sbill case 3: 74839Sbill ctype = (tp->t_flags >> 8) & 03; 74939Sbill if(ctype == 1) { /* tty 37 */ 75039Sbill if (*colp) 75139Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 75239Sbill } else 75339Sbill if(ctype == 2) { /* vt05 */ 75439Sbill c = 6; 75539Sbill } 75639Sbill *colp = 0; 75739Sbill break; 75839Sbill 75939Sbill /* tab */ 76039Sbill case 4: 76139Sbill ctype = (tp->t_flags >> 10) & 03; 76239Sbill if(ctype == 1) { /* tty 37 */ 76339Sbill c = 1 - (*colp | ~07); 76439Sbill if(c < 5) 76539Sbill c = 0; 76639Sbill } 76739Sbill *colp |= 07; 76839Sbill (*colp)++; 76939Sbill break; 77039Sbill 77139Sbill /* vertical motion */ 77239Sbill case 5: 77339Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 77439Sbill c = 0177; 77539Sbill break; 77639Sbill 77739Sbill /* carriage return */ 77839Sbill case 6: 77939Sbill ctype = (tp->t_flags >> 12) & 03; 78039Sbill if(ctype == 1) { /* tn 300 */ 78139Sbill c = 5; 78239Sbill } else if(ctype == 2) { /* ti 700 */ 78339Sbill c = 10; 78439Sbill } else if(ctype == 3) { /* concept 100 */ 78539Sbill int i; 78639Sbill for (i= *colp; i<9; i++) 787121Sbill (void) putc(0177, &tp->t_outq); 78839Sbill } 78939Sbill *colp = 0; 79039Sbill } 79139Sbill if(c) 792121Sbill (void) putc(c|0200, &tp->t_outq); 79339Sbill } 79439Sbill 79539Sbill /* 79639Sbill * Restart typewriter output following a delay 79739Sbill * timeout. 79839Sbill * The name of the routine is passed to the timeout 79939Sbill * subroutine and it is called during a clock interrupt. 80039Sbill */ 80139Sbill ttrstrt(tp) 80239Sbill register struct tty *tp; 80339Sbill { 80439Sbill 80539Sbill tp->t_state &= ~TIMEOUT; 80639Sbill ttstart(tp); 80739Sbill } 80839Sbill 80939Sbill /* 81039Sbill * Start output on the typewriter. It is used from the top half 81139Sbill * after some characters have been put on the output queue, 81239Sbill * from the interrupt routine to transmit the next 81339Sbill * character, and after a timeout has finished. 81439Sbill */ 81539Sbill ttstart(tp) 81639Sbill register struct tty *tp; 81739Sbill { 81839Sbill register s; 81939Sbill 82039Sbill s = spl5(); 82139Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 82239Sbill (*tp->t_oproc)(tp); 82339Sbill splx(s); 82439Sbill } 82539Sbill 82639Sbill /* 82739Sbill * Called from device's read routine after it has 82839Sbill * calculated the tty-structure given as argument. 82939Sbill */ 83039Sbill ttread(tp) 83139Sbill register struct tty *tp; 83239Sbill { 83339Sbill register s; 83439Sbill 83539Sbill if ((tp->t_state&CARR_ON)==0) 83639Sbill return(-1); 83739Sbill s = spl5(); 83839Sbill if (tp->t_canq.c_cc==0) 83939Sbill while (canon(tp)<0) 84039Sbill if (tp->t_chan==NULL) { 84139Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 84239Sbill } else { 84339Sbill splx(s); 84439Sbill return(0); 84539Sbill } 84639Sbill splx(s); 84739Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 84839Sbill ; 84939Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 85039Sbill } 85139Sbill 85239Sbill /* 85339Sbill * Called from the device's write routine after it has 85439Sbill * calculated the tty-structure given as argument. 85539Sbill */ 85639Sbill caddr_t 85739Sbill ttwrite(tp) 85839Sbill register struct tty *tp; 85939Sbill { 86039Sbill /* 86139Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 86239Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 86339Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 86439Sbill */ 86539Sbill register char *cp; 86639Sbill register int cc, ce; 86739Sbill register i; 86839Sbill char obuf[OBUFSIZ]; 86939Sbill 87039Sbill if ((tp->t_state&CARR_ON)==0) 87139Sbill return(NULL); 87239Sbill while (u.u_count) { 87339Sbill cc = MIN(u.u_count, OBUFSIZ); 87439Sbill cp = obuf; 87539Sbill iomove(cp, (unsigned)cc, B_WRITE); 87639Sbill if (u.u_error) 87739Sbill break; 878121Sbill (void) spl5(); 87939Sbill while (tp->t_outq.c_cc > TTHIWAT) { 88039Sbill ttstart(tp); 88139Sbill tp->t_state |= ASLEEP; 88239Sbill if (tp->t_chan) { 88339Sbill u.u_base -= cc; 88439Sbill u.u_offset -= cc; 88539Sbill u.u_count += cc; 886121Sbill (void) spl0(); 88739Sbill return((caddr_t)&tp->t_outq); 88839Sbill } 88939Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 89039Sbill } 891121Sbill (void) spl0(); 89239Sbill if (tp->t_flags&LCASE) { 89339Sbill while (cc--) 89439Sbill ttyoutput(*cp++,tp); 89539Sbill continue; 89639Sbill } 89739Sbill while (cc) { 89839Sbill if (tp->t_flags&RAW) 89939Sbill ce=cc; 90039Sbill else { 90139Sbill #ifdef VAX 90239Sbill asm(" scanc r9,(r10),_partab,$077"); 90339Sbill asm(" subl3 r0,r9,r8"); 90439Sbill #else 90539Sbill ce=0; 90639Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 90739Sbill ce++; 90839Sbill #endif 90939Sbill if (ce==0) { 91039Sbill ttyoutput(*cp++,tp); 91139Sbill cc--; 912121Sbill goto check; 91339Sbill } 91439Sbill } 91539Sbill i=b_to_q(cp,ce,&tp->t_outq); 91639Sbill ce-=i; 91739Sbill tk_nout+=ce; 91839Sbill tp->t_col+=ce; 91939Sbill cp+=ce; 92039Sbill cc-=ce; 921121Sbill check: 922121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 923121Sbill (void) spl5(); 92439Sbill while (tp->t_outq.c_cc > TTHIWAT) { 92539Sbill ttstart(tp); 92639Sbill tp->t_state |= ASLEEP; 92739Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 92839Sbill } 929121Sbill (void) spl0(); 93039Sbill } 93139Sbill } 93239Sbill } 93339Sbill ttstart(tp); 93439Sbill return(NULL); 93539Sbill } 936