1*121Sbill /* tty.c 3.2 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 2139Sbill 2239Sbill /* 2339Sbill * Input mapping table-- if an entry is non-zero, when the 2439Sbill * corresponding character is typed preceded by "\" the escape 2539Sbill * sequence is replaced by the table value. Mostly used for 2639Sbill * upper-case only terminals. 2739Sbill */ 2839Sbill 2939Sbill char maptab[] ={ 3039Sbill 000,000,000,000,000,000,000,000, 3139Sbill 000,000,000,000,000,000,000,000, 3239Sbill 000,000,000,000,000,000,000,000, 3339Sbill 000,000,000,000,000,000,000,000, 3439Sbill 000,'|',000,000,000,000,000,'`', 3539Sbill '{','}',000,000,000,000,000,000, 3639Sbill 000,000,000,000,000,000,000,000, 3739Sbill 000,000,000,000,000,000,000,000, 3839Sbill 000,000,000,000,000,000,000,000, 3939Sbill 000,000,000,000,000,000,000,000, 4039Sbill 000,000,000,000,000,000,000,000, 4139Sbill 000,000,000,000,000,000,'~',000, 4239Sbill 000,'A','B','C','D','E','F','G', 4339Sbill 'H','I','J','K','L','M','N','O', 4439Sbill 'P','Q','R','S','T','U','V','W', 4539Sbill 'X','Y','Z',000,000,000,000,000, 4639Sbill }; 4739Sbill 4839Sbill 4939Sbill /* 5039Sbill * shorthand 5139Sbill */ 5239Sbill #define q1 tp->t_rawq 5339Sbill #define q2 tp->t_canq 5439Sbill #define q3 tp->t_outq 5539Sbill #define q4 tp->t_un.t_ctlq 5639Sbill 5739Sbill #define OBUFSIZ 100 5839Sbill 5939Sbill /* 6039Sbill * routine called on first teletype open. 6139Sbill * establishes a process group for distribution 6239Sbill * of quits and interrupts from the tty. 6339Sbill */ 6439Sbill ttyopen(dev, tp) 6539Sbill dev_t dev; 6639Sbill register struct tty *tp; 6739Sbill { 6839Sbill register struct proc *pp; 6939Sbill 7039Sbill pp = u.u_procp; 7139Sbill tp->t_dev = dev; 7239Sbill if(pp->p_pgrp == 0) { 7339Sbill u.u_ttyp = tp; 7439Sbill u.u_ttyd = dev; 7539Sbill if (tp->t_pgrp==0) 7639Sbill tp->t_pgrp = pp->p_pid; 7739Sbill pp->p_pgrp = tp->t_pgrp; 7839Sbill } 7939Sbill tp->t_state &= ~WOPEN; 8039Sbill tp->t_state |= ISOPEN; 8139Sbill } 8239Sbill 8339Sbill 8439Sbill /* 8539Sbill * set default control characters. 8639Sbill */ 8739Sbill ttychars(tp) 8839Sbill register struct tty *tp; 8939Sbill { 9039Sbill tun.t_intrc = CINTR; 9139Sbill tun.t_quitc = CQUIT; 9239Sbill tun.t_startc = CSTART; 9339Sbill tun.t_stopc = CSTOP; 9439Sbill tun.t_eofc = CEOT; 9539Sbill tun.t_brkc = CBRK; 9639Sbill tp->t_erase = CERASE; 9739Sbill tp->t_kill = CKILL; 9839Sbill } 9939Sbill 10039Sbill /* 10139Sbill * clean tp on last close 10239Sbill */ 10339Sbill ttyclose(tp) 10439Sbill register struct tty *tp; 10539Sbill { 10639Sbill 10739Sbill tp->t_pgrp = 0; 10839Sbill wflushtty(tp); 10939Sbill tp->t_state = 0; 11039Sbill } 11139Sbill 11239Sbill /* 11339Sbill * stty/gtty writearound 11439Sbill */ 11539Sbill stty() 11639Sbill { 11739Sbill u.u_arg[2] = u.u_arg[1]; 11839Sbill u.u_arg[1] = TIOCSETP; 11939Sbill ioctl(); 12039Sbill } 12139Sbill 12239Sbill gtty() 12339Sbill { 12439Sbill u.u_arg[2] = u.u_arg[1]; 12539Sbill u.u_arg[1] = TIOCGETP; 12639Sbill ioctl(); 12739Sbill } 12839Sbill 12939Sbill /* 130*121Sbill * Do nothing specific version of line 131*121Sbill * discipline specific ioctl command. 132*121Sbill */ 133*121Sbill nullioctl(tp, cmd, addr) 134*121Sbill register struct tty *tp; 135*121Sbill caddr_t addr; 136*121Sbill { 137*121Sbill 138*121Sbill return (cmd); 139*121Sbill } 140*121Sbill 141*121Sbill /* 14239Sbill * ioctl system call 14339Sbill * Check legality, execute common code, and switch out to individual 14439Sbill * device routine. 14539Sbill */ 14639Sbill ioctl() 14739Sbill { 14839Sbill register struct file *fp; 14939Sbill register struct inode *ip; 15039Sbill register struct a { 15139Sbill int fdes; 15239Sbill int cmd; 15339Sbill caddr_t cmarg; 15439Sbill } *uap; 15539Sbill register dev_t dev; 15639Sbill register fmt; 15739Sbill 15839Sbill uap = (struct a *)u.u_ap; 15939Sbill if ((fp = getf(uap->fdes)) == NULL) 16039Sbill return; 16139Sbill if (uap->cmd==FIOCLEX) { 16239Sbill u.u_pofile[uap->fdes] |= EXCLOSE; 16339Sbill return; 16439Sbill } 16539Sbill if (uap->cmd==FIONCLEX) { 16639Sbill u.u_pofile[uap->fdes] &= ~EXCLOSE; 16739Sbill return; 16839Sbill } 16939Sbill ip = fp->f_inode; 17039Sbill fmt = ip->i_mode & IFMT; 17139Sbill if (fmt != IFCHR && fmt != IFMPC) { 17239Sbill u.u_error = ENOTTY; 17339Sbill return; 17439Sbill } 17539Sbill dev = ip->i_un.i_rdev; 17639Sbill u.u_r.r_val1 = 0; 17739Sbill (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); 17839Sbill } 17939Sbill 18039Sbill /* 18139Sbill * Common code for several tty ioctl commands 18239Sbill */ 18339Sbill ttioccomm(com, tp, addr, dev) 18439Sbill register struct tty *tp; 18539Sbill caddr_t addr; 18639Sbill { 18739Sbill unsigned t; 18839Sbill struct ttiocb iocb; 18939Sbill extern int nldisp; 190*121Sbill register s; 19139Sbill 19239Sbill switch(com) { 19339Sbill 19439Sbill /* 19539Sbill * get discipline number 19639Sbill */ 19739Sbill case TIOCGETD: 19839Sbill t = tp->t_line; 19939Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 20039Sbill u.u_error = EFAULT; 20139Sbill break; 20239Sbill 20339Sbill /* 20439Sbill * set line discipline 20539Sbill */ 20639Sbill case TIOCSETD: 20739Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 20839Sbill u.u_error = EFAULT; 20939Sbill break; 21039Sbill } 21139Sbill if (t >= nldisp) { 21239Sbill u.u_error = ENXIO; 21339Sbill break; 21439Sbill } 215*121Sbill s = spl5(); 21639Sbill if (tp->t_line) 21739Sbill (*linesw[tp->t_line].l_close)(tp); 21839Sbill if (t) 21939Sbill (*linesw[t].l_open)(dev, tp, addr); 22039Sbill if (u.u_error==0) 22139Sbill tp->t_line = t; 222*121Sbill splx(s); 22339Sbill break; 22439Sbill 22539Sbill /* 22639Sbill * prevent more opens on channel 22739Sbill */ 22839Sbill case TIOCEXCL: 22939Sbill tp->t_state |= XCLUDE; 23039Sbill break; 23139Sbill 23239Sbill case TIOCNXCL: 23339Sbill tp->t_state &= ~XCLUDE; 23439Sbill break; 23539Sbill 23639Sbill /* 23739Sbill * Set new parameters 23839Sbill */ 23939Sbill case TIOCSETP: 24039Sbill wflushtty(tp); 24139Sbill case TIOCSETN: 24239Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 24339Sbill u.u_error = EFAULT; 24439Sbill return(1); 24539Sbill } 246*121Sbill (void) spl5(); 24739Sbill while (canon(tp)>=0) 24839Sbill ; 24939Sbill if ((tp->t_state&SPEEDS)==0) { 25039Sbill tp->t_ispeed = iocb.ioc_ispeed; 25139Sbill tp->t_ospeed = iocb.ioc_ospeed; 25239Sbill } 25339Sbill tp->t_erase = iocb.ioc_erase; 25439Sbill tp->t_kill = iocb.ioc_kill; 25539Sbill tp->t_flags = iocb.ioc_flags; 256*121Sbill (void) spl0(); 25739Sbill break; 25839Sbill 25939Sbill /* 26039Sbill * send current parameters to user 26139Sbill */ 26239Sbill case TIOCGETP: 26339Sbill iocb.ioc_ispeed = tp->t_ispeed; 26439Sbill iocb.ioc_ospeed = tp->t_ospeed; 26539Sbill iocb.ioc_erase = tp->t_erase; 26639Sbill iocb.ioc_kill = tp->t_kill; 26739Sbill iocb.ioc_flags = tp->t_flags; 26839Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 26939Sbill u.u_error = EFAULT; 27039Sbill break; 27139Sbill 27239Sbill /* 27339Sbill * Hang up line on last close 27439Sbill */ 27539Sbill 27639Sbill case TIOCHPCL: 27739Sbill tp->t_state |= HUPCLS; 27839Sbill break; 27939Sbill 28039Sbill case TIOCFLUSH: 28139Sbill flushtty(tp); 28239Sbill break; 28339Sbill 28439Sbill /* 28539Sbill * ioctl entries to line discipline 28639Sbill */ 28739Sbill case DIOCSETP: 28839Sbill case DIOCGETP: 289*121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 290*121Sbill u.u_error = ENOTTY; 29139Sbill break; 29239Sbill 29339Sbill /* 29439Sbill * set and fetch special characters 29539Sbill */ 29639Sbill case TIOCSETC: 29739Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tc))) 29839Sbill u.u_error = EFAULT; 29939Sbill break; 30039Sbill 30139Sbill case TIOCGETC: 30239Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tc))) 30339Sbill u.u_error = EFAULT; 30439Sbill break; 30539Sbill 30639Sbill default: 30739Sbill return(0); 30839Sbill } 30939Sbill return(1); 31039Sbill } 31139Sbill 31239Sbill /* 31339Sbill * Wait for output to drain, then flush input waiting. 31439Sbill */ 31539Sbill wflushtty(tp) 31639Sbill register struct tty *tp; 31739Sbill { 31839Sbill 319*121Sbill (void) spl5(); 32039Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 32139Sbill (*tp->t_oproc)(tp); 32239Sbill tp->t_state |= ASLEEP; 32339Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 32439Sbill } 32539Sbill flushtty(tp); 326*121Sbill (void) spl0(); 32739Sbill } 32839Sbill 32939Sbill /* 33039Sbill * flush all TTY queues 33139Sbill */ 33239Sbill flushtty(tp) 33339Sbill register struct tty *tp; 33439Sbill { 33539Sbill register s; 33639Sbill 337*121Sbill s = spl6(); 33839Sbill while (getc(&tp->t_canq) >= 0) 33939Sbill ; 34039Sbill wakeup((caddr_t)&tp->t_rawq); 34139Sbill wakeup((caddr_t)&tp->t_outq); 34239Sbill tp->t_state &= ~TTSTOP; 34339Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 34439Sbill while (getc(&tp->t_outq) >= 0) 34539Sbill ; 34639Sbill while (getc(&tp->t_rawq) >= 0) 34739Sbill ; 34839Sbill tp->t_delct = 0; 34939Sbill splx(s); 35039Sbill } 35139Sbill 35239Sbill 35339Sbill 35439Sbill /* 35539Sbill * transfer raw input list to canonical list, 35639Sbill * doing erase-kill processing and handling escapes. 35739Sbill * It waits until a full line has been typed in cooked mode, 35839Sbill * or until any character has been typed in raw mode. 35939Sbill */ 36039Sbill canon(tp) 36139Sbill register struct tty *tp; 36239Sbill { 36339Sbill register char *bp; 36439Sbill char *bp1; 36539Sbill register int c; 36639Sbill int mc; 36739Sbill int s; 36839Sbill 36939Sbill if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 37039Sbill || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { 37139Sbill return(-1); 37239Sbill } 37339Sbill s = spl0(); 37439Sbill loop: 37539Sbill bp = &canonb[2]; 37639Sbill while ((c=getc(&tp->t_rawq)) >= 0) { 37739Sbill if ((tp->t_flags&(RAW|CBREAK))==0) { 37839Sbill if (c==0377) { 37939Sbill tp->t_delct--; 38039Sbill break; 38139Sbill } 38239Sbill if (bp[-1]!='\\') { 38339Sbill if (c==tp->t_erase) { 38439Sbill if (bp > &canonb[2]) 38539Sbill bp--; 38639Sbill continue; 38739Sbill } 38839Sbill if (c==tp->t_kill) 38939Sbill goto loop; 39039Sbill if (c==tun.t_eofc) 39139Sbill continue; 39239Sbill } else { 39339Sbill mc = maptab[c]; 39439Sbill if (c==tp->t_erase || c==tp->t_kill) 39539Sbill mc = c; 39639Sbill if (mc && (mc==c || (tp->t_flags&LCASE))) { 39739Sbill if (bp[-2] != '\\') 39839Sbill c = mc; 39939Sbill bp--; 40039Sbill } 40139Sbill } 40239Sbill } 40339Sbill *bp++ = c; 40439Sbill if (bp>=canonb+CANBSIZ) 40539Sbill break; 40639Sbill } 40739Sbill bp1 = &canonb[2]; 408*121Sbill (void) b_to_q(bp1, bp-bp1, &tp->t_canq); 40939Sbill 41039Sbill if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 41139Sbill if (putc(tun.t_startc, &tp->t_outq)==0) { 41239Sbill tp->t_state &= ~TBLOCK; 41339Sbill ttstart(tp); 41439Sbill } 41539Sbill tp->t_char = 0; 41639Sbill } 41739Sbill 41839Sbill splx(s); 41939Sbill return(0); 42039Sbill } 42139Sbill 42239Sbill 42339Sbill /* 42439Sbill * block transfer input handler. 42539Sbill */ 42639Sbill ttyrend(tp, pb, pe) 42739Sbill register struct tty *tp; 42839Sbill register char *pb, *pe; 42939Sbill { 43039Sbill int tandem; 43139Sbill 43239Sbill tandem = tp->t_flags&TANDEM; 43339Sbill if (tp->t_flags&RAW) { 434*121Sbill (void) b_to_q(pb, pe-pb, &tp->t_rawq); 43539Sbill if (tp->t_chan) 436*121Sbill (void) sdata(tp->t_chan); else 43739Sbill wakeup((caddr_t)&tp->t_rawq); 43839Sbill } else { 43939Sbill tp->t_flags &= ~TANDEM; 44039Sbill while (pb < pe) 44139Sbill ttyinput(*pb++, tp); 44239Sbill tp->t_flags |= tandem; 44339Sbill } 44439Sbill if (tandem) 44539Sbill ttyblock(tp); 44639Sbill } 44739Sbill 44839Sbill /* 44939Sbill * Place a character on raw TTY input queue, putting in delimiters 45039Sbill * and waking up top half as needed. 45139Sbill * Also echo if required. 45239Sbill * The arguments are the character and the appropriate 45339Sbill * tty structure. 45439Sbill */ 45539Sbill ttyinput(c, tp) 45639Sbill register c; 45739Sbill register struct tty *tp; 45839Sbill { 45939Sbill register int t_flags; 46039Sbill register struct chan *cp; 46139Sbill 46239Sbill tk_nin += 1; 46339Sbill c &= 0377; 46439Sbill t_flags = tp->t_flags; 46539Sbill if (t_flags&TANDEM) 46639Sbill ttyblock(tp); 46739Sbill if ((t_flags&RAW)==0) { 46839Sbill c &= 0177; 46939Sbill if (tp->t_state&TTSTOP) { 47039Sbill if (c==tun.t_startc) { 47139Sbill tp->t_state &= ~TTSTOP; 47239Sbill ttstart(tp); 47339Sbill return; 47439Sbill } 47539Sbill if (c==tun.t_stopc) 47639Sbill return; 47739Sbill tp->t_state &= ~TTSTOP; 47839Sbill ttstart(tp); 47939Sbill } else { 48039Sbill if (c==tun.t_stopc) { 48139Sbill tp->t_state |= TTSTOP; 48239Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 48339Sbill return; 48439Sbill } 48539Sbill if (c==tun.t_startc) 48639Sbill return; 48739Sbill } 48839Sbill if (c==tun.t_quitc || c==tun.t_intrc) { 48939Sbill flushtty(tp); 49039Sbill c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; 49139Sbill if (tp->t_chan) 49239Sbill scontrol(tp->t_chan, M_SIG, c); 49339Sbill else 49439Sbill signal(tp->t_pgrp, c); 49539Sbill return; 49639Sbill } 49739Sbill if (c=='\r' && t_flags&CRMOD) 49839Sbill c = '\n'; 49939Sbill } 50039Sbill if (tp->t_rawq.c_cc>TTYHOG) { 50139Sbill flushtty(tp); 50239Sbill return; 50339Sbill } 50439Sbill if (t_flags&LCASE && c>='A' && c<='Z') 50539Sbill c += 'a'-'A'; 506*121Sbill (void) putc(c, &tp->t_rawq); 50739Sbill if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { 50839Sbill if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) 50939Sbill tp->t_delct++; 51039Sbill if ((cp=tp->t_chan)!=NULL) 511*121Sbill (void) sdata(cp); else 51239Sbill wakeup((caddr_t)&tp->t_rawq); 51339Sbill } 51439Sbill if (t_flags&ECHO) { 51539Sbill ttyoutput(c, tp); 51639Sbill if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) 51739Sbill ttyoutput('\n', tp); 51839Sbill ttstart(tp); 51939Sbill } 52039Sbill } 52139Sbill 52239Sbill 52339Sbill /* 52439Sbill * Send stop character on input overflow. 52539Sbill */ 52639Sbill ttyblock(tp) 52739Sbill register struct tty *tp; 52839Sbill { 52939Sbill register x; 53039Sbill x = q1.c_cc + q2.c_cc; 53139Sbill if (q1.c_cc > TTYHOG) { 53239Sbill flushtty(tp); 53339Sbill tp->t_state &= ~TBLOCK; 53439Sbill } 53539Sbill if (x >= TTYHOG/2) { 53639Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 53739Sbill tp->t_state |= TBLOCK; 53839Sbill tp->t_char++; 53939Sbill ttstart(tp); 54039Sbill } 54139Sbill } 54239Sbill } 54339Sbill 54439Sbill /* 54539Sbill * put character on TTY output queue, adding delays, 54639Sbill * expanding tabs, and handling the CR/NL bit. 54739Sbill * It is called both from the top half for output, and from 54839Sbill * interrupt level for echoing. 54939Sbill * The arguments are the character and the tty structure. 55039Sbill */ 55139Sbill ttyoutput(c, tp) 55239Sbill register c; 55339Sbill register struct tty *tp; 55439Sbill { 55539Sbill register char *colp; 55639Sbill register ctype; 55739Sbill 55839Sbill /* 55939Sbill * Ignore EOT in normal mode to avoid hanging up 56039Sbill * certain terminals. 56139Sbill * In raw mode dump the char unchanged. 56239Sbill */ 56339Sbill if ((tp->t_flags&RAW)==0) { 56439Sbill c &= 0177; 56539Sbill if ((tp->t_flags&CBREAK)==0 && c==CEOT) 56639Sbill return; 56739Sbill } else { 568*121Sbill tk_nout++; 569*121Sbill (void) putc(c, &tp->t_outq); 57039Sbill return; 57139Sbill } 57239Sbill 57339Sbill /* 57439Sbill * Turn tabs to spaces as required 57539Sbill */ 57639Sbill if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { 577*121Sbill c = 8 - (tp->t_col & 7); 578*121Sbill (void) b_to_q(" ", c, &tp->t_outq); 579*121Sbill tp->t_col += c; 580*121Sbill tk_nout += c; 58139Sbill return; 58239Sbill } 583*121Sbill tk_nout++; 58439Sbill /* 58539Sbill * for upper-case-only terminals, 58639Sbill * generate escapes. 58739Sbill */ 58839Sbill if (tp->t_flags&LCASE) { 58939Sbill colp = "({)}!|^~'`"; 59039Sbill while(*colp++) 59139Sbill if(c == *colp++) { 59239Sbill ttyoutput('\\', tp); 59339Sbill c = colp[-2]; 59439Sbill break; 59539Sbill } 59639Sbill if ('a'<=c && c<='z') 59739Sbill c += 'A' - 'a'; 59839Sbill } 59939Sbill /* 60039Sbill * turn <nl> to <cr><lf> if desired. 60139Sbill */ 60239Sbill if (c=='\n' && tp->t_flags&CRMOD) 60339Sbill ttyoutput('\r', tp); 604*121Sbill (void) putc(c, &tp->t_outq); 60539Sbill /* 60639Sbill * Calculate delays. 60739Sbill * The numbers here represent clock ticks 60839Sbill * and are not necessarily optimal for all terminals. 60939Sbill * The delays are indicated by characters above 0200. 61039Sbill * In raw mode there are no delays and the 61139Sbill * transmission path is 8 bits wide. 61239Sbill */ 61339Sbill colp = &tp->t_col; 61439Sbill ctype = partab[c]; 61539Sbill c = 0; 61639Sbill switch (ctype&077) { 61739Sbill 61839Sbill /* ordinary */ 61939Sbill case 0: 62039Sbill (*colp)++; 62139Sbill 62239Sbill /* non-printing */ 62339Sbill case 1: 62439Sbill break; 62539Sbill 62639Sbill /* backspace */ 62739Sbill case 2: 62839Sbill if (*colp) 62939Sbill (*colp)--; 63039Sbill break; 63139Sbill 63239Sbill /* newline */ 63339Sbill case 3: 63439Sbill ctype = (tp->t_flags >> 8) & 03; 63539Sbill if(ctype == 1) { /* tty 37 */ 63639Sbill if (*colp) 63739Sbill c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 63839Sbill } else 63939Sbill if(ctype == 2) { /* vt05 */ 64039Sbill c = 6; 64139Sbill } 64239Sbill *colp = 0; 64339Sbill break; 64439Sbill 64539Sbill /* tab */ 64639Sbill case 4: 64739Sbill ctype = (tp->t_flags >> 10) & 03; 64839Sbill if(ctype == 1) { /* tty 37 */ 64939Sbill c = 1 - (*colp | ~07); 65039Sbill if(c < 5) 65139Sbill c = 0; 65239Sbill } 65339Sbill *colp |= 07; 65439Sbill (*colp)++; 65539Sbill break; 65639Sbill 65739Sbill /* vertical motion */ 65839Sbill case 5: 65939Sbill if(tp->t_flags & VTDELAY) /* tty 37 */ 66039Sbill c = 0177; 66139Sbill break; 66239Sbill 66339Sbill /* carriage return */ 66439Sbill case 6: 66539Sbill ctype = (tp->t_flags >> 12) & 03; 66639Sbill if(ctype == 1) { /* tn 300 */ 66739Sbill c = 5; 66839Sbill } else if(ctype == 2) { /* ti 700 */ 66939Sbill c = 10; 67039Sbill } else if(ctype == 3) { /* concept 100 */ 67139Sbill int i; 67239Sbill for (i= *colp; i<9; i++) 673*121Sbill (void) putc(0177, &tp->t_outq); 67439Sbill } 67539Sbill *colp = 0; 67639Sbill } 67739Sbill if(c) 678*121Sbill (void) putc(c|0200, &tp->t_outq); 67939Sbill } 68039Sbill 68139Sbill /* 68239Sbill * Restart typewriter output following a delay 68339Sbill * timeout. 68439Sbill * The name of the routine is passed to the timeout 68539Sbill * subroutine and it is called during a clock interrupt. 68639Sbill */ 68739Sbill ttrstrt(tp) 68839Sbill register struct tty *tp; 68939Sbill { 69039Sbill 69139Sbill tp->t_state &= ~TIMEOUT; 69239Sbill ttstart(tp); 69339Sbill } 69439Sbill 69539Sbill /* 69639Sbill * Start output on the typewriter. It is used from the top half 69739Sbill * after some characters have been put on the output queue, 69839Sbill * from the interrupt routine to transmit the next 69939Sbill * character, and after a timeout has finished. 70039Sbill */ 70139Sbill ttstart(tp) 70239Sbill register struct tty *tp; 70339Sbill { 70439Sbill register s; 70539Sbill 70639Sbill s = spl5(); 70739Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 70839Sbill (*tp->t_oproc)(tp); 70939Sbill splx(s); 71039Sbill } 71139Sbill 71239Sbill /* 71339Sbill * Called from device's read routine after it has 71439Sbill * calculated the tty-structure given as argument. 71539Sbill */ 71639Sbill ttread(tp) 71739Sbill register struct tty *tp; 71839Sbill { 71939Sbill register s; 72039Sbill 72139Sbill if ((tp->t_state&CARR_ON)==0) 72239Sbill return(-1); 72339Sbill s = spl5(); 72439Sbill if (tp->t_canq.c_cc==0) 72539Sbill while (canon(tp)<0) 72639Sbill if (tp->t_chan==NULL) { 72739Sbill sleep((caddr_t)&tp->t_rawq, TTIPRI); 72839Sbill } else { 72939Sbill splx(s); 73039Sbill return(0); 73139Sbill } 73239Sbill splx(s); 73339Sbill while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) 73439Sbill ; 73539Sbill return(tp->t_rawq.c_cc+tp->t_canq.c_cc); 73639Sbill } 73739Sbill 73839Sbill /* 73939Sbill * Called from the device's write routine after it has 74039Sbill * calculated the tty-structure given as argument. 74139Sbill */ 74239Sbill caddr_t 74339Sbill ttwrite(tp) 74439Sbill register struct tty *tp; 74539Sbill { 74639Sbill /* 74739Sbill * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL 74839Sbill * AND MUST NOT BE CHANGED WITHOUT PATCHING 74939Sbill * THE 'ASM' INLINES BELOW. WATCH OUT. 75039Sbill */ 75139Sbill register char *cp; 75239Sbill register int cc, ce; 75339Sbill register i; 75439Sbill char obuf[OBUFSIZ]; 75539Sbill 75639Sbill if ((tp->t_state&CARR_ON)==0) 75739Sbill return(NULL); 75839Sbill while (u.u_count) { 75939Sbill cc = MIN(u.u_count, OBUFSIZ); 76039Sbill cp = obuf; 76139Sbill iomove(cp, (unsigned)cc, B_WRITE); 76239Sbill if (u.u_error) 76339Sbill break; 764*121Sbill (void) spl5(); 76539Sbill while (tp->t_outq.c_cc > TTHIWAT) { 76639Sbill ttstart(tp); 76739Sbill tp->t_state |= ASLEEP; 76839Sbill if (tp->t_chan) { 76939Sbill u.u_base -= cc; 77039Sbill u.u_offset -= cc; 77139Sbill u.u_count += cc; 772*121Sbill (void) spl0(); 77339Sbill return((caddr_t)&tp->t_outq); 77439Sbill } 77539Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 77639Sbill } 777*121Sbill (void) spl0(); 77839Sbill if (tp->t_flags&LCASE) { 77939Sbill while (cc--) 78039Sbill ttyoutput(*cp++,tp); 78139Sbill continue; 78239Sbill } 78339Sbill while (cc) { 78439Sbill if (tp->t_flags&RAW) 78539Sbill ce=cc; 78639Sbill else { 78739Sbill #ifdef VAX 78839Sbill asm(" scanc r9,(r10),_partab,$077"); 78939Sbill asm(" subl3 r0,r9,r8"); 79039Sbill #else 79139Sbill ce=0; 79239Sbill while(((partab[*(cp+ce)]&077)==0)&&(ce<cc)) 79339Sbill ce++; 79439Sbill #endif 79539Sbill if (ce==0) { 79639Sbill ttyoutput(*cp++,tp); 79739Sbill cc--; 798*121Sbill goto check; 79939Sbill } 80039Sbill } 80139Sbill i=b_to_q(cp,ce,&tp->t_outq); 80239Sbill ce-=i; 80339Sbill tk_nout+=ce; 80439Sbill tp->t_col+=ce; 80539Sbill cp+=ce; 80639Sbill cc-=ce; 807*121Sbill if (i == 0) 808*121Sbill continue; 809*121Sbill check: 810*121Sbill if (tp->t_outq.c_cc > TTHIWAT) { 811*121Sbill (void) spl5(); 81239Sbill while (tp->t_outq.c_cc > TTHIWAT) { 81339Sbill ttstart(tp); 81439Sbill tp->t_state |= ASLEEP; 81539Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 81639Sbill } 817*121Sbill (void) spl0(); 81839Sbill } 81939Sbill } 82039Sbill } 82139Sbill ttstart(tp); 82239Sbill return(NULL); 82339Sbill } 824