1*340Sbill /* tty.c 3.9 07/01/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" 18*340Sbill #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; 93174Sbill 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; 136174Sbill 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; 22739Sbill 22839Sbill switch(com) { 22939Sbill 23039Sbill /* 23139Sbill * get discipline number 23239Sbill */ 23339Sbill case TIOCGETD: 23439Sbill t = tp->t_line; 23539Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 23639Sbill u.u_error = EFAULT; 23739Sbill break; 23839Sbill 23939Sbill /* 24039Sbill * set line discipline 24139Sbill */ 24239Sbill case TIOCSETD: 24339Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 24439Sbill u.u_error = EFAULT; 24539Sbill break; 24639Sbill } 24739Sbill if (t >= nldisp) { 24839Sbill u.u_error = ENXIO; 24939Sbill break; 25039Sbill } 251174Sbill (void) spl5(); 25239Sbill if (tp->t_line) 25339Sbill (*linesw[tp->t_line].l_close)(tp); 25439Sbill if (t) 25539Sbill (*linesw[t].l_open)(dev, tp, addr); 25639Sbill if (u.u_error==0) 25739Sbill tp->t_line = t; 258174Sbill (void) spl0(); 25939Sbill break; 26039Sbill 26139Sbill /* 26239Sbill * prevent more opens on channel 26339Sbill */ 26439Sbill case TIOCEXCL: 26539Sbill tp->t_state |= XCLUDE; 26639Sbill break; 26739Sbill 26839Sbill case TIOCNXCL: 26939Sbill tp->t_state &= ~XCLUDE; 27039Sbill break; 27139Sbill 27239Sbill /* 27339Sbill * Set new parameters 27439Sbill */ 27539Sbill case TIOCSETP: 276191Sbill case TIOCSETN: 27739Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 27839Sbill u.u_error = EFAULT; 27939Sbill return(1); 28039Sbill } 281121Sbill (void) spl5(); 282174Sbill if (tp->t_line == 0) { 283174Sbill if (com == TIOCSETP) 284174Sbill wflushtty(tp); 285174Sbill while (canon(tp)>=0) 286174Sbill ; 287174Sbill } else if (tp->t_line == NTTYDISC) { 288174Sbill if (tp->t_flags&RAW || iocb.sg_flags&RAW || 289174Sbill com == TIOCSETP) 290174Sbill wflushtty(tp); 291174Sbill else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 292174Sbill if (iocb.sg_flags & CBREAK) { 293174Sbill catq(&tp->t_rawq, &tp->t_canq); 294174Sbill tq = tp->t_rawq; 295174Sbill tp->t_rawq = tp->t_canq; 296174Sbill tp->t_canq = tq; 297174Sbill } else { 298174Sbill tp->t_local |= LPENDIN; 299174Sbill if (tp->t_canq.c_cc) 300174Sbill panic("ioccom canq"); 301174Sbill if (tp->t_chan) 302174Sbill (void) sdata(tp->t_chan); 303174Sbill else 304174Sbill wakeup((caddr_t)&tp->t_rawq); 305174Sbill } 306174Sbill } 307174Sbill } 30839Sbill if ((tp->t_state&SPEEDS)==0) { 309174Sbill tp->t_ispeed = iocb.sg_ispeed; 310174Sbill tp->t_ospeed = iocb.sg_ospeed; 31139Sbill } 312174Sbill tp->t_erase = iocb.sg_erase; 313174Sbill tp->t_kill = iocb.sg_kill; 314174Sbill tp->t_flags = iocb.sg_flags; 315121Sbill (void) spl0(); 31639Sbill break; 31739Sbill 31839Sbill /* 31939Sbill * send current parameters to user 32039Sbill */ 32139Sbill case TIOCGETP: 322174Sbill iocb.sg_ispeed = tp->t_ispeed; 323174Sbill iocb.sg_ospeed = tp->t_ospeed; 324174Sbill iocb.sg_erase = tp->t_erase; 325174Sbill iocb.sg_kill = tp->t_kill; 326174Sbill iocb.sg_flags = tp->t_flags; 32739Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 32839Sbill u.u_error = EFAULT; 32939Sbill break; 33039Sbill 33139Sbill /* 33239Sbill * Hang up line on last close 33339Sbill */ 33439Sbill 33539Sbill case TIOCHPCL: 33639Sbill tp->t_state |= HUPCLS; 33739Sbill break; 33839Sbill 33939Sbill case TIOCFLUSH: 34039Sbill flushtty(tp); 34139Sbill break; 34239Sbill 34339Sbill /* 34439Sbill * ioctl entries to line discipline 34539Sbill */ 34639Sbill case DIOCSETP: 34739Sbill case DIOCGETP: 348121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 349121Sbill u.u_error = ENOTTY; 35039Sbill break; 35139Sbill 35239Sbill /* 35339Sbill * set and fetch special characters 35439Sbill */ 35539Sbill case TIOCSETC: 356174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 35739Sbill u.u_error = EFAULT; 35839Sbill break; 35939Sbill 36039Sbill case TIOCGETC: 361174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 36239Sbill u.u_error = EFAULT; 36339Sbill break; 36439Sbill 365174Sbill /* local ioctls */ 366174Sbill case TIOCSLTC: 367174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 368174Sbill u.u_error = EFAULT; 369174Sbill break; 370174Sbill 371174Sbill case TIOCGLTC: 372174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 373174Sbill u.u_error = EFAULT; 374174Sbill break; 375174Sbill 376174Sbill case FIONREAD: { 377*340Sbill off_t nread; 378174Sbill 379*340Sbill switch (tp->t_line) { 380*340Sbill 381*340Sbill case NETLDISC: 382*340Sbill nread = tp->t_rec ? tp->t_inbuf : 0; 383*340Sbill break; 384*340Sbill 385*340Sbill case NTTYDISC: 386*340Sbill nread = tp->t_canq.c_cc; 387*340Sbill if (tp->t_flags & (RAW|CBREAK)) 388*340Sbill nread += tp->t_rawq.c_cc; 389*340Sbill break; 390*340Sbill 391*340Sbill case 0: 392*340Sbill /* do something here ... */ 393*340Sbill ; 394*340Sbill } 395174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 396174Sbill u.u_error = EFAULT; 397174Sbill break; 398174Sbill } 399174Sbill 400174Sbill /* 401174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 402174Sbill */ 403174Sbill case TIOCSPGRP: 404174Sbill tp->t_pgrp = (int)addr; 405174Sbill break; 406174Sbill 407174Sbill case TIOCGPGRP: 408174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 409174Sbill u.u_error = EFAULT; 410174Sbill break; 411174Sbill 412174Sbill /* 413174Sbill * Modify local mode word. 414174Sbill */ 415174Sbill case TIOCLBIS: 416174Sbill tp->t_local |= (int)addr; 417174Sbill break; 418174Sbill 419174Sbill case TIOCLBIC: 420174Sbill tp->t_local &= ~(int)addr; 421174Sbill break; 422174Sbill 423174Sbill case TIOCLSET: 424174Sbill tp->t_local = (int)addr; 425174Sbill break; 426174Sbill 427174Sbill case TIOCLGET: 428174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 429174Sbill u.u_error = EFAULT; 430174Sbill break; 431174Sbill 432213Sbill case TIOCOUTQ: 433213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 434213Sbill u.u_error = EFAULT; 435213Sbill break; 436213Sbill 437174Sbill /* end of locals */ 43839Sbill default: 43939Sbill return(0); 44039Sbill } 44139Sbill return(1); 44239Sbill } 44339Sbill 44439Sbill /* 44539Sbill * Wait for output to drain, then flush input waiting. 44639Sbill */ 44739Sbill wflushtty(tp) 44839Sbill register struct tty *tp; 44939Sbill { 45039Sbill 451121Sbill (void) spl5(); 45239Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 45339Sbill (*tp->t_oproc)(tp); 45439Sbill tp->t_state |= ASLEEP; 45539Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 45639Sbill } 45739Sbill flushtty(tp); 458121Sbill (void) spl0(); 45939Sbill } 46039Sbill 46139Sbill /* 46239Sbill * flush all TTY queues 46339Sbill */ 46439Sbill flushtty(tp) 46539Sbill register struct tty *tp; 46639Sbill { 46739Sbill register s; 46839Sbill 469*340Sbill if (tp->t_line == NETLDISC) 470*340Sbill return; 471121Sbill s = spl6(); 47239Sbill while (getc(&tp->t_canq) >= 0) 47339Sbill ; 47439Sbill wakeup((caddr_t)&tp->t_rawq); 47539Sbill wakeup((caddr_t)&tp->t_outq); 47639Sbill tp->t_state &= ~TTSTOP; 47739Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 47839Sbill while (getc(&tp->t_outq) >= 0) 47939Sbill ; 48039Sbill while (getc(&tp->t_rawq) >= 0) 48139Sbill ; 48239Sbill tp->t_delct = 0; 483174Sbill tp->t_rocount = 0; /* local */ 484208Sbill tp->t_lstate = 0; 48539Sbill splx(s); 48639Sbill } 48739Sbill 48839Sbill 48939Sbill 49039Sbill /* 49139Sbill * transfer raw input list to canonical list, 49239Sbill * doing erase-kill processing and handling escapes. 49339Sbill * It waits until a full line has been typed in cooked mode, 49439Sbill * or until any character has been typed in raw mode. 49539Sbill */ 49639Sbill canon(tp) 49739Sbill register struct tty *tp; 49839Sbill { 49939Sbill register char *bp; 50039Sbill char *bp1; 50139Sbill register int c; 50239Sbill int mc; 50339Sbill int s; 50439Sbill 50539Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 50639Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 50739Sbill return(-1); 50839Sbill } 50939Sbill s = spl0(); 51039Sbill loop: 51139Sbill bp = &canonb[2]; 51239Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 51339Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 51439Sbill if (c==0377) { 51539Sbill tp->t_delct--; 51639Sbill break; 51739Sbill } 51839Sbill if (bp[-1]!='\\') { 51939Sbill if (c==tp->t_erase) { 52039Sbill if (bp > &canonb[2]) 52139Sbill bp--; 52239Sbill continue; 52339Sbill } 52439Sbill if (c==tp->t_kill) 52539Sbill goto loop; 52639Sbill if (c==tun.t_eofc) 52739Sbill continue; 52839Sbill } else { 52939Sbill mc = maptab[c]; 53039Sbill if (c==tp->t_erase || c==tp->t_kill) 53139Sbill mc = c; 53239Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 53339Sbill if (bp[-2] != '\\') 53439Sbill c = mc; 53539Sbill bp--; 53639Sbill } 53739Sbill } 53839Sbill } 53939Sbill *bp++ = c; 54039Sbill if (bp>=canonb+CANBSIZ) 54139Sbill break; 54239Sbill } 54339Sbill bp1 = &canonb[2]; 544121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 54539Sbill 54639Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 54739Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 54839Sbill tp->t_state &= ~TBLOCK; 54939Sbill ttstart(tp); 55039Sbill } 55139Sbill tp->t_char = 0; 55239Sbill } 55339Sbill 55439Sbill splx(s); 55539Sbill return(0); 55639Sbill } 55739Sbill 55839Sbill 55939Sbill /* 56039Sbill * block transfer input handler. 56139Sbill */ 56239Sbill ttyrend(tp, pb, pe) 56339Sbill register struct tty *tp; 56439Sbill register char *pb, *pe; 56539Sbill { 56639Sbill int tandem; 56739Sbill 56839Sbill tandem = tp->t_flags&TANDEM; 56939Sbill if (tp->t_flags&RAW) { 570121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 57139Sbill if (tp->t_chan) 572121Sbill (void) sdata(tp->t_chan); else 57339Sbill wakeup((caddr_t)&tp->t_rawq); 57439Sbill } else { 57539Sbill tp->t_flags &= ~TANDEM; 57639Sbill while (pb < pe) 57739Sbill ttyinput(*pb++, tp); 57839Sbill tp->t_flags |= tandem; 57939Sbill } 58039Sbill if (tandem) 58139Sbill ttyblock(tp); 58239Sbill } 58339Sbill 58439Sbill /* 58539Sbill * Place a character on raw TTY input queue, putting in delimiters 58639Sbill * and waking up top half as needed. 58739Sbill * Also echo if required. 58839Sbill * The arguments are the character and the appropriate 58939Sbill * tty structure. 59039Sbill */ 59139Sbill ttyinput(c, tp) 59239Sbill register c; 59339Sbill register struct tty *tp; 59439Sbill { 59539Sbill register int t_flags; 59639Sbill register struct chan *cp; 59739Sbill 59839Sbill tk_nin += 1; 59939Sbill c &= 0377; 60039Sbill t_flags = tp->t_flags; 60139Sbill if (t_flags&TANDEM) 60239Sbill ttyblock(tp); 60339Sbill if ((t_flags&RAW)==0) { 60439Sbill c &= 0177; 60539Sbill if (tp->t_state&TTSTOP) { 60639Sbill if (c==tun.t_startc) { 60739Sbill tp->t_state &= ~TTSTOP; 60839Sbill ttstart(tp); 60939Sbill return; 61039Sbill } 61139Sbill if (c==tun.t_stopc) 61239Sbill return; 61339Sbill tp->t_state &= ~TTSTOP; 61439Sbill ttstart(tp); 61539Sbill } else { 61639Sbill if (c==tun.t_stopc) { 61739Sbill tp->t_state |= TTSTOP; 61839Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 61939Sbill return; 62039Sbill } 62139Sbill if (c==tun.t_startc) 62239Sbill return; 62339Sbill } 62439Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 62539Sbill flushtty(tp); 62639Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 62739Sbill if (tp->t_chan) 62839Sbill scontrol(tp->t_chan, M_SIG, c); 62939Sbill else 630174Sbill gsignal(tp->t_pgrp, c); 63139Sbill return; 63239Sbill } 63339Sbill if (c=='\r' && t_flags&CRMOD) 63439Sbill c = '\n'; 63539Sbill } 63639Sbill if (tp->t_rawq.c_cc>TTYHOG) { 63739Sbill flushtty(tp); 63839Sbill return; 63939Sbill } 64039Sbill if (t_flags&LCASE && c>='A' && c<='Z') 64139Sbill c += 'a'-'A'; 642121Sbill (void) putc(c, &tp->t_rawq); 64339Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 64439Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 64539Sbill tp->t_delct++; 64639Sbill if ((cp=tp->t_chan)!=NULL) 647121Sbill (void) sdata(cp); else 64839Sbill wakeup((caddr_t)&tp->t_rawq); 64939Sbill } 65039Sbill if (t_flags&ECHO) { 65139Sbill ttyoutput(c, tp); 65239Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 65339Sbill ttyoutput('\n', tp); 65439Sbill ttstart(tp); 65539Sbill } 65639Sbill } 65739Sbill 65839Sbill 65939Sbill /* 66039Sbill * Send stop character on input overflow. 66139Sbill */ 66239Sbill ttyblock(tp) 66339Sbill register struct tty *tp; 66439Sbill { 66539Sbill register x; 66639Sbill x = q1.c_cc + q2.c_cc; 66739Sbill if (q1.c_cc > TTYHOG) { 66839Sbill flushtty(tp); 66939Sbill tp->t_state &= ~TBLOCK; 67039Sbill } 67139Sbill if (x >= TTYHOG/2) { 67239Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 67339Sbill tp->t_state |= TBLOCK; 67439Sbill tp->t_char++; 67539Sbill ttstart(tp); 67639Sbill } 67739Sbill } 67839Sbill } 67939Sbill 68039Sbill /* 68139Sbill * put character on TTY output queue, adding delays, 68239Sbill * expanding tabs, and handling the CR/NL bit. 68339Sbill * It is called both from the top half for output, and from 68439Sbill * interrupt level for echoing. 68539Sbill * The arguments are the character and the tty structure. 68639Sbill */ 68739Sbill ttyoutput(c, tp) 68839Sbill register c; 68939Sbill register struct tty *tp; 69039Sbill { 69139Sbill register char *colp; 69239Sbill register ctype; 69339Sbill 69439Sbill /* 69539Sbill * Ignore EOT in normal mode to avoid hanging up 69639Sbill * certain terminals. 69739Sbill * In raw mode dump the char unchanged. 69839Sbill */ 69939Sbill if ((tp->t_flags&RAW)==0) { 70039Sbill c &= 0177; 70139Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 70239Sbill return; 70339Sbill } else { 704121Sbill tk_nout++; 705121Sbill (void) putc(c, &tp->t_outq); 70639Sbill return; 70739Sbill } 70839Sbill 70939Sbill /* 71039Sbill * Turn tabs to spaces as required 71139Sbill */ 71239Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 713121Sbill c = 8 - (tp->t_col & 7); 714121Sbill (void) b_to_q(" ", c, &tp->t_outq); 715121Sbill tp->t_col += c; 716121Sbill tk_nout += c; 71739Sbill return; 71839Sbill } 719121Sbill tk_nout++; 72039Sbill /* 72139Sbill * for upper-case-only terminals, 72239Sbill * generate escapes. 72339Sbill */ 72439Sbill if (tp->t_flags&LCASE) { 72539Sbill colp = "({)}!|^~'`"; 72639Sbill while(*colp++) 72739Sbill if(c == *colp++) { 72839Sbill ttyoutput('\\', tp); 72939Sbill c = colp[-2]; 73039Sbill break; 73139Sbill } 73239Sbill if ('a'<=c && c<='z') 73339Sbill c += 'A' - 'a'; 73439Sbill } 73539Sbill /* 73639Sbill * turn <nl> to <cr><lf> if desired. 73739Sbill */ 73839Sbill if (c=='\n' && tp->t_flags&CRMOD) 73939Sbill ttyoutput('\r', tp); 740121Sbill (void) putc(c, &tp->t_outq); 74139Sbill /* 74239Sbill * Calculate delays. 74339Sbill * The numbers here represent clock ticks 74439Sbill * and are not necessarily optimal for all terminals. 74539Sbill * The delays are indicated by characters above 0200. 74639Sbill * In raw mode there are no delays and the 74739Sbill * transmission path is 8 bits wide. 74839Sbill */ 74939Sbill colp = &tp->t_col; 75039Sbill ctype = partab[c]; 75139Sbill c = 0; 75239Sbill switch (ctype&077) { 75339Sbill 75439Sbill /* ordinary */ 75539Sbill case 0: 75639Sbill (*colp)++; 75739Sbill 75839Sbill /* non-printing */ 75939Sbill case 1: 76039Sbill break; 76139Sbill 76239Sbill /* backspace */ 76339Sbill case 2: 76439Sbill if (*colp) 76539Sbill (*colp)--; 76639Sbill break; 76739Sbill 76839Sbill /* newline */ 76939Sbill case 3: 77039Sbill ctype = (tp->t_flags >> 8) & 03; 77139Sbill if(ctype == 1) { /* tty 37 */ 77239Sbill if (*colp) 77339Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 77439Sbill } else 77539Sbill if(ctype == 2) { /* vt05 */ 77639Sbill c = 6; 77739Sbill } 77839Sbill *colp = 0; 77939Sbill break; 78039Sbill 78139Sbill /* tab */ 78239Sbill case 4: 78339Sbill ctype = (tp->t_flags >> 10) & 03; 78439Sbill if(ctype == 1) { /* tty 37 */ 78539Sbill c = 1 - (*colp | ~07); 78639Sbill if(c < 5) 78739Sbill c = 0; 78839Sbill } 78939Sbill *colp |= 07; 79039Sbill (*colp)++; 79139Sbill break; 79239Sbill 79339Sbill /* vertical motion */ 79439Sbill case 5: 79539Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 79639Sbill c = 0177; 79739Sbill break; 79839Sbill 79939Sbill /* carriage return */ 80039Sbill case 6: 80139Sbill ctype = (tp->t_flags >> 12) & 03; 80239Sbill if(ctype == 1) { /* tn 300 */ 80339Sbill c = 5; 80439Sbill } else if(ctype == 2) { /* ti 700 */ 80539Sbill c = 10; 80639Sbill } else if(ctype == 3) { /* concept 100 */ 80739Sbill int i; 80839Sbill for (i= *colp; i<9; i++) 809121Sbill (void) putc(0177, &tp->t_outq); 81039Sbill } 81139Sbill *colp = 0; 81239Sbill } 81339Sbill if(c) 814121Sbill (void) putc(c|0200, &tp->t_outq); 81539Sbill } 81639Sbill 81739Sbill /* 81839Sbill * Restart typewriter output following a delay 81939Sbill * timeout. 82039Sbill * The name of the routine is passed to the timeout 82139Sbill * subroutine and it is called during a clock interrupt. 82239Sbill */ 82339Sbill ttrstrt(tp) 82439Sbill register struct tty *tp; 82539Sbill { 82639Sbill 82739Sbill tp->t_state &= ~TIMEOUT; 82839Sbill ttstart(tp); 82939Sbill } 83039Sbill 83139Sbill /* 83239Sbill * Start output on the typewriter. It is used from the top half 83339Sbill * after some characters have been put on the output queue, 83439Sbill * from the interrupt routine to transmit the next 83539Sbill * character, and after a timeout has finished. 83639Sbill */ 83739Sbill ttstart(tp) 83839Sbill register struct tty *tp; 83939Sbill { 84039Sbill register s; 84139Sbill 84239Sbill s = spl5(); 84339Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 84439Sbill (*tp->t_oproc)(tp); 84539Sbill splx(s); 84639Sbill } 84739Sbill 84839Sbill /* 84939Sbill * Called from device's read routine after it has 85039Sbill * calculated the tty-structure given as argument. 85139Sbill */ 85239Sbill ttread(tp) 85339Sbill register struct tty *tp; 85439Sbill { 85539Sbill register s; 85639Sbill 85739Sbill if ((tp->t_state&CARR_ON)==0) 85839Sbill return(-1); 85939Sbill s = spl5(); 86039Sbill if (tp->t_canq.c_cc==0) 86139Sbill while (canon(tp)<0) 86239Sbill if (tp->t_chan==NULL) { 86339Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 86439Sbill } else { 86539Sbill splx(s); 86639Sbill return(0); 86739Sbill } 86839Sbill splx(s); 86939Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 87039Sbill ; 87139Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 87239Sbill } 87339Sbill 87439Sbill /* 87539Sbill * Called from the device's write routine after it has 87639Sbill * calculated the tty-structure given as argument. 87739Sbill */ 87839Sbill caddr_t 87939Sbill ttwrite(tp) 88039Sbill register struct tty *tp; 88139Sbill { 88239Sbill /* 88339Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 88439Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 88539Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 88639Sbill */ 88739Sbill register char *cp; 88839Sbill register int cc, ce; 88939Sbill register i; 89039Sbill char obuf[OBUFSIZ]; 89139Sbill 89239Sbill if ((tp->t_state&CARR_ON)==0) 89339Sbill return(NULL); 89439Sbill while (u.u_count) { 89539Sbill cc = MIN(u.u_count, OBUFSIZ); 89639Sbill cp = obuf; 89739Sbill iomove(cp, (unsigned)cc, B_WRITE); 89839Sbill if (u.u_error) 89939Sbill break; 900121Sbill (void) spl5(); 90139Sbill while (tp->t_outq.c_cc > TTHIWAT) { 90239Sbill ttstart(tp); 90339Sbill tp->t_state |= ASLEEP; 90439Sbill if (tp->t_chan) { 90539Sbill u.u_base -= cc; 90639Sbill u.u_offset -= cc; 90739Sbill u.u_count += cc; 908121Sbill (void) spl0(); 90939Sbill return((caddr_t)&tp->t_outq); 91039Sbill } 91139Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 91239Sbill } 913121Sbill (void) spl0(); 91439Sbill if (tp->t_flags&LCASE) { 91539Sbill while (cc--) 91639Sbill ttyoutput(*cp++,tp); 91739Sbill continue; 91839Sbill } 91939Sbill while (cc) { 92039Sbill if (tp->t_flags&RAW) 92139Sbill ce=cc; 92239Sbill else { 92339Sbill #ifdef VAX 92439Sbill asm(" scanc r9,(r10),_partab,$077"); 92539Sbill asm(" subl3 r0,r9,r8"); 92639Sbill #else 92739Sbill ce=0; 92839Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 92939Sbill ce++; 93039Sbill #endif 93139Sbill if (ce==0) { 93239Sbill ttyoutput(*cp++,tp); 93339Sbill cc--; 934121Sbill goto check; 93539Sbill } 93639Sbill } 93739Sbill i=b_to_q(cp,ce,&tp->t_outq); 93839Sbill ce-=i; 93939Sbill tk_nout+=ce; 94039Sbill tp->t_col+=ce; 94139Sbill cp+=ce; 94239Sbill cc-=ce; 943121Sbill check: 944121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 945121Sbill (void) spl5(); 94639Sbill while (tp->t_outq.c_cc > TTHIWAT) { 94739Sbill ttstart(tp); 94839Sbill tp->t_state |= ASLEEP; 94939Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 95039Sbill } 951121Sbill (void) spl0(); 95239Sbill } 95339Sbill } 95439Sbill } 95539Sbill ttstart(tp); 95639Sbill return(NULL); 95739Sbill } 958