X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/6d27b2c67ea2a12e49912503a4f041b1eb372315..5513375c86e602a9163497b7ad7e66f860de9efb:/usr/src/sys/kern/tty.c diff --git a/usr/src/sys/kern/tty.c b/usr/src/sys/kern/tty.c index 36e3217396..2d61be7ad0 100644 --- a/usr/src/sys/kern/tty.c +++ b/usr/src/sys/kern/tty.c @@ -1,7 +1,7 @@ -/* tty.c 3.16 %G% */ +/* tty.c 4.3 %G% */ /* - * general TTY subroutines + * TTY subroutines common to more than one line discipline */ #include "../h/param.h" #include "../h/systm.h" @@ -57,42 +57,13 @@ char maptab[] ={ 'X','Y','Z',000,000,000,000,000, }; - -/* - * shorthand - */ -#define q1 tp->t_rawq -#define q2 tp->t_canq -#define q3 tp->t_outq -#define q4 tp->t_un.t_ctlq +short tthiwat[16] = + { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; +short ttlowat[16] = + { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; #define OBUFSIZ 100 -/* - * routine called on first teletype open. - * establishes a process group for distribution - * of quits and interrupts from the tty. - */ -ttyopen(dev, tp) -dev_t dev; -register struct tty *tp; -{ - register struct proc *pp; - - pp = u.u_procp; - tp->t_dev = dev; - if(pp->p_pgrp == 0) { - u.u_ttyp = tp; - u.u_ttyd = dev; - if (tp->t_pgrp == 0) - tp->t_pgrp = pp->p_pid; - pp->p_pgrp = tp->t_pgrp; - } - tp->t_state &= ~WOPEN; - tp->t_state |= ISOPEN; - tp->t_line = 0; /* conservative */ -} - /* * set default control characters. */ @@ -115,115 +86,123 @@ register struct tty *tp; tlun.t_flushc = CTRL(o); tlun.t_werasc = CTRL(w); tlun.t_lnextc = CTRL(v); - tlun.t_lintr = CTRL(c); - tlun.t_lerase = CTRL(h); - tlun.t_lkill = CTRL(u); tp->t_local = 0; tp->t_lstate = 0; /* end local */ } /* - * clean tp on last close + * Wait for output to drain, then flush input waiting. */ -ttyclose(tp) +wflushtty(tp) register struct tty *tp; { - tp->t_pgrp = 0; - wflushtty(tp); - tp->t_state = 0; - tp->t_line = 0; + (void) spl5(); + while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { + (*tp->t_oproc)(tp); + tp->t_state |= ASLEEP; + sleep((caddr_t)&tp->t_outq, TTOPRI); + } + flushtty(tp, FREAD|FWRITE); + (void) spl0(); } /* - * stty/gtty writearound + * flush all TTY queues */ -stty() +flushtty(tp, rw) +register struct tty *tp; { - u.u_arg[2] = u.u_arg[1]; - u.u_arg[1] = TIOCSETP; - ioctl(); + register s; + + if (tp->t_line == NETLDISC) + return; + s = spl6(); + if (rw & FREAD) { + while (getc(&tp->t_canq) >= 0) + ; + wakeup((caddr_t)&tp->t_rawq); + } + if (rw & FWRITE) { + wakeup((caddr_t)&tp->t_outq); + tp->t_state &= ~TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp); + while (getc(&tp->t_outq) >= 0) + ; + } + if (rw & FREAD) { + while (getc(&tp->t_rawq) >= 0) + ; + tp->t_delct = 0; + tp->t_rocount = 0; /* local */ + tp->t_rocol = 0; + tp->t_lstate = 0; + } + splx(s); } -gtty() +/* + * Send stop character on input overflow. + */ +ttyblock(tp) +register struct tty *tp; { - u.u_arg[2] = u.u_arg[1]; - u.u_arg[1] = TIOCGETP; - ioctl(); + register x; + x = tp->t_rawq.c_cc + tp->t_canq.c_cc; + if (tp->t_rawq.c_cc > TTYHOG) { + flushtty(tp, FREAD|FWRITE); + tp->t_state &= ~TBLOCK; + } + if (x >= TTYHOG/2) { + if (putc(tun.t_stopc, &tp->t_outq)==0) { + tp->t_state |= TBLOCK; + tp->t_char++; + ttstart(tp); + } + } } /* - * Do nothing specific version of line - * discipline specific ioctl command. + * Restart typewriter output following a delay + * timeout. + * The name of the routine is passed to the timeout + * subroutine and it is called during a clock interrupt. */ -/*ARGSUSED*/ -nullioctl(tp, cmd, addr) +ttrstrt(tp) register struct tty *tp; -caddr_t addr; { - return (cmd); + tp->t_state &= ~TIMEOUT; + ttstart(tp); } /* - * ioctl system call - * Check legality, execute common code, and switch out to individual - * device routine. + * Start output on the typewriter. It is used from the top half + * after some characters have been put on the output queue, + * from the interrupt routine to transmit the next + * character, and after a timeout has finished. */ -ioctl() +ttstart(tp) +register struct tty *tp; { - register struct file *fp; - register struct inode *ip; - register struct a { - int fdes; - int cmd; - caddr_t cmarg; - } *uap; - register dev_t dev; - register fmt; - - uap = (struct a *)u.u_ap; - if ((fp = getf(uap->fdes)) == NULL) - return; - if ((fp->f_flag & (FREAD|FWRITE)) == 0) { - u.u_error = EBADF; - return; - } - if (uap->cmd==FIOCLEX) { - u.u_pofile[uap->fdes] |= EXCLOSE; - return; - } - if (uap->cmd==FIONCLEX) { - u.u_pofile[uap->fdes] &= ~EXCLOSE; - return; - } - ip = fp->f_inode; - fmt = ip->i_mode & IFMT; - if (fmt != IFCHR && fmt != IFMPC) { -/* begin local */ - if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) { - off_t nread = ip->i_size - fp->f_un.f_offset; + register s; - if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t))) - u.u_error = EFAULT; - } else -/* end local */ - u.u_error = ENOTTY; - return; - } - dev = ip->i_un.i_rdev; - u.u_r.r_val1 = 0; - (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); + s = spl5(); + if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) + (*tp->t_oproc)(tp); + splx(s); } /* - * Common code for several tty ioctl commands + * Common code for tty ioctls. */ -ttioccomm(com, tp, addr, dev) +/*ARGSUSED*/ +ttioctl(tp, com, addr, flag) register struct tty *tp; caddr_t addr; { + int dev; unsigned t; struct sgttyb iocb; struct clist tq; @@ -231,10 +210,59 @@ caddr_t addr; register c; int temp; + /* + * This is especially so that isatty() will + * fail when carrier is gone. + */ + if ((tp->t_state&CARR_ON) == 0) { + u.u_error = EBADF; + return (1); + } + + dev = tp->t_dev; + /* + * If the ioctl involves modification, + * insist on being able to write the device, + * and hang if in the background. + */ + switch(com) { + + case TIOCSETD: + case TIOCSETP: + case TIOCSETN: + case TIOCFLUSH: + case TIOCSETC: + case TIOCSLTC: + case TIOCSPGRP: + case TIOCLBIS: + case TIOCLBIC: + case TIOCLSET: + case TIOCSTI: +/* this is reasonable, but impractical... + if ((flag & FWRITE) == 0) { + u.u_error = EBADF; + return (1); + } + */ + while (tp->t_line == NTTYDISC && + u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && + (u.u_procp->p_flag&SVFORK) == 0 && + u.u_signal[SIGTTOU] != SIG_IGN && + u.u_signal[SIGTTOU] != SIG_HOLD && + (u.u_procp->p_flag&SDETACH)==0) { + gsignal(u.u_procp->p_pgrp, SIGTTOU); + sleep((caddr_t)&lbolt, TTOPRI); + } + break; + } + + /* + * Process the ioctl. + */ switch(com) { /* - * get discipline number + * Get discipline number */ case TIOCGETD: t = tp->t_line; @@ -243,7 +271,7 @@ caddr_t addr; break; /* - * set line discipline + * Set line discipline */ case TIOCSETD: if (copyin(addr, (caddr_t)&t, sizeof(t))) { @@ -265,7 +293,7 @@ caddr_t addr; break; /* - * prevent more opens on channel + * Prevent more opens on channel */ case TIOCEXCL: tp->t_state |= XCLUDE; @@ -290,6 +318,9 @@ caddr_t addr; wflushtty(tp); while (canon(tp)>=0) ; +#ifdef notdef + wakeup((caddr_t)&tp->t_rawq); +#endif } else if (tp->t_line == NTTYDISC) { if (tp->t_flags&RAW || iocb.sg_flags&RAW || com == TIOCSETP) @@ -304,9 +335,11 @@ caddr_t addr; tp->t_local |= LPENDIN; if (tp->t_canq.c_cc) panic("ioccom canq"); +#ifdef notdef if (tp->t_chan) (void) sdata(tp->t_chan); else +#endif wakeup((caddr_t)&tp->t_rawq); } } @@ -322,7 +355,7 @@ caddr_t addr; break; /* - * send current parameters to user + * Send current parameters to user */ case TIOCGETP: iocb.sg_ispeed = tp->t_ispeed; @@ -337,7 +370,6 @@ caddr_t addr; /* * Hang up line on last close */ - case TIOCHPCL: tp->t_state |= HUPCLS; break; @@ -347,16 +379,7 @@ caddr_t addr; break; /* - * ioctl entries to line discipline - */ - case DIOCSETP: - case DIOCGETP: - if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) - u.u_error = ENOTTY; - break; - - /* - * set and fetch special characters + * Set and fetch special characters */ case TIOCSETC: if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) @@ -369,6 +392,9 @@ caddr_t addr; break; /* local ioctls */ + /* + * Set/get local special characters. + */ case TIOCSLTC: if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) u.u_error = EFAULT; @@ -379,6 +405,9 @@ caddr_t addr; u.u_error = EFAULT; break; + /* + * Return number of characters immediately available. + */ case FIONREAD: { off_t nread; @@ -449,11 +478,18 @@ caddr_t addr; u.u_error = EFAULT; break; + /* + * Return number of characters in + * the output. + */ case TIOCOUTQ: if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) u.u_error = EFAULT; break; + /* + * Simulate typing of a character at the terminal. + */ case TIOCSTI: c = fubyte(addr); if (u.u_uid && u.u_ttyp != tp || c < 0) @@ -468,526 +504,3 @@ caddr_t addr; } return(1); } - -/* - * Wait for output to drain, then flush input waiting. - */ -wflushtty(tp) -register struct tty *tp; -{ - - (void) spl5(); - while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { - (*tp->t_oproc)(tp); - tp->t_state |= ASLEEP; - sleep((caddr_t)&tp->t_outq, TTOPRI); - } - flushtty(tp, FREAD|FWRITE); - (void) spl0(); -} - -/* - * flush all TTY queues - */ -flushtty(tp, rw) -register struct tty *tp; -{ - register s; - - if (tp->t_line == NETLDISC) - return; - s = spl6(); - if (rw & FREAD) { - while (getc(&tp->t_canq) >= 0) - ; - wakeup((caddr_t)&tp->t_rawq); - } - if (rw & FWRITE) { - wakeup((caddr_t)&tp->t_outq); - tp->t_state &= ~TTSTOP; - (*cdevsw[major(tp->t_dev)].d_stop)(tp); - while (getc(&tp->t_outq) >= 0) - ; - } - if (rw & FREAD) { - while (getc(&tp->t_rawq) >= 0) - ; - tp->t_delct = 0; - tp->t_rocount = 0; /* local */ - tp->t_rocol = 0; - tp->t_lstate = 0; - } - splx(s); -} - - - -/* - * transfer raw input list to canonical list, - * doing erase-kill processing and handling escapes. - * It waits until a full line has been typed in cooked mode, - * or until any character has been typed in raw mode. - */ -canon(tp) -register struct tty *tp; -{ - register char *bp; - char *bp1; - register int c; - int mc; - int s; - - if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 - || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { - return(-1); - } - s = spl0(); -loop: - bp = &canonb[2]; - while ((c=getc(&tp->t_rawq)) >= 0) { - if ((tp->t_flags&(RAW|CBREAK))==0) { - if (c==0377) { - tp->t_delct--; - break; - } - if (bp[-1]!='\\') { - if (c==tp->t_erase) { - if (bp > &canonb[2]) - bp--; - continue; - } - if (c==tp->t_kill) - goto loop; - if (c==tun.t_eofc) - continue; - } else { - mc = maptab[c]; - if (c==tp->t_erase || c==tp->t_kill) - mc = c; - if (mc && (mc==c || (tp->t_flags&LCASE))) { - if (bp[-2] != '\\') - c = mc; - bp--; - } - } - } - *bp++ = c; - if (bp>=canonb+CANBSIZ) - break; - } - bp1 = &canonb[2]; - (void) b_to_q(bp1, bp-bp1, &tp->t_canq); - - if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { - if (putc(tun.t_startc, &tp->t_outq)==0) { - tp->t_state &= ~TBLOCK; - ttstart(tp); - } - tp->t_char = 0; - } - - splx(s); - return(0); -} - - -/* - * block transfer input handler. - */ -ttyrend(tp, pb, pe) -register struct tty *tp; -register char *pb, *pe; -{ - int tandem; - - tandem = tp->t_flags&TANDEM; - if (tp->t_flags&RAW) { - (void) b_to_q(pb, pe-pb, &tp->t_rawq); - if (tp->t_chan) - (void) sdata(tp->t_chan); else - wakeup((caddr_t)&tp->t_rawq); - } else { - tp->t_flags &= ~TANDEM; - while (pb < pe) - ttyinput(*pb++, tp); - tp->t_flags |= tandem; - } - if (tandem) - ttyblock(tp); -} - -/* - * Place a character on raw TTY input queue, putting in delimiters - * and waking up top half as needed. - * Also echo if required. - * The arguments are the character and the appropriate - * tty structure. - */ -ttyinput(c, tp) -register c; -register struct tty *tp; -{ - register int t_flags; - register struct chan *cp; - - tk_nin += 1; - c &= 0377; - t_flags = tp->t_flags; - if (t_flags&TANDEM) - ttyblock(tp); - if ((t_flags&RAW)==0) { - c &= 0177; - if (tp->t_state&TTSTOP) { - if (c==tun.t_startc) { - tp->t_state &= ~TTSTOP; - ttstart(tp); - return; - } - if (c==tun.t_stopc) - return; - tp->t_state &= ~TTSTOP; - ttstart(tp); - } else { - if (c==tun.t_stopc) { - tp->t_state |= TTSTOP; - (*cdevsw[major(tp->t_dev)].d_stop)(tp); - return; - } - if (c==tun.t_startc) - return; - } - if (c==tun.t_quitc || c==tun.t_intrc) { - flushtty(tp, FREAD|FWRITE); - c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; - if (tp->t_chan) - scontrol(tp->t_chan, M_SIG, c); - else - gsignal(tp->t_pgrp, c); - return; - } - if (c=='\r' && t_flags&CRMOD) - c = '\n'; - } - if (tp->t_rawq.c_cc>TTYHOG) { - flushtty(tp, FREAD|FWRITE); - return; - } - if (t_flags&LCASE && c>='A' && c<='Z') - c += 'a'-'A'; - (void) putc(c, &tp->t_rawq); - if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { - if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) - tp->t_delct++; - if ((cp=tp->t_chan)!=NULL) - (void) sdata(cp); else - wakeup((caddr_t)&tp->t_rawq); - } - if (t_flags&ECHO) { - ttyoutput(c, tp); - if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) - ttyoutput('\n', tp); - ttstart(tp); - } -} - - -/* - * Send stop character on input overflow. - */ -ttyblock(tp) -register struct tty *tp; -{ - register x; - x = q1.c_cc + q2.c_cc; - if (q1.c_cc > TTYHOG) { - flushtty(tp, FREAD|FWRITE); - tp->t_state &= ~TBLOCK; - } - if (x >= TTYHOG/2) { - if (putc(tun.t_stopc, &tp->t_outq)==0) { - tp->t_state |= TBLOCK; - tp->t_char++; - ttstart(tp); - } - } -} - -/* - * put character on TTY output queue, adding delays, - * expanding tabs, and handling the CR/NL bit. - * It is called both from the top half for output, and from - * interrupt level for echoing. - * The arguments are the character and the tty structure. - */ -ttyoutput(c, tp) -register c; -register struct tty *tp; -{ - register char *colp; - register ctype; - - /* - * Ignore EOT in normal mode to avoid hanging up - * certain terminals. - * In raw mode dump the char unchanged. - */ - if ((tp->t_flags&RAW)==0) { - c &= 0177; - if ((tp->t_flags&CBREAK)==0 && c==CEOT) - return; - } else { - tk_nout++; - (void) putc(c, &tp->t_outq); - return; - } - - /* - * Turn tabs to spaces as required - */ - if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { - c = 8 - (tp->t_col & 7); - (void) b_to_q(" ", c, &tp->t_outq); - tp->t_col += c; - tk_nout += c; - return; - } - tk_nout++; - /* - * for upper-case-only terminals, - * generate escapes. - */ - if (tp->t_flags&LCASE) { - colp = "({)}!|^~'`"; - while(*colp++) - if(c == *colp++) { - ttyoutput('\\', tp); - c = colp[-2]; - break; - } - if ('a'<=c && c<='z') - c += 'A' - 'a'; - } - /* - * turn to if desired. - */ - if (c=='\n' && tp->t_flags&CRMOD) - ttyoutput('\r', tp); - (void) putc(c, &tp->t_outq); - /* - * Calculate delays. - * The numbers here represent clock ticks - * and are not necessarily optimal for all terminals. - * The delays are indicated by characters above 0200. - * In raw mode there are no delays and the - * transmission path is 8 bits wide. - */ - colp = &tp->t_col; - ctype = partab[c]; - c = 0; - switch (ctype&077) { - - /* ordinary */ - case 0: - (*colp)++; - - /* non-printing */ - case 1: - break; - - /* backspace */ - case 2: - if (*colp) - (*colp)--; - break; - - /* newline */ - case 3: - ctype = (tp->t_flags >> 8) & 03; - if(ctype == 1) { /* tty 37 */ - if (*colp) - c = max(((unsigned)*colp>>4) + 3, (unsigned)6); - } else - if(ctype == 2) { /* vt05 */ - c = 6; - } - *colp = 0; - break; - - /* tab */ - case 4: - ctype = (tp->t_flags >> 10) & 03; - if(ctype == 1) { /* tty 37 */ - c = 1 - (*colp | ~07); - if(c < 5) - c = 0; - } - *colp |= 07; - (*colp)++; - break; - - /* vertical motion */ - case 5: - if(tp->t_flags & VTDELAY) /* tty 37 */ - c = 0177; - break; - - /* carriage return */ - case 6: - ctype = (tp->t_flags >> 12) & 03; - if(ctype == 1) { /* tn 300 */ - c = 5; - } else if(ctype == 2) { /* ti 700 */ - c = 10; - } else if(ctype == 3) { /* concept 100 */ - int i; - if ((i = *colp) >= 0) - for (; i<9; i++) - (void) putc(0177, &tp->t_outq); - } - *colp = 0; - } - if(c) - (void) putc(c|0200, &tp->t_outq); -} - -/* - * Restart typewriter output following a delay - * timeout. - * The name of the routine is passed to the timeout - * subroutine and it is called during a clock interrupt. - */ -ttrstrt(tp) -register struct tty *tp; -{ - - tp->t_state &= ~TIMEOUT; - ttstart(tp); -} - -/* - * Start output on the typewriter. It is used from the top half - * after some characters have been put on the output queue, - * from the interrupt routine to transmit the next - * character, and after a timeout has finished. - */ -ttstart(tp) -register struct tty *tp; -{ - register s; - - s = spl5(); - if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) - (*tp->t_oproc)(tp); - splx(s); -} - -/* - * Called from device's read routine after it has - * calculated the tty-structure given as argument. - */ -ttread(tp) -register struct tty *tp; -{ -register s; - - if ((tp->t_state&CARR_ON)==0) - return(-1); - s = spl5(); - if (tp->t_canq.c_cc==0) - while (canon(tp)<0) - if (tp->t_chan==NULL) { - sleep((caddr_t)&tp->t_rawq, TTIPRI); - } else { - splx(s); - return(0); - } - splx(s); - while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) - ; - return(tp->t_rawq.c_cc+tp->t_canq.c_cc); -} - -/* - * Called from the device's write routine after it has - * calculated the tty-structure given as argument. - */ -caddr_t -ttwrite(tp) -register struct tty *tp; -{ - /* - * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL - * AND MUST NOT BE CHANGED WITHOUT PATCHING - * THE 'ASM' INLINES BELOW. WATCH OUT. - */ - register char *cp; - register int cc, ce; - register i; - char obuf[OBUFSIZ]; - - if ((tp->t_state&CARR_ON)==0) - return(NULL); - while (u.u_count) { - cc = MIN(u.u_count, OBUFSIZ); - cp = obuf; - iomove(cp, (unsigned)cc, B_WRITE); - if (u.u_error) - break; - (void) spl5(); - while (tp->t_outq.c_cc > TTHIWAT) { - ttstart(tp); - tp->t_state |= ASLEEP; - if (tp->t_chan) { - u.u_base -= cc; - u.u_offset -= cc; - u.u_count += cc; - (void) spl0(); - return((caddr_t)&tp->t_outq); - } - sleep((caddr_t)&tp->t_outq, TTOPRI); - } - (void) spl0(); - if (tp->t_flags&LCASE) { - while (cc--) - ttyoutput(*cp++,tp); - continue; - } - while (cc) { - if (tp->t_flags&RAW) - ce=cc; - else { -#ifdef VAX - asm(" scanc r9,(r10),_partab,$077"); - asm(" subl3 r0,r9,r8"); -#else - ce=0; - while(((partab[*(cp+ce)]&077)==0)&&(cet_outq); - ce-=i; - tk_nout+=ce; - tp->t_col+=ce; - cp+=ce; - cc-=ce; -check: - if (tp->t_outq.c_cc > TTHIWAT) { - (void) spl5(); - while (tp->t_outq.c_cc > TTHIWAT) { - ttstart(tp); - tp->t_state |= ASLEEP; - sleep((caddr_t)&tp->t_outq, TTOPRI); - } - (void) spl0(); - } - } - } - ttstart(tp); - return(NULL); -}