1*146Sbill /* tty.c 3.3 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 21*146Sbill /* 22*146Sbill * When running dz's using only SAE (silo alarm) on input 23*146Sbill * it is necessary to call dzrint() at clock interrupt time. 24*146Sbill * This is unsafe unless spl5()s in tty code are changed to 25*146Sbill * spl6()s to block clock interrupts. Note that the dh driver 26*146Sbill * currently in use works the same way as the dz, even though 27*146Sbill * we could try to more intelligently manage its silo. 28*146Sbill * Thus don't take this out if you have no dz's unless you 29*146Sbill * change clock.c and dhtimer(). 30*146Sbill */ 31*146Sbill #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; 8639Sbill if (tp->t_pgrp==0) 8739Sbill tp->t_pgrp = pp->p_pid; 8839Sbill pp->p_pgrp = tp->t_pgrp; 8939Sbill } 9039Sbill tp->t_state &= ~WOPEN; 9139Sbill tp->t_state |= ISOPEN; 9239Sbill } 9339Sbill 9439Sbill 9539Sbill /* 9639Sbill * set default control characters. 9739Sbill */ 9839Sbill ttychars(tp) 9939Sbill register struct tty *tp; 10039Sbill { 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; 10939Sbill } 11039Sbill 11139Sbill /* 11239Sbill * clean tp on last close 11339Sbill */ 11439Sbill ttyclose(tp) 11539Sbill register struct tty *tp; 11639Sbill { 11739Sbill 11839Sbill tp->t_pgrp = 0; 11939Sbill wflushtty(tp); 12039Sbill tp->t_state = 0; 12139Sbill } 12239Sbill 12339Sbill /* 12439Sbill * stty/gtty writearound 12539Sbill */ 12639Sbill stty() 12739Sbill { 12839Sbill u.u_arg[2] = u.u_arg[1]; 12939Sbill u.u_arg[1] = TIOCSETP; 13039Sbill ioctl(); 13139Sbill } 13239Sbill 13339Sbill gtty() 13439Sbill { 13539Sbill u.u_arg[2] = u.u_arg[1]; 13639Sbill u.u_arg[1] = TIOCGETP; 13739Sbill ioctl(); 13839Sbill } 13939Sbill 14039Sbill /* 141121Sbill * Do nothing specific version of line 142121Sbill * discipline specific ioctl command. 143121Sbill */ 144121Sbill nullioctl(tp, cmd, addr) 145121Sbill register struct tty *tp; 146121Sbill caddr_t addr; 147121Sbill { 148121Sbill 149121Sbill return (cmd); 150121Sbill } 151121Sbill 152121Sbill /* 15339Sbill * ioctl system call 15439Sbill * Check legality, execute common code, and switch out to individual 15539Sbill * device routine. 15639Sbill */ 15739Sbill ioctl() 15839Sbill { 15939Sbill register struct file *fp; 16039Sbill register struct inode *ip; 16139Sbill register struct a { 16239Sbill int fdes; 16339Sbill int cmd; 16439Sbill caddr_t cmarg; 16539Sbill } *uap; 16639Sbill register dev_t dev; 16739Sbill register fmt; 16839Sbill 16939Sbill uap = (struct a *)u.u_ap; 17039Sbill if ((fp = getf(uap->fdes)) == NULL) 17139Sbill return; 17239Sbill if (uap->cmd==FIOCLEX) { 17339Sbill u.u_pofile[uap->fdes] |= EXCLOSE; 17439Sbill return; 17539Sbill } 17639Sbill if (uap->cmd==FIONCLEX) { 17739Sbill u.u_pofile[uap->fdes] &= ~EXCLOSE; 17839Sbill return; 17939Sbill } 18039Sbill ip = fp->f_inode; 18139Sbill fmt = ip->i_mode & IFMT; 18239Sbill if (fmt != IFCHR && fmt != IFMPC) { 18339Sbill u.u_error = ENOTTY; 18439Sbill return; 18539Sbill } 18639Sbill dev = ip->i_un.i_rdev; 18739Sbill u.u_r.r_val1 = 0; 18839Sbill (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); 18939Sbill } 19039Sbill 19139Sbill /* 19239Sbill * Common code for several tty ioctl commands 19339Sbill */ 19439Sbill ttioccomm(com, tp, addr, dev) 19539Sbill register struct tty *tp; 19639Sbill caddr_t addr; 19739Sbill { 19839Sbill unsigned t; 19939Sbill struct ttiocb iocb; 20039Sbill extern int nldisp; 201121Sbill register s; 20239Sbill 20339Sbill switch(com) { 20439Sbill 20539Sbill /* 20639Sbill * get discipline number 20739Sbill */ 20839Sbill case TIOCGETD: 20939Sbill t = tp->t_line; 21039Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 21139Sbill u.u_error = EFAULT; 21239Sbill break; 21339Sbill 21439Sbill /* 21539Sbill * set line discipline 21639Sbill */ 21739Sbill case TIOCSETD: 21839Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 21939Sbill u.u_error = EFAULT; 22039Sbill break; 22139Sbill } 22239Sbill if (t >= nldisp) { 22339Sbill u.u_error = ENXIO; 22439Sbill break; 22539Sbill } 226121Sbill s = spl5(); 22739Sbill if (tp->t_line) 22839Sbill (*linesw[tp->t_line].l_close)(tp); 22939Sbill if (t) 23039Sbill (*linesw[t].l_open)(dev, tp, addr); 23139Sbill if (u.u_error==0) 23239Sbill tp->t_line = t; 233121Sbill splx(s); 23439Sbill break; 23539Sbill 23639Sbill /* 23739Sbill * prevent more opens on channel 23839Sbill */ 23939Sbill case TIOCEXCL: 24039Sbill tp->t_state |= XCLUDE; 24139Sbill break; 24239Sbill 24339Sbill case TIOCNXCL: 24439Sbill tp->t_state &= ~XCLUDE; 24539Sbill break; 24639Sbill 24739Sbill /* 24839Sbill * Set new parameters 24939Sbill */ 25039Sbill case TIOCSETP: 25139Sbill wflushtty(tp); 25239Sbill case TIOCSETN: 25339Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 25439Sbill u.u_error = EFAULT; 25539Sbill return(1); 25639Sbill } 257121Sbill (void) spl5(); 25839Sbill while (canon(tp)>=0) 25939Sbill ; 26039Sbill if ((tp->t_state&SPEEDS)==0) { 26139Sbill tp->t_ispeed = iocb.ioc_ispeed; 26239Sbill tp->t_ospeed = iocb.ioc_ospeed; 26339Sbill } 26439Sbill tp->t_erase = iocb.ioc_erase; 26539Sbill tp->t_kill = iocb.ioc_kill; 26639Sbill tp->t_flags = iocb.ioc_flags; 267121Sbill (void) spl0(); 26839Sbill break; 26939Sbill 27039Sbill /* 27139Sbill * send current parameters to user 27239Sbill */ 27339Sbill case TIOCGETP: 27439Sbill iocb.ioc_ispeed = tp->t_ispeed; 27539Sbill iocb.ioc_ospeed = tp->t_ospeed; 27639Sbill iocb.ioc_erase = tp->t_erase; 27739Sbill iocb.ioc_kill = tp->t_kill; 27839Sbill iocb.ioc_flags = tp->t_flags; 27939Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 28039Sbill u.u_error = EFAULT; 28139Sbill break; 28239Sbill 28339Sbill /* 28439Sbill * Hang up line on last close 28539Sbill */ 28639Sbill 28739Sbill case TIOCHPCL: 28839Sbill tp->t_state |= HUPCLS; 28939Sbill break; 29039Sbill 29139Sbill case TIOCFLUSH: 29239Sbill flushtty(tp); 29339Sbill break; 29439Sbill 29539Sbill /* 29639Sbill * ioctl entries to line discipline 29739Sbill */ 29839Sbill case DIOCSETP: 29939Sbill case DIOCGETP: 300121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 301121Sbill u.u_error = ENOTTY; 30239Sbill break; 30339Sbill 30439Sbill /* 30539Sbill * set and fetch special characters 30639Sbill */ 30739Sbill case TIOCSETC: 30839Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tc))) 30939Sbill u.u_error = EFAULT; 31039Sbill break; 31139Sbill 31239Sbill case TIOCGETC: 31339Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tc))) 31439Sbill u.u_error = EFAULT; 31539Sbill break; 31639Sbill 31739Sbill default: 31839Sbill return(0); 31939Sbill } 32039Sbill return(1); 32139Sbill } 32239Sbill 32339Sbill /* 32439Sbill * Wait for output to drain, then flush input waiting. 32539Sbill */ 32639Sbill wflushtty(tp) 32739Sbill register struct tty *tp; 32839Sbill { 32939Sbill 330121Sbill (void) spl5(); 33139Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 33239Sbill (*tp->t_oproc)(tp); 33339Sbill tp->t_state |= ASLEEP; 33439Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 33539Sbill } 33639Sbill flushtty(tp); 337121Sbill (void) spl0(); 33839Sbill } 33939Sbill 34039Sbill /* 34139Sbill * flush all TTY queues 34239Sbill */ 34339Sbill flushtty(tp) 34439Sbill register struct tty *tp; 34539Sbill { 34639Sbill register s; 34739Sbill 348121Sbill s = spl6(); 34939Sbill while (getc(&tp->t_canq) >= 0) 35039Sbill ; 35139Sbill wakeup((caddr_t)&tp->t_rawq); 35239Sbill wakeup((caddr_t)&tp->t_outq); 35339Sbill tp->t_state &= ~TTSTOP; 35439Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 35539Sbill while (getc(&tp->t_outq) >= 0) 35639Sbill ; 35739Sbill while (getc(&tp->t_rawq) >= 0) 35839Sbill ; 35939Sbill tp->t_delct = 0; 36039Sbill splx(s); 36139Sbill } 36239Sbill 36339Sbill 36439Sbill 36539Sbill /* 36639Sbill * transfer raw input list to canonical list, 36739Sbill * doing erase-kill processing and handling escapes. 36839Sbill * It waits until a full line has been typed in cooked mode, 36939Sbill * or until any character has been typed in raw mode. 37039Sbill */ 37139Sbill canon(tp) 37239Sbill register struct tty *tp; 37339Sbill { 37439Sbill register char *bp; 37539Sbill char *bp1; 37639Sbill register int c; 37739Sbill int mc; 37839Sbill int s; 37939Sbill 38039Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 38139Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 38239Sbill return(-1); 38339Sbill } 38439Sbill s = spl0(); 38539Sbill loop: 38639Sbill bp = &canonb[2]; 38739Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 38839Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 38939Sbill if (c==0377) { 39039Sbill tp->t_delct--; 39139Sbill break; 39239Sbill } 39339Sbill if (bp[-1]!='\\') { 39439Sbill if (c==tp->t_erase) { 39539Sbill if (bp > &canonb[2]) 39639Sbill bp--; 39739Sbill continue; 39839Sbill } 39939Sbill if (c==tp->t_kill) 40039Sbill goto loop; 40139Sbill if (c==tun.t_eofc) 40239Sbill continue; 40339Sbill } else { 40439Sbill mc = maptab[c]; 40539Sbill if (c==tp->t_erase || c==tp->t_kill) 40639Sbill mc = c; 40739Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 40839Sbill if (bp[-2] != '\\') 40939Sbill c = mc; 41039Sbill bp--; 41139Sbill } 41239Sbill } 41339Sbill } 41439Sbill *bp++ = c; 41539Sbill if (bp>=canonb+CANBSIZ) 41639Sbill break; 41739Sbill } 41839Sbill bp1 = &canonb[2]; 419121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 42039Sbill 42139Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 42239Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 42339Sbill tp->t_state &= ~TBLOCK; 42439Sbill ttstart(tp); 42539Sbill } 42639Sbill tp->t_char = 0; 42739Sbill } 42839Sbill 42939Sbill splx(s); 43039Sbill return(0); 43139Sbill } 43239Sbill 43339Sbill 43439Sbill /* 43539Sbill * block transfer input handler. 43639Sbill */ 43739Sbill ttyrend(tp, pb, pe) 43839Sbill register struct tty *tp; 43939Sbill register char *pb, *pe; 44039Sbill { 44139Sbill int tandem; 44239Sbill 44339Sbill tandem = tp->t_flags&TANDEM; 44439Sbill if (tp->t_flags&RAW) { 445121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 44639Sbill if (tp->t_chan) 447121Sbill (void) sdata(tp->t_chan); else 44839Sbill wakeup((caddr_t)&tp->t_rawq); 44939Sbill } else { 45039Sbill tp->t_flags &= ~TANDEM; 45139Sbill while (pb < pe) 45239Sbill ttyinput(*pb++, tp); 45339Sbill tp->t_flags |= tandem; 45439Sbill } 45539Sbill if (tandem) 45639Sbill ttyblock(tp); 45739Sbill } 45839Sbill 45939Sbill /* 46039Sbill * Place a character on raw TTY input queue, putting in delimiters 46139Sbill * and waking up top half as needed. 46239Sbill * Also echo if required. 46339Sbill * The arguments are the character and the appropriate 46439Sbill * tty structure. 46539Sbill */ 46639Sbill ttyinput(c, tp) 46739Sbill register c; 46839Sbill register struct tty *tp; 46939Sbill { 47039Sbill register int t_flags; 47139Sbill register struct chan *cp; 47239Sbill 47339Sbill tk_nin += 1; 47439Sbill c &= 0377; 47539Sbill t_flags = tp->t_flags; 47639Sbill if (t_flags&TANDEM) 47739Sbill ttyblock(tp); 47839Sbill if ((t_flags&RAW)==0) { 47939Sbill c &= 0177; 48039Sbill if (tp->t_state&TTSTOP) { 48139Sbill if (c==tun.t_startc) { 48239Sbill tp->t_state &= ~TTSTOP; 48339Sbill ttstart(tp); 48439Sbill return; 48539Sbill } 48639Sbill if (c==tun.t_stopc) 48739Sbill return; 48839Sbill tp->t_state &= ~TTSTOP; 48939Sbill ttstart(tp); 49039Sbill } else { 49139Sbill if (c==tun.t_stopc) { 49239Sbill tp->t_state |= TTSTOP; 49339Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 49439Sbill return; 49539Sbill } 49639Sbill if (c==tun.t_startc) 49739Sbill return; 49839Sbill } 49939Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 50039Sbill flushtty(tp); 50139Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 50239Sbill if (tp->t_chan) 50339Sbill scontrol(tp->t_chan, M_SIG, c); 50439Sbill else 50539Sbill signal(tp->t_pgrp, c); 50639Sbill return; 50739Sbill } 50839Sbill if (c=='\r' && t_flags&CRMOD) 50939Sbill c = '\n'; 51039Sbill } 51139Sbill if (tp->t_rawq.c_cc>TTYHOG) { 51239Sbill flushtty(tp); 51339Sbill return; 51439Sbill } 51539Sbill if (t_flags&LCASE && c>='A' && c<='Z') 51639Sbill c += 'a'-'A'; 517121Sbill (void) putc(c, &tp->t_rawq); 51839Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 51939Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 52039Sbill tp->t_delct++; 52139Sbill if ((cp=tp->t_chan)!=NULL) 522121Sbill (void) sdata(cp); else 52339Sbill wakeup((caddr_t)&tp->t_rawq); 52439Sbill } 52539Sbill if (t_flags&ECHO) { 52639Sbill ttyoutput(c, tp); 52739Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 52839Sbill ttyoutput('\n', tp); 52939Sbill ttstart(tp); 53039Sbill } 53139Sbill } 53239Sbill 53339Sbill 53439Sbill /* 53539Sbill * Send stop character on input overflow. 53639Sbill */ 53739Sbill ttyblock(tp) 53839Sbill register struct tty *tp; 53939Sbill { 54039Sbill register x; 54139Sbill x = q1.c_cc + q2.c_cc; 54239Sbill if (q1.c_cc > TTYHOG) { 54339Sbill flushtty(tp); 54439Sbill tp->t_state &= ~TBLOCK; 54539Sbill } 54639Sbill if (x >= TTYHOG/2) { 54739Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 54839Sbill tp->t_state |= TBLOCK; 54939Sbill tp->t_char++; 55039Sbill ttstart(tp); 55139Sbill } 55239Sbill } 55339Sbill } 55439Sbill 55539Sbill /* 55639Sbill * put character on TTY output queue, adding delays, 55739Sbill * expanding tabs, and handling the CR/NL bit. 55839Sbill * It is called both from the top half for output, and from 55939Sbill * interrupt level for echoing. 56039Sbill * The arguments are the character and the tty structure. 56139Sbill */ 56239Sbill ttyoutput(c, tp) 56339Sbill register c; 56439Sbill register struct tty *tp; 56539Sbill { 56639Sbill register char *colp; 56739Sbill register ctype; 56839Sbill 56939Sbill /* 57039Sbill * Ignore EOT in normal mode to avoid hanging up 57139Sbill * certain terminals. 57239Sbill * In raw mode dump the char unchanged. 57339Sbill */ 57439Sbill if ((tp->t_flags&RAW)==0) { 57539Sbill c &= 0177; 57639Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 57739Sbill return; 57839Sbill } else { 579121Sbill tk_nout++; 580121Sbill (void) putc(c, &tp->t_outq); 58139Sbill return; 58239Sbill } 58339Sbill 58439Sbill /* 58539Sbill * Turn tabs to spaces as required 58639Sbill */ 58739Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 588121Sbill c = 8 - (tp->t_col & 7); 589121Sbill (void) b_to_q(" ", c, &tp->t_outq); 590121Sbill tp->t_col += c; 591121Sbill tk_nout += c; 59239Sbill return; 59339Sbill } 594121Sbill tk_nout++; 59539Sbill /* 59639Sbill * for upper-case-only terminals, 59739Sbill * generate escapes. 59839Sbill */ 59939Sbill if (tp->t_flags&LCASE) { 60039Sbill colp = "({)}!|^~'`"; 60139Sbill while(*colp++) 60239Sbill if(c == *colp++) { 60339Sbill ttyoutput('\\', tp); 60439Sbill c = colp[-2]; 60539Sbill break; 60639Sbill } 60739Sbill if ('a'<=c && c<='z') 60839Sbill c += 'A' - 'a'; 60939Sbill } 61039Sbill /* 61139Sbill * turn <nl> to <cr><lf> if desired. 61239Sbill */ 61339Sbill if (c=='\n' && tp->t_flags&CRMOD) 61439Sbill ttyoutput('\r', tp); 615121Sbill (void) putc(c, &tp->t_outq); 61639Sbill /* 61739Sbill * Calculate delays. 61839Sbill * The numbers here represent clock ticks 61939Sbill * and are not necessarily optimal for all terminals. 62039Sbill * The delays are indicated by characters above 0200. 62139Sbill * In raw mode there are no delays and the 62239Sbill * transmission path is 8 bits wide. 62339Sbill */ 62439Sbill colp = &tp->t_col; 62539Sbill ctype = partab[c]; 62639Sbill c = 0; 62739Sbill switch (ctype&077) { 62839Sbill 62939Sbill /* ordinary */ 63039Sbill case 0: 63139Sbill (*colp)++; 63239Sbill 63339Sbill /* non-printing */ 63439Sbill case 1: 63539Sbill break; 63639Sbill 63739Sbill /* backspace */ 63839Sbill case 2: 63939Sbill if (*colp) 64039Sbill (*colp)--; 64139Sbill break; 64239Sbill 64339Sbill /* newline */ 64439Sbill case 3: 64539Sbill ctype = (tp->t_flags >> 8) & 03; 64639Sbill if(ctype == 1) { /* tty 37 */ 64739Sbill if (*colp) 64839Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 64939Sbill } else 65039Sbill if(ctype == 2) { /* vt05 */ 65139Sbill c = 6; 65239Sbill } 65339Sbill *colp = 0; 65439Sbill break; 65539Sbill 65639Sbill /* tab */ 65739Sbill case 4: 65839Sbill ctype = (tp->t_flags >> 10) & 03; 65939Sbill if(ctype == 1) { /* tty 37 */ 66039Sbill c = 1 - (*colp | ~07); 66139Sbill if(c < 5) 66239Sbill c = 0; 66339Sbill } 66439Sbill *colp |= 07; 66539Sbill (*colp)++; 66639Sbill break; 66739Sbill 66839Sbill /* vertical motion */ 66939Sbill case 5: 67039Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 67139Sbill c = 0177; 67239Sbill break; 67339Sbill 67439Sbill /* carriage return */ 67539Sbill case 6: 67639Sbill ctype = (tp->t_flags >> 12) & 03; 67739Sbill if(ctype == 1) { /* tn 300 */ 67839Sbill c = 5; 67939Sbill } else if(ctype == 2) { /* ti 700 */ 68039Sbill c = 10; 68139Sbill } else if(ctype == 3) { /* concept 100 */ 68239Sbill int i; 68339Sbill for (i= *colp; i<9; i++) 684121Sbill (void) putc(0177, &tp->t_outq); 68539Sbill } 68639Sbill *colp = 0; 68739Sbill } 68839Sbill if(c) 689121Sbill (void) putc(c|0200, &tp->t_outq); 69039Sbill } 69139Sbill 69239Sbill /* 69339Sbill * Restart typewriter output following a delay 69439Sbill * timeout. 69539Sbill * The name of the routine is passed to the timeout 69639Sbill * subroutine and it is called during a clock interrupt. 69739Sbill */ 69839Sbill ttrstrt(tp) 69939Sbill register struct tty *tp; 70039Sbill { 70139Sbill 70239Sbill tp->t_state &= ~TIMEOUT; 70339Sbill ttstart(tp); 70439Sbill } 70539Sbill 70639Sbill /* 70739Sbill * Start output on the typewriter. It is used from the top half 70839Sbill * after some characters have been put on the output queue, 70939Sbill * from the interrupt routine to transmit the next 71039Sbill * character, and after a timeout has finished. 71139Sbill */ 71239Sbill ttstart(tp) 71339Sbill register struct tty *tp; 71439Sbill { 71539Sbill register s; 71639Sbill 71739Sbill s = spl5(); 71839Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 71939Sbill (*tp->t_oproc)(tp); 72039Sbill splx(s); 72139Sbill } 72239Sbill 72339Sbill /* 72439Sbill * Called from device's read routine after it has 72539Sbill * calculated the tty-structure given as argument. 72639Sbill */ 72739Sbill ttread(tp) 72839Sbill register struct tty *tp; 72939Sbill { 73039Sbill register s; 73139Sbill 73239Sbill if ((tp->t_state&CARR_ON)==0) 73339Sbill return(-1); 73439Sbill s = spl5(); 73539Sbill if (tp->t_canq.c_cc==0) 73639Sbill while (canon(tp)<0) 73739Sbill if (tp->t_chan==NULL) { 73839Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 73939Sbill } else { 74039Sbill splx(s); 74139Sbill return(0); 74239Sbill } 74339Sbill splx(s); 74439Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 74539Sbill ; 74639Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 74739Sbill } 74839Sbill 74939Sbill /* 75039Sbill * Called from the device's write routine after it has 75139Sbill * calculated the tty-structure given as argument. 75239Sbill */ 75339Sbill caddr_t 75439Sbill ttwrite(tp) 75539Sbill register struct tty *tp; 75639Sbill { 75739Sbill /* 75839Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 75939Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 76039Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 76139Sbill */ 76239Sbill register char *cp; 76339Sbill register int cc, ce; 76439Sbill register i; 76539Sbill char obuf[OBUFSIZ]; 76639Sbill 76739Sbill if ((tp->t_state&CARR_ON)==0) 76839Sbill return(NULL); 76939Sbill while (u.u_count) { 77039Sbill cc = MIN(u.u_count, OBUFSIZ); 77139Sbill cp = obuf; 77239Sbill iomove(cp, (unsigned)cc, B_WRITE); 77339Sbill if (u.u_error) 77439Sbill break; 775121Sbill (void) spl5(); 77639Sbill while (tp->t_outq.c_cc > TTHIWAT) { 77739Sbill ttstart(tp); 77839Sbill tp->t_state |= ASLEEP; 77939Sbill if (tp->t_chan) { 78039Sbill u.u_base -= cc; 78139Sbill u.u_offset -= cc; 78239Sbill u.u_count += cc; 783121Sbill (void) spl0(); 78439Sbill return((caddr_t)&tp->t_outq); 78539Sbill } 78639Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 78739Sbill } 788121Sbill (void) spl0(); 78939Sbill if (tp->t_flags&LCASE) { 79039Sbill while (cc--) 79139Sbill ttyoutput(*cp++,tp); 79239Sbill continue; 79339Sbill } 79439Sbill while (cc) { 79539Sbill if (tp->t_flags&RAW) 79639Sbill ce=cc; 79739Sbill else { 79839Sbill #ifdef VAX 79939Sbill asm(" scanc r9,(r10),_partab,$077"); 80039Sbill asm(" subl3 r0,r9,r8"); 80139Sbill #else 80239Sbill ce=0; 80339Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 80439Sbill ce++; 80539Sbill #endif 80639Sbill if (ce==0) { 80739Sbill ttyoutput(*cp++,tp); 80839Sbill cc--; 809121Sbill goto check; 81039Sbill } 81139Sbill } 81239Sbill i=b_to_q(cp,ce,&tp->t_outq); 81339Sbill ce-=i; 81439Sbill tk_nout+=ce; 81539Sbill tp->t_col+=ce; 81639Sbill cp+=ce; 81739Sbill cc-=ce; 818121Sbill if (i == 0) 819121Sbill continue; 820121Sbill check: 821121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 822121Sbill (void) spl5(); 82339Sbill while (tp->t_outq.c_cc > TTHIWAT) { 82439Sbill ttstart(tp); 82539Sbill tp->t_state |= ASLEEP; 82639Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 82739Sbill } 828121Sbill (void) spl0(); 82939Sbill } 83039Sbill } 83139Sbill } 83239Sbill ttstart(tp); 83339Sbill return(NULL); 83439Sbill } 835