1*174Sbill /* tty.c 3.4 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*174Sbill tp->t_pgrp = pp->p_pid; 8739Sbill pp->p_pgrp = tp->t_pgrp; 8839Sbill } 8939Sbill tp->t_state &= ~WOPEN; 9039Sbill tp->t_state |= ISOPEN; 91*174Sbill tp->t_line = 0; /* conservative */ 9239Sbill } 9339Sbill 9439Sbill /* 9539Sbill * set default control characters. 9639Sbill */ 9739Sbill ttychars(tp) 9839Sbill register struct tty *tp; 9939Sbill { 100*174Sbill 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; 109*174Sbill /* begin local */ 110*174Sbill tlun.t_suspc = 0377; 111*174Sbill tlun.t_dstopc = 0377; 112*174Sbill tlun.t_rprntc = CTRL(r); 113*174Sbill tlun.t_flushc = CTRL(o); 114*174Sbill tlun.t_werasc = CTRL(w); 115*174Sbill tlun.t_lnextc = CTRL(v); 116*174Sbill tlun.t_lintr = CTRL(c); 117*174Sbill tlun.t_lerase = CTRL(h); 118*174Sbill tlun.t_lkill = CTRL(u); 119*174Sbill tp->t_local = 0; 120*174Sbill tp->t_lstate = 0; 121*174Sbill /* 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; 134*174Sbill 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 */ 158121Sbill nullioctl(tp, cmd, addr) 159121Sbill register struct tty *tp; 160121Sbill caddr_t addr; 161121Sbill { 162121Sbill 163121Sbill return (cmd); 164121Sbill } 165121Sbill 166121Sbill /* 16739Sbill * ioctl system call 16839Sbill * Check legality, execute common code, and switch out to individual 16939Sbill * device routine. 17039Sbill */ 17139Sbill ioctl() 17239Sbill { 17339Sbill register struct file *fp; 17439Sbill register struct inode *ip; 17539Sbill register struct a { 17639Sbill int fdes; 17739Sbill int cmd; 17839Sbill caddr_t cmarg; 17939Sbill } *uap; 18039Sbill register dev_t dev; 18139Sbill register fmt; 18239Sbill 18339Sbill uap = (struct a *)u.u_ap; 18439Sbill if ((fp = getf(uap->fdes)) == NULL) 18539Sbill return; 18639Sbill if (uap->cmd==FIOCLEX) { 18739Sbill u.u_pofile[uap->fdes] |= EXCLOSE; 18839Sbill return; 18939Sbill } 19039Sbill if (uap->cmd==FIONCLEX) { 19139Sbill u.u_pofile[uap->fdes] &= ~EXCLOSE; 19239Sbill return; 19339Sbill } 19439Sbill ip = fp->f_inode; 19539Sbill fmt = ip->i_mode & IFMT; 19639Sbill if (fmt != IFCHR && fmt != IFMPC) { 197*174Sbill /* begin local */ 198*174Sbill if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 199*174Sbill off_t nread = ip->i_size - fp->f_un.f_offset; 200*174Sbill 201*174Sbill if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t))) 202*174Sbill u.u_error = EFAULT; 203*174Sbill } else 204*174Sbill /* end local */ 205*174Sbill u.u_error = ENOTTY; 20639Sbill return; 20739Sbill } 20839Sbill dev = ip->i_un.i_rdev; 20939Sbill u.u_r.r_val1 = 0; 21039Sbill (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); 21139Sbill } 21239Sbill 21339Sbill /* 21439Sbill * Common code for several tty ioctl commands 21539Sbill */ 21639Sbill ttioccomm(com, tp, addr, dev) 21739Sbill register struct tty *tp; 21839Sbill caddr_t addr; 21939Sbill { 22039Sbill unsigned t; 221*174Sbill struct sgttyb iocb; 22239Sbill extern int nldisp; 22339Sbill 22439Sbill switch(com) { 22539Sbill 22639Sbill /* 22739Sbill * get discipline number 22839Sbill */ 22939Sbill case TIOCGETD: 23039Sbill t = tp->t_line; 23139Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 23239Sbill u.u_error = EFAULT; 23339Sbill break; 23439Sbill 23539Sbill /* 23639Sbill * set line discipline 23739Sbill */ 23839Sbill case TIOCSETD: 23939Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 24039Sbill u.u_error = EFAULT; 24139Sbill break; 24239Sbill } 24339Sbill if (t >= nldisp) { 24439Sbill u.u_error = ENXIO; 24539Sbill break; 24639Sbill } 247*174Sbill (void) spl5(); 24839Sbill if (tp->t_line) 24939Sbill (*linesw[tp->t_line].l_close)(tp); 25039Sbill if (t) 25139Sbill (*linesw[t].l_open)(dev, tp, addr); 25239Sbill if (u.u_error==0) 25339Sbill tp->t_line = t; 254*174Sbill (void) spl0(); 25539Sbill break; 25639Sbill 25739Sbill /* 25839Sbill * prevent more opens on channel 25939Sbill */ 26039Sbill case TIOCEXCL: 26139Sbill tp->t_state |= XCLUDE; 26239Sbill break; 26339Sbill 26439Sbill case TIOCNXCL: 26539Sbill tp->t_state &= ~XCLUDE; 26639Sbill break; 26739Sbill 26839Sbill /* 26939Sbill * Set new parameters 27039Sbill */ 27139Sbill case TIOCSETP: 272*174Sbill case TIOCSETN: { 273*174Sbill struct clist tq; 274*174Sbill register c; 275*174Sbill 27639Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 27739Sbill u.u_error = EFAULT; 27839Sbill return(1); 27939Sbill } 280121Sbill (void) spl5(); 281*174Sbill if (tp->t_line == 0) { 282*174Sbill if (com == TIOCSETP) 283*174Sbill wflushtty(tp); 284*174Sbill while (canon(tp)>=0) 285*174Sbill ; 286*174Sbill } else if (tp->t_line == NTTYDISC) { 287*174Sbill if (tp->t_flags&RAW || iocb.sg_flags&RAW || 288*174Sbill com == TIOCSETP) 289*174Sbill wflushtty(tp); 290*174Sbill else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 291*174Sbill if (iocb.sg_flags & CBREAK) { 292*174Sbill catq(&tp->t_rawq, &tp->t_canq); 293*174Sbill tq = tp->t_rawq; 294*174Sbill tp->t_rawq = tp->t_canq; 295*174Sbill tp->t_canq = tq; 296*174Sbill } else { 297*174Sbill tp->t_local |= LPENDIN; 298*174Sbill if (tp->t_canq.c_cc) 299*174Sbill panic("ioccom canq"); 300*174Sbill if (tp->t_chan) 301*174Sbill (void) sdata(tp->t_chan); 302*174Sbill else 303*174Sbill wakeup((caddr_t)&tp->t_rawq); 304*174Sbill } 305*174Sbill } 306*174Sbill } 30739Sbill if ((tp->t_state&SPEEDS)==0) { 308*174Sbill tp->t_ispeed = iocb.sg_ispeed; 309*174Sbill tp->t_ospeed = iocb.sg_ospeed; 31039Sbill } 311*174Sbill tp->t_erase = iocb.sg_erase; 312*174Sbill tp->t_kill = iocb.sg_kill; 313*174Sbill tp->t_flags = iocb.sg_flags; 314121Sbill (void) spl0(); 31539Sbill break; 316*174Sbill } 31739Sbill 31839Sbill /* 31939Sbill * send current parameters to user 32039Sbill */ 32139Sbill case TIOCGETP: 322*174Sbill iocb.sg_ispeed = tp->t_ispeed; 323*174Sbill iocb.sg_ospeed = tp->t_ospeed; 324*174Sbill iocb.sg_erase = tp->t_erase; 325*174Sbill iocb.sg_kill = tp->t_kill; 326*174Sbill 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: 356*174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 35739Sbill u.u_error = EFAULT; 35839Sbill break; 35939Sbill 36039Sbill case TIOCGETC: 361*174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 36239Sbill u.u_error = EFAULT; 36339Sbill break; 36439Sbill 365*174Sbill /* local ioctls */ 366*174Sbill case TIOCSLTC: 367*174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 368*174Sbill u.u_error = EFAULT; 369*174Sbill break; 370*174Sbill 371*174Sbill case TIOCGLTC: 372*174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 373*174Sbill u.u_error = EFAULT; 374*174Sbill break; 375*174Sbill 376*174Sbill case FIONREAD: { 377*174Sbill off_t nread = tp->t_canq.c_cc; 378*174Sbill 379*174Sbill if (tp->t_flags & (RAW|CBREAK)) 380*174Sbill nread += tp->t_rawq.c_cc; 381*174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 382*174Sbill u.u_error = EFAULT; 383*174Sbill break; 384*174Sbill } 385*174Sbill 386*174Sbill /* 387*174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 388*174Sbill */ 389*174Sbill case TIOCSPGRP: 390*174Sbill tp->t_pgrp = (int)addr; 391*174Sbill break; 392*174Sbill 393*174Sbill case TIOCGPGRP: 394*174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 395*174Sbill u.u_error = EFAULT; 396*174Sbill break; 397*174Sbill 398*174Sbill /* 399*174Sbill * Modify local mode word. 400*174Sbill */ 401*174Sbill case TIOCLBIS: 402*174Sbill tp->t_local |= (int)addr; 403*174Sbill break; 404*174Sbill 405*174Sbill case TIOCLBIC: 406*174Sbill tp->t_local &= ~(int)addr; 407*174Sbill break; 408*174Sbill 409*174Sbill case TIOCLSET: 410*174Sbill tp->t_local = (int)addr; 411*174Sbill break; 412*174Sbill 413*174Sbill case TIOCLGET: 414*174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 415*174Sbill u.u_error = EFAULT; 416*174Sbill break; 417*174Sbill 418*174Sbill /* end of locals */ 41939Sbill default: 42039Sbill return(0); 42139Sbill } 42239Sbill return(1); 42339Sbill } 42439Sbill 42539Sbill /* 42639Sbill * Wait for output to drain, then flush input waiting. 42739Sbill */ 42839Sbill wflushtty(tp) 42939Sbill register struct tty *tp; 43039Sbill { 43139Sbill 432121Sbill (void) spl5(); 43339Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 43439Sbill (*tp->t_oproc)(tp); 43539Sbill tp->t_state |= ASLEEP; 43639Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 43739Sbill } 43839Sbill flushtty(tp); 439121Sbill (void) spl0(); 44039Sbill } 44139Sbill 44239Sbill /* 44339Sbill * flush all TTY queues 44439Sbill */ 44539Sbill flushtty(tp) 44639Sbill register struct tty *tp; 44739Sbill { 44839Sbill register s; 44939Sbill 450121Sbill s = spl6(); 45139Sbill while (getc(&tp->t_canq) >= 0) 45239Sbill ; 45339Sbill wakeup((caddr_t)&tp->t_rawq); 45439Sbill wakeup((caddr_t)&tp->t_outq); 45539Sbill tp->t_state &= ~TTSTOP; 45639Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 45739Sbill while (getc(&tp->t_outq) >= 0) 45839Sbill ; 45939Sbill while (getc(&tp->t_rawq) >= 0) 46039Sbill ; 46139Sbill tp->t_delct = 0; 462*174Sbill tp->t_rocount = 0; /* local */ 463*174Sbill tp->t_lstate = 0; /* reset */ 46439Sbill splx(s); 46539Sbill } 46639Sbill 46739Sbill 46839Sbill 46939Sbill /* 47039Sbill * transfer raw input list to canonical list, 47139Sbill * doing erase-kill processing and handling escapes. 47239Sbill * It waits until a full line has been typed in cooked mode, 47339Sbill * or until any character has been typed in raw mode. 47439Sbill */ 47539Sbill canon(tp) 47639Sbill register struct tty *tp; 47739Sbill { 47839Sbill register char *bp; 47939Sbill char *bp1; 48039Sbill register int c; 48139Sbill int mc; 48239Sbill int s; 48339Sbill 48439Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 48539Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 48639Sbill return(-1); 48739Sbill } 48839Sbill s = spl0(); 48939Sbill loop: 49039Sbill bp = &canonb[2]; 49139Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 49239Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 49339Sbill if (c==0377) { 49439Sbill tp->t_delct--; 49539Sbill break; 49639Sbill } 49739Sbill if (bp[-1]!='\\') { 49839Sbill if (c==tp->t_erase) { 49939Sbill if (bp > &canonb[2]) 50039Sbill bp--; 50139Sbill continue; 50239Sbill } 50339Sbill if (c==tp->t_kill) 50439Sbill goto loop; 50539Sbill if (c==tun.t_eofc) 50639Sbill continue; 50739Sbill } else { 50839Sbill mc = maptab[c]; 50939Sbill if (c==tp->t_erase || c==tp->t_kill) 51039Sbill mc = c; 51139Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 51239Sbill if (bp[-2] != '\\') 51339Sbill c = mc; 51439Sbill bp--; 51539Sbill } 51639Sbill } 51739Sbill } 51839Sbill *bp++ = c; 51939Sbill if (bp>=canonb+CANBSIZ) 52039Sbill break; 52139Sbill } 52239Sbill bp1 = &canonb[2]; 523121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 52439Sbill 52539Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 52639Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 52739Sbill tp->t_state &= ~TBLOCK; 52839Sbill ttstart(tp); 52939Sbill } 53039Sbill tp->t_char = 0; 53139Sbill } 53239Sbill 53339Sbill splx(s); 53439Sbill return(0); 53539Sbill } 53639Sbill 53739Sbill 53839Sbill /* 53939Sbill * block transfer input handler. 54039Sbill */ 54139Sbill ttyrend(tp, pb, pe) 54239Sbill register struct tty *tp; 54339Sbill register char *pb, *pe; 54439Sbill { 54539Sbill int tandem; 54639Sbill 54739Sbill tandem = tp->t_flags&TANDEM; 54839Sbill if (tp->t_flags&RAW) { 549121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 55039Sbill if (tp->t_chan) 551121Sbill (void) sdata(tp->t_chan); else 55239Sbill wakeup((caddr_t)&tp->t_rawq); 55339Sbill } else { 55439Sbill tp->t_flags &= ~TANDEM; 55539Sbill while (pb < pe) 55639Sbill ttyinput(*pb++, tp); 55739Sbill tp->t_flags |= tandem; 55839Sbill } 55939Sbill if (tandem) 56039Sbill ttyblock(tp); 56139Sbill } 56239Sbill 56339Sbill /* 56439Sbill * Place a character on raw TTY input queue, putting in delimiters 56539Sbill * and waking up top half as needed. 56639Sbill * Also echo if required. 56739Sbill * The arguments are the character and the appropriate 56839Sbill * tty structure. 56939Sbill */ 57039Sbill ttyinput(c, tp) 57139Sbill register c; 57239Sbill register struct tty *tp; 57339Sbill { 57439Sbill register int t_flags; 57539Sbill register struct chan *cp; 57639Sbill 57739Sbill tk_nin += 1; 57839Sbill c &= 0377; 57939Sbill t_flags = tp->t_flags; 58039Sbill if (t_flags&TANDEM) 58139Sbill ttyblock(tp); 58239Sbill if ((t_flags&RAW)==0) { 58339Sbill c &= 0177; 58439Sbill if (tp->t_state&TTSTOP) { 58539Sbill if (c==tun.t_startc) { 58639Sbill tp->t_state &= ~TTSTOP; 58739Sbill ttstart(tp); 58839Sbill return; 58939Sbill } 59039Sbill if (c==tun.t_stopc) 59139Sbill return; 59239Sbill tp->t_state &= ~TTSTOP; 59339Sbill ttstart(tp); 59439Sbill } else { 59539Sbill if (c==tun.t_stopc) { 59639Sbill tp->t_state |= TTSTOP; 59739Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 59839Sbill return; 59939Sbill } 60039Sbill if (c==tun.t_startc) 60139Sbill return; 60239Sbill } 60339Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 60439Sbill flushtty(tp); 60539Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 60639Sbill if (tp->t_chan) 60739Sbill scontrol(tp->t_chan, M_SIG, c); 60839Sbill else 609*174Sbill gsignal(tp->t_pgrp, c); 61039Sbill return; 61139Sbill } 61239Sbill if (c=='\r' && t_flags&CRMOD) 61339Sbill c = '\n'; 61439Sbill } 61539Sbill if (tp->t_rawq.c_cc>TTYHOG) { 61639Sbill flushtty(tp); 61739Sbill return; 61839Sbill } 61939Sbill if (t_flags&LCASE && c>='A' && c<='Z') 62039Sbill c += 'a'-'A'; 621121Sbill (void) putc(c, &tp->t_rawq); 62239Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 62339Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 62439Sbill tp->t_delct++; 62539Sbill if ((cp=tp->t_chan)!=NULL) 626121Sbill (void) sdata(cp); else 62739Sbill wakeup((caddr_t)&tp->t_rawq); 62839Sbill } 62939Sbill if (t_flags&ECHO) { 63039Sbill ttyoutput(c, tp); 63139Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 63239Sbill ttyoutput('\n', tp); 63339Sbill ttstart(tp); 63439Sbill } 63539Sbill } 63639Sbill 63739Sbill 63839Sbill /* 63939Sbill * Send stop character on input overflow. 64039Sbill */ 64139Sbill ttyblock(tp) 64239Sbill register struct tty *tp; 64339Sbill { 64439Sbill register x; 64539Sbill x = q1.c_cc + q2.c_cc; 64639Sbill if (q1.c_cc > TTYHOG) { 64739Sbill flushtty(tp); 64839Sbill tp->t_state &= ~TBLOCK; 64939Sbill } 65039Sbill if (x >= TTYHOG/2) { 65139Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 65239Sbill tp->t_state |= TBLOCK; 65339Sbill tp->t_char++; 65439Sbill ttstart(tp); 65539Sbill } 65639Sbill } 65739Sbill } 65839Sbill 65939Sbill /* 66039Sbill * put character on TTY output queue, adding delays, 66139Sbill * expanding tabs, and handling the CR/NL bit. 66239Sbill * It is called both from the top half for output, and from 66339Sbill * interrupt level for echoing. 66439Sbill * The arguments are the character and the tty structure. 66539Sbill */ 66639Sbill ttyoutput(c, tp) 66739Sbill register c; 66839Sbill register struct tty *tp; 66939Sbill { 67039Sbill register char *colp; 67139Sbill register ctype; 67239Sbill 67339Sbill /* 67439Sbill * Ignore EOT in normal mode to avoid hanging up 67539Sbill * certain terminals. 67639Sbill * In raw mode dump the char unchanged. 67739Sbill */ 67839Sbill if ((tp->t_flags&RAW)==0) { 67939Sbill c &= 0177; 68039Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 68139Sbill return; 68239Sbill } else { 683121Sbill tk_nout++; 684121Sbill (void) putc(c, &tp->t_outq); 68539Sbill return; 68639Sbill } 68739Sbill 68839Sbill /* 68939Sbill * Turn tabs to spaces as required 69039Sbill */ 69139Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 692121Sbill c = 8 - (tp->t_col & 7); 693121Sbill (void) b_to_q(" ", c, &tp->t_outq); 694121Sbill tp->t_col += c; 695121Sbill tk_nout += c; 69639Sbill return; 69739Sbill } 698121Sbill tk_nout++; 69939Sbill /* 70039Sbill * for upper-case-only terminals, 70139Sbill * generate escapes. 70239Sbill */ 70339Sbill if (tp->t_flags&LCASE) { 70439Sbill colp = "({)}!|^~'`"; 70539Sbill while(*colp++) 70639Sbill if(c == *colp++) { 70739Sbill ttyoutput('\\', tp); 70839Sbill c = colp[-2]; 70939Sbill break; 71039Sbill } 71139Sbill if ('a'<=c && c<='z') 71239Sbill c += 'A' - 'a'; 71339Sbill } 71439Sbill /* 71539Sbill * turn <nl> to <cr><lf> if desired. 71639Sbill */ 71739Sbill if (c=='\n' && tp->t_flags&CRMOD) 71839Sbill ttyoutput('\r', tp); 719121Sbill (void) putc(c, &tp->t_outq); 72039Sbill /* 72139Sbill * Calculate delays. 72239Sbill * The numbers here represent clock ticks 72339Sbill * and are not necessarily optimal for all terminals. 72439Sbill * The delays are indicated by characters above 0200. 72539Sbill * In raw mode there are no delays and the 72639Sbill * transmission path is 8 bits wide. 72739Sbill */ 72839Sbill colp = &tp->t_col; 72939Sbill ctype = partab[c]; 73039Sbill c = 0; 73139Sbill switch (ctype&077) { 73239Sbill 73339Sbill /* ordinary */ 73439Sbill case 0: 73539Sbill (*colp)++; 73639Sbill 73739Sbill /* non-printing */ 73839Sbill case 1: 73939Sbill break; 74039Sbill 74139Sbill /* backspace */ 74239Sbill case 2: 74339Sbill if (*colp) 74439Sbill (*colp)--; 74539Sbill break; 74639Sbill 74739Sbill /* newline */ 74839Sbill case 3: 74939Sbill ctype = (tp->t_flags >> 8) & 03; 75039Sbill if(ctype == 1) { /* tty 37 */ 75139Sbill if (*colp) 75239Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 75339Sbill } else 75439Sbill if(ctype == 2) { /* vt05 */ 75539Sbill c = 6; 75639Sbill } 75739Sbill *colp = 0; 75839Sbill break; 75939Sbill 76039Sbill /* tab */ 76139Sbill case 4: 76239Sbill ctype = (tp->t_flags >> 10) & 03; 76339Sbill if(ctype == 1) { /* tty 37 */ 76439Sbill c = 1 - (*colp | ~07); 76539Sbill if(c < 5) 76639Sbill c = 0; 76739Sbill } 76839Sbill *colp |= 07; 76939Sbill (*colp)++; 77039Sbill break; 77139Sbill 77239Sbill /* vertical motion */ 77339Sbill case 5: 77439Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 77539Sbill c = 0177; 77639Sbill break; 77739Sbill 77839Sbill /* carriage return */ 77939Sbill case 6: 78039Sbill ctype = (tp->t_flags >> 12) & 03; 78139Sbill if(ctype == 1) { /* tn 300 */ 78239Sbill c = 5; 78339Sbill } else if(ctype == 2) { /* ti 700 */ 78439Sbill c = 10; 78539Sbill } else if(ctype == 3) { /* concept 100 */ 78639Sbill int i; 78739Sbill for (i= *colp; i<9; i++) 788121Sbill (void) putc(0177, &tp->t_outq); 78939Sbill } 79039Sbill *colp = 0; 79139Sbill } 79239Sbill if(c) 793121Sbill (void) putc(c|0200, &tp->t_outq); 79439Sbill } 79539Sbill 79639Sbill /* 79739Sbill * Restart typewriter output following a delay 79839Sbill * timeout. 79939Sbill * The name of the routine is passed to the timeout 80039Sbill * subroutine and it is called during a clock interrupt. 80139Sbill */ 80239Sbill ttrstrt(tp) 80339Sbill register struct tty *tp; 80439Sbill { 80539Sbill 80639Sbill tp->t_state &= ~TIMEOUT; 80739Sbill ttstart(tp); 80839Sbill } 80939Sbill 81039Sbill /* 81139Sbill * Start output on the typewriter. It is used from the top half 81239Sbill * after some characters have been put on the output queue, 81339Sbill * from the interrupt routine to transmit the next 81439Sbill * character, and after a timeout has finished. 81539Sbill */ 81639Sbill ttstart(tp) 81739Sbill register struct tty *tp; 81839Sbill { 81939Sbill register s; 82039Sbill 82139Sbill s = spl5(); 82239Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 82339Sbill (*tp->t_oproc)(tp); 82439Sbill splx(s); 82539Sbill } 82639Sbill 82739Sbill /* 82839Sbill * Called from device's read routine after it has 82939Sbill * calculated the tty-structure given as argument. 83039Sbill */ 83139Sbill ttread(tp) 83239Sbill register struct tty *tp; 83339Sbill { 83439Sbill register s; 83539Sbill 83639Sbill if ((tp->t_state&CARR_ON)==0) 83739Sbill return(-1); 83839Sbill s = spl5(); 83939Sbill if (tp->t_canq.c_cc==0) 84039Sbill while (canon(tp)<0) 84139Sbill if (tp->t_chan==NULL) { 84239Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 84339Sbill } else { 84439Sbill splx(s); 84539Sbill return(0); 84639Sbill } 84739Sbill splx(s); 84839Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 84939Sbill ; 85039Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 85139Sbill } 85239Sbill 85339Sbill /* 85439Sbill * Called from the device's write routine after it has 85539Sbill * calculated the tty-structure given as argument. 85639Sbill */ 85739Sbill caddr_t 85839Sbill ttwrite(tp) 85939Sbill register struct tty *tp; 86039Sbill { 86139Sbill /* 86239Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 86339Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 86439Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 86539Sbill */ 86639Sbill register char *cp; 86739Sbill register int cc, ce; 86839Sbill register i; 86939Sbill char obuf[OBUFSIZ]; 87039Sbill 87139Sbill if ((tp->t_state&CARR_ON)==0) 87239Sbill return(NULL); 87339Sbill while (u.u_count) { 87439Sbill cc = MIN(u.u_count, OBUFSIZ); 87539Sbill cp = obuf; 87639Sbill iomove(cp, (unsigned)cc, B_WRITE); 87739Sbill if (u.u_error) 87839Sbill break; 879121Sbill (void) spl5(); 88039Sbill while (tp->t_outq.c_cc > TTHIWAT) { 88139Sbill ttstart(tp); 88239Sbill tp->t_state |= ASLEEP; 88339Sbill if (tp->t_chan) { 88439Sbill u.u_base -= cc; 88539Sbill u.u_offset -= cc; 88639Sbill u.u_count += cc; 887121Sbill (void) spl0(); 88839Sbill return((caddr_t)&tp->t_outq); 88939Sbill } 89039Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 89139Sbill } 892121Sbill (void) spl0(); 89339Sbill if (tp->t_flags&LCASE) { 89439Sbill while (cc--) 89539Sbill ttyoutput(*cp++,tp); 89639Sbill continue; 89739Sbill } 89839Sbill while (cc) { 89939Sbill if (tp->t_flags&RAW) 90039Sbill ce=cc; 90139Sbill else { 90239Sbill #ifdef VAX 90339Sbill asm(" scanc r9,(r10),_partab,$077"); 90439Sbill asm(" subl3 r0,r9,r8"); 90539Sbill #else 90639Sbill ce=0; 90739Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 90839Sbill ce++; 90939Sbill #endif 91039Sbill if (ce==0) { 91139Sbill ttyoutput(*cp++,tp); 91239Sbill cc--; 913121Sbill goto check; 91439Sbill } 91539Sbill } 91639Sbill i=b_to_q(cp,ce,&tp->t_outq); 91739Sbill ce-=i; 91839Sbill tk_nout+=ce; 91939Sbill tp->t_col+=ce; 92039Sbill cp+=ce; 92139Sbill cc-=ce; 922121Sbill check: 923121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 924121Sbill (void) spl5(); 92539Sbill while (tp->t_outq.c_cc > TTHIWAT) { 92639Sbill ttstart(tp); 92739Sbill tp->t_state |= ASLEEP; 92839Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 92939Sbill } 930121Sbill (void) spl0(); 93139Sbill } 93239Sbill } 93339Sbill } 93439Sbill ttstart(tp); 93539Sbill return(NULL); 93639Sbill } 937