1*191Sbill /* tty.c 3.5 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; 86174Sbill tp->t_pgrp = pp->p_pid; 8739Sbill pp->p_pgrp = tp->t_pgrp; 8839Sbill } 8939Sbill tp->t_state &= ~WOPEN; 9039Sbill tp->t_state |= ISOPEN; 91174Sbill tp->t_line = 0; /* conservative */ 9239Sbill } 9339Sbill 9439Sbill /* 9539Sbill * set default control characters. 9639Sbill */ 9739Sbill ttychars(tp) 9839Sbill register struct tty *tp; 9939Sbill { 100174Sbill 10139Sbill tun.t_intrc = CINTR; 10239Sbill tun.t_quitc = CQUIT; 10339Sbill tun.t_startc = CSTART; 10439Sbill tun.t_stopc = CSTOP; 10539Sbill tun.t_eofc = CEOT; 10639Sbill tun.t_brkc = CBRK; 10739Sbill tp->t_erase = CERASE; 10839Sbill tp->t_kill = CKILL; 109174Sbill /* begin local */ 110174Sbill tlun.t_suspc = 0377; 111174Sbill tlun.t_dstopc = 0377; 112174Sbill tlun.t_rprntc = CTRL(r); 113174Sbill tlun.t_flushc = CTRL(o); 114174Sbill tlun.t_werasc = CTRL(w); 115174Sbill tlun.t_lnextc = CTRL(v); 116174Sbill tlun.t_lintr = CTRL(c); 117174Sbill tlun.t_lerase = CTRL(h); 118174Sbill tlun.t_lkill = CTRL(u); 119174Sbill tp->t_local = 0; 120174Sbill tp->t_lstate = 0; 121174Sbill /* end local */ 12239Sbill } 12339Sbill 12439Sbill /* 12539Sbill * clean tp on last close 12639Sbill */ 12739Sbill ttyclose(tp) 12839Sbill register struct tty *tp; 12939Sbill { 13039Sbill 13139Sbill tp->t_pgrp = 0; 13239Sbill wflushtty(tp); 13339Sbill tp->t_state = 0; 134174Sbill tp->t_line = 0; 13539Sbill } 13639Sbill 13739Sbill /* 13839Sbill * stty/gtty writearound 13939Sbill */ 14039Sbill stty() 14139Sbill { 14239Sbill u.u_arg[2] = u.u_arg[1]; 14339Sbill u.u_arg[1] = TIOCSETP; 14439Sbill ioctl(); 14539Sbill } 14639Sbill 14739Sbill gtty() 14839Sbill { 14939Sbill u.u_arg[2] = u.u_arg[1]; 15039Sbill u.u_arg[1] = TIOCGETP; 15139Sbill ioctl(); 15239Sbill } 15339Sbill 15439Sbill /* 155121Sbill * Do nothing specific version of line 156121Sbill * discipline specific ioctl command. 157121Sbill */ 158*191Sbill /*ARGSUSED*/ 159121Sbill nullioctl(tp, cmd, addr) 160121Sbill register struct tty *tp; 161121Sbill caddr_t addr; 162121Sbill { 163121Sbill 164121Sbill return (cmd); 165121Sbill } 166121Sbill 167121Sbill /* 16839Sbill * ioctl system call 16939Sbill * Check legality, execute common code, and switch out to individual 17039Sbill * device routine. 17139Sbill */ 17239Sbill ioctl() 17339Sbill { 17439Sbill register struct file *fp; 17539Sbill register struct inode *ip; 17639Sbill register struct a { 17739Sbill int fdes; 17839Sbill int cmd; 17939Sbill caddr_t cmarg; 18039Sbill } *uap; 18139Sbill register dev_t dev; 18239Sbill register fmt; 18339Sbill 18439Sbill uap = (struct a *)u.u_ap; 18539Sbill if ((fp = getf(uap->fdes)) == NULL) 18639Sbill return; 18739Sbill if (uap->cmd==FIOCLEX) { 18839Sbill u.u_pofile[uap->fdes] |= EXCLOSE; 18939Sbill return; 19039Sbill } 19139Sbill if (uap->cmd==FIONCLEX) { 19239Sbill u.u_pofile[uap->fdes] &= ~EXCLOSE; 19339Sbill return; 19439Sbill } 19539Sbill ip = fp->f_inode; 19639Sbill fmt = ip->i_mode & IFMT; 19739Sbill if (fmt != IFCHR && fmt != IFMPC) { 198174Sbill /* begin local */ 199174Sbill if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 200174Sbill off_t nread = ip->i_size - fp->f_un.f_offset; 201174Sbill 202174Sbill if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t))) 203174Sbill u.u_error = EFAULT; 204174Sbill } else 205174Sbill /* end local */ 206174Sbill u.u_error = ENOTTY; 20739Sbill return; 20839Sbill } 20939Sbill dev = ip->i_un.i_rdev; 21039Sbill u.u_r.r_val1 = 0; 21139Sbill (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); 21239Sbill } 21339Sbill 21439Sbill /* 21539Sbill * Common code for several tty ioctl commands 21639Sbill */ 21739Sbill ttioccomm(com, tp, addr, dev) 21839Sbill register struct tty *tp; 21939Sbill caddr_t addr; 22039Sbill { 22139Sbill unsigned t; 222174Sbill struct sgttyb iocb; 223*191Sbill struct clist tq; 22439Sbill extern int nldisp; 22539Sbill 22639Sbill switch(com) { 22739Sbill 22839Sbill /* 22939Sbill * get discipline number 23039Sbill */ 23139Sbill case TIOCGETD: 23239Sbill t = tp->t_line; 23339Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 23439Sbill u.u_error = EFAULT; 23539Sbill break; 23639Sbill 23739Sbill /* 23839Sbill * set line discipline 23939Sbill */ 24039Sbill case TIOCSETD: 24139Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 24239Sbill u.u_error = EFAULT; 24339Sbill break; 24439Sbill } 24539Sbill if (t >= nldisp) { 24639Sbill u.u_error = ENXIO; 24739Sbill break; 24839Sbill } 249174Sbill (void) spl5(); 25039Sbill if (tp->t_line) 25139Sbill (*linesw[tp->t_line].l_close)(tp); 25239Sbill if (t) 25339Sbill (*linesw[t].l_open)(dev, tp, addr); 25439Sbill if (u.u_error==0) 25539Sbill tp->t_line = t; 256174Sbill (void) spl0(); 25739Sbill break; 25839Sbill 25939Sbill /* 26039Sbill * prevent more opens on channel 26139Sbill */ 26239Sbill case TIOCEXCL: 26339Sbill tp->t_state |= XCLUDE; 26439Sbill break; 26539Sbill 26639Sbill case TIOCNXCL: 26739Sbill tp->t_state &= ~XCLUDE; 26839Sbill break; 26939Sbill 27039Sbill /* 27139Sbill * Set new parameters 27239Sbill */ 27339Sbill case TIOCSETP: 274*191Sbill case TIOCSETN: 27539Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 27639Sbill u.u_error = EFAULT; 27739Sbill return(1); 27839Sbill } 279121Sbill (void) spl5(); 280174Sbill if (tp->t_line == 0) { 281174Sbill if (com == TIOCSETP) 282174Sbill wflushtty(tp); 283174Sbill while (canon(tp)>=0) 284174Sbill ; 285174Sbill } else if (tp->t_line == NTTYDISC) { 286174Sbill if (tp->t_flags&RAW || iocb.sg_flags&RAW || 287174Sbill com == TIOCSETP) 288174Sbill wflushtty(tp); 289174Sbill else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 290174Sbill if (iocb.sg_flags & CBREAK) { 291174Sbill catq(&tp->t_rawq, &tp->t_canq); 292174Sbill tq = tp->t_rawq; 293174Sbill tp->t_rawq = tp->t_canq; 294174Sbill tp->t_canq = tq; 295174Sbill } else { 296174Sbill tp->t_local |= LPENDIN; 297174Sbill if (tp->t_canq.c_cc) 298174Sbill panic("ioccom canq"); 299174Sbill if (tp->t_chan) 300174Sbill (void) sdata(tp->t_chan); 301174Sbill else 302174Sbill wakeup((caddr_t)&tp->t_rawq); 303174Sbill } 304174Sbill } 305174Sbill } 30639Sbill if ((tp->t_state&SPEEDS)==0) { 307174Sbill tp->t_ispeed = iocb.sg_ispeed; 308174Sbill tp->t_ospeed = iocb.sg_ospeed; 30939Sbill } 310174Sbill tp->t_erase = iocb.sg_erase; 311174Sbill tp->t_kill = iocb.sg_kill; 312174Sbill tp->t_flags = iocb.sg_flags; 313121Sbill (void) spl0(); 31439Sbill break; 31539Sbill 31639Sbill /* 31739Sbill * send current parameters to user 31839Sbill */ 31939Sbill case TIOCGETP: 320174Sbill iocb.sg_ispeed = tp->t_ispeed; 321174Sbill iocb.sg_ospeed = tp->t_ospeed; 322174Sbill iocb.sg_erase = tp->t_erase; 323174Sbill iocb.sg_kill = tp->t_kill; 324174Sbill iocb.sg_flags = tp->t_flags; 32539Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 32639Sbill u.u_error = EFAULT; 32739Sbill break; 32839Sbill 32939Sbill /* 33039Sbill * Hang up line on last close 33139Sbill */ 33239Sbill 33339Sbill case TIOCHPCL: 33439Sbill tp->t_state |= HUPCLS; 33539Sbill break; 33639Sbill 33739Sbill case TIOCFLUSH: 33839Sbill flushtty(tp); 33939Sbill break; 34039Sbill 34139Sbill /* 34239Sbill * ioctl entries to line discipline 34339Sbill */ 34439Sbill case DIOCSETP: 34539Sbill case DIOCGETP: 346121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 347121Sbill u.u_error = ENOTTY; 34839Sbill break; 34939Sbill 35039Sbill /* 35139Sbill * set and fetch special characters 35239Sbill */ 35339Sbill case TIOCSETC: 354174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 35539Sbill u.u_error = EFAULT; 35639Sbill break; 35739Sbill 35839Sbill case TIOCGETC: 359174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 36039Sbill u.u_error = EFAULT; 36139Sbill break; 36239Sbill 363174Sbill /* local ioctls */ 364174Sbill case TIOCSLTC: 365174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 366174Sbill u.u_error = EFAULT; 367174Sbill break; 368174Sbill 369174Sbill case TIOCGLTC: 370174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 371174Sbill u.u_error = EFAULT; 372174Sbill break; 373174Sbill 374174Sbill case FIONREAD: { 375174Sbill off_t nread = tp->t_canq.c_cc; 376174Sbill 377174Sbill if (tp->t_flags & (RAW|CBREAK)) 378174Sbill nread += tp->t_rawq.c_cc; 379174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 380174Sbill u.u_error = EFAULT; 381174Sbill break; 382174Sbill } 383174Sbill 384174Sbill /* 385174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 386174Sbill */ 387174Sbill case TIOCSPGRP: 388174Sbill tp->t_pgrp = (int)addr; 389174Sbill break; 390174Sbill 391174Sbill case TIOCGPGRP: 392174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 393174Sbill u.u_error = EFAULT; 394174Sbill break; 395174Sbill 396174Sbill /* 397174Sbill * Modify local mode word. 398174Sbill */ 399174Sbill case TIOCLBIS: 400174Sbill tp->t_local |= (int)addr; 401174Sbill break; 402174Sbill 403174Sbill case TIOCLBIC: 404174Sbill tp->t_local &= ~(int)addr; 405174Sbill break; 406174Sbill 407174Sbill case TIOCLSET: 408174Sbill tp->t_local = (int)addr; 409174Sbill break; 410174Sbill 411174Sbill case TIOCLGET: 412174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 413174Sbill u.u_error = EFAULT; 414174Sbill break; 415174Sbill 416174Sbill /* end of locals */ 41739Sbill default: 41839Sbill return(0); 41939Sbill } 42039Sbill return(1); 42139Sbill } 42239Sbill 42339Sbill /* 42439Sbill * Wait for output to drain, then flush input waiting. 42539Sbill */ 42639Sbill wflushtty(tp) 42739Sbill register struct tty *tp; 42839Sbill { 42939Sbill 430121Sbill (void) spl5(); 43139Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 43239Sbill (*tp->t_oproc)(tp); 43339Sbill tp->t_state |= ASLEEP; 43439Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 43539Sbill } 43639Sbill flushtty(tp); 437121Sbill (void) spl0(); 43839Sbill } 43939Sbill 44039Sbill /* 44139Sbill * flush all TTY queues 44239Sbill */ 44339Sbill flushtty(tp) 44439Sbill register struct tty *tp; 44539Sbill { 44639Sbill register s; 44739Sbill 448121Sbill s = spl6(); 44939Sbill while (getc(&tp->t_canq) >= 0) 45039Sbill ; 45139Sbill wakeup((caddr_t)&tp->t_rawq); 45239Sbill wakeup((caddr_t)&tp->t_outq); 45339Sbill tp->t_state &= ~TTSTOP; 45439Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 45539Sbill while (getc(&tp->t_outq) >= 0) 45639Sbill ; 45739Sbill while (getc(&tp->t_rawq) >= 0) 45839Sbill ; 45939Sbill tp->t_delct = 0; 460174Sbill tp->t_rocount = 0; /* local */ 461174Sbill tp->t_lstate = 0; /* reset */ 46239Sbill splx(s); 46339Sbill } 46439Sbill 46539Sbill 46639Sbill 46739Sbill /* 46839Sbill * transfer raw input list to canonical list, 46939Sbill * doing erase-kill processing and handling escapes. 47039Sbill * It waits until a full line has been typed in cooked mode, 47139Sbill * or until any character has been typed in raw mode. 47239Sbill */ 47339Sbill canon(tp) 47439Sbill register struct tty *tp; 47539Sbill { 47639Sbill register char *bp; 47739Sbill char *bp1; 47839Sbill register int c; 47939Sbill int mc; 48039Sbill int s; 48139Sbill 48239Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 48339Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 48439Sbill return(-1); 48539Sbill } 48639Sbill s = spl0(); 48739Sbill loop: 48839Sbill bp = &canonb[2]; 48939Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 49039Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 49139Sbill if (c==0377) { 49239Sbill tp->t_delct--; 49339Sbill break; 49439Sbill } 49539Sbill if (bp[-1]!='\\') { 49639Sbill if (c==tp->t_erase) { 49739Sbill if (bp > &canonb[2]) 49839Sbill bp--; 49939Sbill continue; 50039Sbill } 50139Sbill if (c==tp->t_kill) 50239Sbill goto loop; 50339Sbill if (c==tun.t_eofc) 50439Sbill continue; 50539Sbill } else { 50639Sbill mc = maptab[c]; 50739Sbill if (c==tp->t_erase || c==tp->t_kill) 50839Sbill mc = c; 50939Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 51039Sbill if (bp[-2] != '\\') 51139Sbill c = mc; 51239Sbill bp--; 51339Sbill } 51439Sbill } 51539Sbill } 51639Sbill *bp++ = c; 51739Sbill if (bp>=canonb+CANBSIZ) 51839Sbill break; 51939Sbill } 52039Sbill bp1 = &canonb[2]; 521121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 52239Sbill 52339Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 52439Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 52539Sbill tp->t_state &= ~TBLOCK; 52639Sbill ttstart(tp); 52739Sbill } 52839Sbill tp->t_char = 0; 52939Sbill } 53039Sbill 53139Sbill splx(s); 53239Sbill return(0); 53339Sbill } 53439Sbill 53539Sbill 53639Sbill /* 53739Sbill * block transfer input handler. 53839Sbill */ 53939Sbill ttyrend(tp, pb, pe) 54039Sbill register struct tty *tp; 54139Sbill register char *pb, *pe; 54239Sbill { 54339Sbill int tandem; 54439Sbill 54539Sbill tandem = tp->t_flags&TANDEM; 54639Sbill if (tp->t_flags&RAW) { 547121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 54839Sbill if (tp->t_chan) 549121Sbill (void) sdata(tp->t_chan); else 55039Sbill wakeup((caddr_t)&tp->t_rawq); 55139Sbill } else { 55239Sbill tp->t_flags &= ~TANDEM; 55339Sbill while (pb < pe) 55439Sbill ttyinput(*pb++, tp); 55539Sbill tp->t_flags |= tandem; 55639Sbill } 55739Sbill if (tandem) 55839Sbill ttyblock(tp); 55939Sbill } 56039Sbill 56139Sbill /* 56239Sbill * Place a character on raw TTY input queue, putting in delimiters 56339Sbill * and waking up top half as needed. 56439Sbill * Also echo if required. 56539Sbill * The arguments are the character and the appropriate 56639Sbill * tty structure. 56739Sbill */ 56839Sbill ttyinput(c, tp) 56939Sbill register c; 57039Sbill register struct tty *tp; 57139Sbill { 57239Sbill register int t_flags; 57339Sbill register struct chan *cp; 57439Sbill 57539Sbill tk_nin += 1; 57639Sbill c &= 0377; 57739Sbill t_flags = tp->t_flags; 57839Sbill if (t_flags&TANDEM) 57939Sbill ttyblock(tp); 58039Sbill if ((t_flags&RAW)==0) { 58139Sbill c &= 0177; 58239Sbill if (tp->t_state&TTSTOP) { 58339Sbill if (c==tun.t_startc) { 58439Sbill tp->t_state &= ~TTSTOP; 58539Sbill ttstart(tp); 58639Sbill return; 58739Sbill } 58839Sbill if (c==tun.t_stopc) 58939Sbill return; 59039Sbill tp->t_state &= ~TTSTOP; 59139Sbill ttstart(tp); 59239Sbill } else { 59339Sbill if (c==tun.t_stopc) { 59439Sbill tp->t_state |= TTSTOP; 59539Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 59639Sbill return; 59739Sbill } 59839Sbill if (c==tun.t_startc) 59939Sbill return; 60039Sbill } 60139Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 60239Sbill flushtty(tp); 60339Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 60439Sbill if (tp->t_chan) 60539Sbill scontrol(tp->t_chan, M_SIG, c); 60639Sbill else 607174Sbill gsignal(tp->t_pgrp, c); 60839Sbill return; 60939Sbill } 61039Sbill if (c=='\r' && t_flags&CRMOD) 61139Sbill c = '\n'; 61239Sbill } 61339Sbill if (tp->t_rawq.c_cc>TTYHOG) { 61439Sbill flushtty(tp); 61539Sbill return; 61639Sbill } 61739Sbill if (t_flags&LCASE && c>='A' && c<='Z') 61839Sbill c += 'a'-'A'; 619121Sbill (void) putc(c, &tp->t_rawq); 62039Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 62139Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 62239Sbill tp->t_delct++; 62339Sbill if ((cp=tp->t_chan)!=NULL) 624121Sbill (void) sdata(cp); else 62539Sbill wakeup((caddr_t)&tp->t_rawq); 62639Sbill } 62739Sbill if (t_flags&ECHO) { 62839Sbill ttyoutput(c, tp); 62939Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 63039Sbill ttyoutput('\n', tp); 63139Sbill ttstart(tp); 63239Sbill } 63339Sbill } 63439Sbill 63539Sbill 63639Sbill /* 63739Sbill * Send stop character on input overflow. 63839Sbill */ 63939Sbill ttyblock(tp) 64039Sbill register struct tty *tp; 64139Sbill { 64239Sbill register x; 64339Sbill x = q1.c_cc + q2.c_cc; 64439Sbill if (q1.c_cc > TTYHOG) { 64539Sbill flushtty(tp); 64639Sbill tp->t_state &= ~TBLOCK; 64739Sbill } 64839Sbill if (x >= TTYHOG/2) { 64939Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 65039Sbill tp->t_state |= TBLOCK; 65139Sbill tp->t_char++; 65239Sbill ttstart(tp); 65339Sbill } 65439Sbill } 65539Sbill } 65639Sbill 65739Sbill /* 65839Sbill * put character on TTY output queue, adding delays, 65939Sbill * expanding tabs, and handling the CR/NL bit. 66039Sbill * It is called both from the top half for output, and from 66139Sbill * interrupt level for echoing. 66239Sbill * The arguments are the character and the tty structure. 66339Sbill */ 66439Sbill ttyoutput(c, tp) 66539Sbill register c; 66639Sbill register struct tty *tp; 66739Sbill { 66839Sbill register char *colp; 66939Sbill register ctype; 67039Sbill 67139Sbill /* 67239Sbill * Ignore EOT in normal mode to avoid hanging up 67339Sbill * certain terminals. 67439Sbill * In raw mode dump the char unchanged. 67539Sbill */ 67639Sbill if ((tp->t_flags&RAW)==0) { 67739Sbill c &= 0177; 67839Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 67939Sbill return; 68039Sbill } else { 681121Sbill tk_nout++; 682121Sbill (void) putc(c, &tp->t_outq); 68339Sbill return; 68439Sbill } 68539Sbill 68639Sbill /* 68739Sbill * Turn tabs to spaces as required 68839Sbill */ 68939Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 690121Sbill c = 8 - (tp->t_col & 7); 691121Sbill (void) b_to_q(" ", c, &tp->t_outq); 692121Sbill tp->t_col += c; 693121Sbill tk_nout += c; 69439Sbill return; 69539Sbill } 696121Sbill tk_nout++; 69739Sbill /* 69839Sbill * for upper-case-only terminals, 69939Sbill * generate escapes. 70039Sbill */ 70139Sbill if (tp->t_flags&LCASE) { 70239Sbill colp = "({)}!|^~'`"; 70339Sbill while(*colp++) 70439Sbill if(c == *colp++) { 70539Sbill ttyoutput('\\', tp); 70639Sbill c = colp[-2]; 70739Sbill break; 70839Sbill } 70939Sbill if ('a'<=c && c<='z') 71039Sbill c += 'A' - 'a'; 71139Sbill } 71239Sbill /* 71339Sbill * turn <nl> to <cr><lf> if desired. 71439Sbill */ 71539Sbill if (c=='\n' && tp->t_flags&CRMOD) 71639Sbill ttyoutput('\r', tp); 717121Sbill (void) putc(c, &tp->t_outq); 71839Sbill /* 71939Sbill * Calculate delays. 72039Sbill * The numbers here represent clock ticks 72139Sbill * and are not necessarily optimal for all terminals. 72239Sbill * The delays are indicated by characters above 0200. 72339Sbill * In raw mode there are no delays and the 72439Sbill * transmission path is 8 bits wide. 72539Sbill */ 72639Sbill colp = &tp->t_col; 72739Sbill ctype = partab[c]; 72839Sbill c = 0; 72939Sbill switch (ctype&077) { 73039Sbill 73139Sbill /* ordinary */ 73239Sbill case 0: 73339Sbill (*colp)++; 73439Sbill 73539Sbill /* non-printing */ 73639Sbill case 1: 73739Sbill break; 73839Sbill 73939Sbill /* backspace */ 74039Sbill case 2: 74139Sbill if (*colp) 74239Sbill (*colp)--; 74339Sbill break; 74439Sbill 74539Sbill /* newline */ 74639Sbill case 3: 74739Sbill ctype = (tp->t_flags >> 8) & 03; 74839Sbill if(ctype == 1) { /* tty 37 */ 74939Sbill if (*colp) 75039Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 75139Sbill } else 75239Sbill if(ctype == 2) { /* vt05 */ 75339Sbill c = 6; 75439Sbill } 75539Sbill *colp = 0; 75639Sbill break; 75739Sbill 75839Sbill /* tab */ 75939Sbill case 4: 76039Sbill ctype = (tp->t_flags >> 10) & 03; 76139Sbill if(ctype == 1) { /* tty 37 */ 76239Sbill c = 1 - (*colp | ~07); 76339Sbill if(c < 5) 76439Sbill c = 0; 76539Sbill } 76639Sbill *colp |= 07; 76739Sbill (*colp)++; 76839Sbill break; 76939Sbill 77039Sbill /* vertical motion */ 77139Sbill case 5: 77239Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 77339Sbill c = 0177; 77439Sbill break; 77539Sbill 77639Sbill /* carriage return */ 77739Sbill case 6: 77839Sbill ctype = (tp->t_flags >> 12) & 03; 77939Sbill if(ctype == 1) { /* tn 300 */ 78039Sbill c = 5; 78139Sbill } else if(ctype == 2) { /* ti 700 */ 78239Sbill c = 10; 78339Sbill } else if(ctype == 3) { /* concept 100 */ 78439Sbill int i; 78539Sbill for (i= *colp; i<9; i++) 786121Sbill (void) putc(0177, &tp->t_outq); 78739Sbill } 78839Sbill *colp = 0; 78939Sbill } 79039Sbill if(c) 791121Sbill (void) putc(c|0200, &tp->t_outq); 79239Sbill } 79339Sbill 79439Sbill /* 79539Sbill * Restart typewriter output following a delay 79639Sbill * timeout. 79739Sbill * The name of the routine is passed to the timeout 79839Sbill * subroutine and it is called during a clock interrupt. 79939Sbill */ 80039Sbill ttrstrt(tp) 80139Sbill register struct tty *tp; 80239Sbill { 80339Sbill 80439Sbill tp->t_state &= ~TIMEOUT; 80539Sbill ttstart(tp); 80639Sbill } 80739Sbill 80839Sbill /* 80939Sbill * Start output on the typewriter. It is used from the top half 81039Sbill * after some characters have been put on the output queue, 81139Sbill * from the interrupt routine to transmit the next 81239Sbill * character, and after a timeout has finished. 81339Sbill */ 81439Sbill ttstart(tp) 81539Sbill register struct tty *tp; 81639Sbill { 81739Sbill register s; 81839Sbill 81939Sbill s = spl5(); 82039Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 82139Sbill (*tp->t_oproc)(tp); 82239Sbill splx(s); 82339Sbill } 82439Sbill 82539Sbill /* 82639Sbill * Called from device's read routine after it has 82739Sbill * calculated the tty-structure given as argument. 82839Sbill */ 82939Sbill ttread(tp) 83039Sbill register struct tty *tp; 83139Sbill { 83239Sbill register s; 83339Sbill 83439Sbill if ((tp->t_state&CARR_ON)==0) 83539Sbill return(-1); 83639Sbill s = spl5(); 83739Sbill if (tp->t_canq.c_cc==0) 83839Sbill while (canon(tp)<0) 83939Sbill if (tp->t_chan==NULL) { 84039Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 84139Sbill } else { 84239Sbill splx(s); 84339Sbill return(0); 84439Sbill } 84539Sbill splx(s); 84639Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 84739Sbill ; 84839Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 84939Sbill } 85039Sbill 85139Sbill /* 85239Sbill * Called from the device's write routine after it has 85339Sbill * calculated the tty-structure given as argument. 85439Sbill */ 85539Sbill caddr_t 85639Sbill ttwrite(tp) 85739Sbill register struct tty *tp; 85839Sbill { 85939Sbill /* 86039Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 86139Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 86239Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 86339Sbill */ 86439Sbill register char *cp; 86539Sbill register int cc, ce; 86639Sbill register i; 86739Sbill char obuf[OBUFSIZ]; 86839Sbill 86939Sbill if ((tp->t_state&CARR_ON)==0) 87039Sbill return(NULL); 87139Sbill while (u.u_count) { 87239Sbill cc = MIN(u.u_count, OBUFSIZ); 87339Sbill cp = obuf; 87439Sbill iomove(cp, (unsigned)cc, B_WRITE); 87539Sbill if (u.u_error) 87639Sbill break; 877121Sbill (void) spl5(); 87839Sbill while (tp->t_outq.c_cc > TTHIWAT) { 87939Sbill ttstart(tp); 88039Sbill tp->t_state |= ASLEEP; 88139Sbill if (tp->t_chan) { 88239Sbill u.u_base -= cc; 88339Sbill u.u_offset -= cc; 88439Sbill u.u_count += cc; 885121Sbill (void) spl0(); 88639Sbill return((caddr_t)&tp->t_outq); 88739Sbill } 88839Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 88939Sbill } 890121Sbill (void) spl0(); 89139Sbill if (tp->t_flags&LCASE) { 89239Sbill while (cc--) 89339Sbill ttyoutput(*cp++,tp); 89439Sbill continue; 89539Sbill } 89639Sbill while (cc) { 89739Sbill if (tp->t_flags&RAW) 89839Sbill ce=cc; 89939Sbill else { 90039Sbill #ifdef VAX 90139Sbill asm(" scanc r9,(r10),_partab,$077"); 90239Sbill asm(" subl3 r0,r9,r8"); 90339Sbill #else 90439Sbill ce=0; 90539Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 90639Sbill ce++; 90739Sbill #endif 90839Sbill if (ce==0) { 90939Sbill ttyoutput(*cp++,tp); 91039Sbill cc--; 911121Sbill goto check; 91239Sbill } 91339Sbill } 91439Sbill i=b_to_q(cp,ce,&tp->t_outq); 91539Sbill ce-=i; 91639Sbill tk_nout+=ce; 91739Sbill tp->t_col+=ce; 91839Sbill cp+=ce; 91939Sbill cc-=ce; 920121Sbill check: 921121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 922121Sbill (void) spl5(); 92339Sbill while (tp->t_outq.c_cc > TTHIWAT) { 92439Sbill ttstart(tp); 92539Sbill tp->t_state |= ASLEEP; 92639Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 92739Sbill } 928121Sbill (void) spl0(); 92939Sbill } 93039Sbill } 93139Sbill } 93239Sbill ttstart(tp); 93339Sbill return(NULL); 93439Sbill } 935