+ break;
+
+ case FWRITE:
+ if (tp->t_outq.c_cc <= TTLOWAT(tp))
+ goto win;
+ if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
+ tp->t_state |= TS_WCOLL;
+ else
+ tp->t_wsel = u.u_procp;
+ break;
+ }
+ splx(s);
+ return (0);
+win:
+ splx(s);
+ return (1);
+}
+
+#define OBUFSIZ 100
+
+/*
+ * routine called on opens while tp->t_line == NTTYDISC
+ * establishes a process group for distribution of
+ * quits and interrupts from the tty.
+ * (actually, pp->p_pgrp can't be 0 when this routine
+ * is called since NTTYDISC is not the default discipline)
+ */
+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 &= ~TS_WOPEN;
+ tp->t_state |= TS_ISOPEN;
+ if (tp->t_line != NTTYDISC)
+ wflushtty(tp);
+}
+
+/*
+ * clean tp on last close
+ */
+ttyclose(tp)
+ register struct tty *tp;
+{
+
+ if (tp->t_line) {
+ wflushtty(tp);
+ tp->t_line = 0;
+ return;
+ }
+ tp->t_pgrp = 0;
+ wflushtty(tp);
+ tp->t_state = 0;
+}
+
+/*
+ * reinput pending characters after state switch
+ * call at spl5().
+ */
+ttypend(tp)
+ register struct tty *tp;
+{
+ struct clist tq;
+ register c;
+
+ tp->t_local &= ~LPENDIN;
+ tp->t_lstate |= LSTYPEN;
+ tq = tp->t_rawq;
+ tp->t_rawq.c_cc = 0;
+ tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
+ while ((c = getc(&tq)) >= 0)
+ ttyinput(c, tp);
+ tp->t_lstate &= ~LSTYPEN;
+}
+
+/*
+ * 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;
+ int i;
+
+ if (tp->t_local&LPENDIN)
+ ttypend(tp);
+ tk_nin++;
+ c &= 0377;
+ t_flags = tp->t_flags;
+ if (t_flags&TANDEM)
+ ttyblock(tp);
+ if ((t_flags&RAW)==0) {
+ if ((tp->t_lstate&LSTYPEN) == 0)
+ c &= 0177;
+ /* check for literal nexting very first */
+ if (tp->t_lstate&LSLNCH) {
+ c |= 0200;
+ tp->t_lstate &= ~LSLNCH;
+ }
+ if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
+ if (tp->t_flags&ECHO)
+ ttyout("^\b", tp);
+ tp->t_lstate |= LSLNCH;
+ /* check for output control functions */
+ } else if (c==tun.t_stopc) {
+ if ((tp->t_state&TS_TTSTOP)==0) {
+ tp->t_state |= TS_TTSTOP;
+ (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
+ return;
+ }
+ if (c!=tun.t_startc)
+ return;
+ } else if (c==tun.t_startc) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_local &= ~LFLUSHO;
+ ttstart(tp);
+ return;
+ } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
+ if (tp->t_local & LFLUSHO)
+ tp->t_local &= ~LFLUSHO;
+ else {
+ flushtty(tp, FWRITE);
+ ttyecho(c, tp);
+ if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
+ ttyretype(tp);
+ tp->t_local |= LFLUSHO;
+ }
+ ttstart(tp);
+ return;
+ } else if (c==tun.t_intrc || c==tun.t_quitc ||
+ (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
+ if ((tp->t_local & LNOFLSH) == 0)
+ flushtty(tp,
+ c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
+ ttyecho(c, tp);
+ c = c==tun.t_intrc ? SIGINT :
+ ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
+ ttsignal(tp, c);
+ /* check for buffer editing functions - cooked mode */
+ } else if ((t_flags&CBREAK) == 0) {
+ if ((tp->t_lstate&LSQUOT) &&
+ (c==tp->t_erase||c==tp->t_kill)) {
+ ttyrub(unputc(&tp->t_rawq), tp);
+ c |= 0200;
+ }
+ if (c==tp->t_erase) {
+ if (tp->t_rawq.c_cc)
+ ttyrub(unputc(&tp->t_rawq), tp);
+ } else if (c==tp->t_kill) {
+ if (tp->t_local&LCRTKIL &&
+ tp->t_rawq.c_cc == tp->t_rocount) {
+ while (tp->t_rawq.c_cc)
+ ttyrub(unputc(&tp->t_rawq), tp);
+ } else {
+ ttyecho(c, tp);
+ ttyecho('\n', tp);
+ while (getc(&tp->t_rawq) > 0)
+ ;
+ tp->t_rocount = 0;
+ }
+ tp->t_lstate = 0;
+ } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
+ if (tp->t_rawq.c_cc == 0)
+ goto out;
+ do {
+ c = unputc(&tp->t_rawq);
+ if (c != ' ' && c != '\t')
+ goto erasenb;
+ ttyrub(c, tp);
+ } while (tp->t_rawq.c_cc);
+ goto out;
+ erasenb:
+ do {
+ ttyrub(c, tp);
+ if (tp->t_rawq.c_cc == 0)
+ goto out;
+ c = unputc(&tp->t_rawq);
+ } while (c != ' ' && c != '\t');
+ (void) putc(c, &tp->t_rawq);
+ } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
+ ttyretype(tp);
+ /* check for cooked mode input buffer overflow */
+ } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
+ ;
+ /* put data char in q for user and wakeup if a break char */
+ } else if (putc(c, &tp->t_rawq) >= 0) {
+ if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
+ && tp->t_line == NTTYDISC)
+ (void) ttyoutput(CTRL(g), tp);
+ if (!ttbreakc(c, tp)) {
+ if (tp->t_rocount++ == 0)
+ tp->t_rocol = tp->t_col;
+ } else {
+ tp->t_rocount = 0;
+ catq(&tp->t_rawq, &tp->t_canq);
+ /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
+ ttwakeup(tp);
+ }
+ tp->t_lstate &= ~LSQUOT;
+ if (c == '\\')
+ tp->t_lstate |= LSQUOT;
+ if (tp->t_lstate&LSERASE) {
+ tp->t_lstate &= ~LSERASE;
+ (void) ttyoutput('/', tp);
+ }
+ i = tp->t_col;
+ ttyecho(c, tp);
+ if (c==tun.t_eofc && tp->t_flags&ECHO) {
+ i = MIN(2, tp->t_col - i);
+ while (i > 0) {
+ (void) ttyoutput('\b', tp);
+ i--;
+ }
+ }
+ }
+ /* CBREAK mode */
+ } else if (tp->t_rawq.c_cc > TTYHOG) {
+ if (tp->t_outq.c_cc < TTHIWAT(tp) &&
+ tp->t_line == NTTYDISC)
+ (void) ttyoutput(CTRL(g), tp);
+ } else if (putc(c, &tp->t_rawq) >= 0) {
+ ttwakeup(tp);
+ ttyecho(c, tp);
+ }
+ /* RAW mode */
+ } else if (tp->t_rawq.c_cc > TTYHOG)
+ flushtty(tp, FREAD|FWRITE);
+ else {
+ if (putc(c, &tp->t_rawq) >= 0)
+ ttwakeup(tp);
+ ttyecho(c, tp);
+ }
+out:
+ if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
+ tun.t_startc != tun.t_stopc)
+ return;
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_local &= ~LFLUSHO;
+ 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.
+ * Returns < 0 if putc succeeds, otherwise returns char to resend
+ * Must be recursive.
+ */
+ttyoutput(c, tp)
+ register c;
+ register struct tty *tp;
+{
+ register char *colp;
+ register ctype;
+
+ if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
+ if (tp->t_local&LFLUSHO)
+ return (-1);
+ if (putc(c, &tp->t_outq))
+ return (c);
+ tk_nout++;
+ return (-1);
+ }
+ /*
+ * Ignore EOT in normal mode to avoid hanging up
+ * certain terminals.
+ */
+ c &= 0177;
+ if (c==CEOT && (tp->t_flags&CBREAK)==0)
+ return (-1);
+ /*
+ * Turn tabs to spaces as required
+ */
+ if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
+ register int s;
+
+ c = 8 - (tp->t_col&7);
+ if ((tp->t_local&LFLUSHO) == 0) {
+ s = spl5(); /* don't interrupt tabs */
+ c -= b_to_q(" ", c, &tp->t_outq);
+ tk_nout += c;
+ splx(s);
+ }
+ tp->t_col += c;
+ return (c ? -1 : '\t');
+ }
+ tk_nout++;
+ /*
+ * for upper-case-only terminals,
+ * generate escapes.
+ */
+ if (tp->t_flags&LCASE) {
+ colp = "({)}!|^~'`";
+ while (*colp++)
+ if (c == *colp++) {
+ if (ttyoutput('\\', tp) >= 0)
+ return (c);
+ c = colp[-2];
+ break;
+ }
+ if ('A'<=c && c<='Z') {
+ if (ttyoutput('\\', tp) >= 0)
+ return (c);
+ } else if ('a'<=c && c<='z')
+ c += 'A' - 'a';
+ }
+ /*
+ * turn <nl> to <cr><lf> if desired.
+ */
+ if (c=='\n' && tp->t_flags&CRMOD)
+ if (ttyoutput('\r', tp) >= 0)
+ return (c);
+ if (c=='~' && tp->t_local<ILDE)
+ c = '`';
+ if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
+ return (c);
+ /*
+ * 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) {
+
+ case ORDINARY:
+ (*colp)++;
+
+ case CONTROL:
+ break;
+
+ case BACKSPACE:
+ if (*colp)
+ (*colp)--;
+ break;
+
+ case NEWLINE:
+ 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;
+
+ case TAB:
+ ctype = (tp->t_flags >> 10) & 03;
+ if (ctype == 1) { /* tty 37 */
+ c = 1 - (*colp | ~07);
+ if (c < 5)
+ c = 0;
+ }
+ *colp |= 07;
+ (*colp)++;
+ break;
+
+ case VTAB:
+ if (tp->t_flags & VTDELAY) /* tty 37 */
+ c = 0177;
+ break;
+
+ case RETURN:
+ 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 && (tp->t_local&LFLUSHO) == 0)
+ (void) putc(c|0200, &tp->t_outq);
+ return (-1);
+}
+
+/*
+ * Called from device's read routine after it has
+ * calculated the tty-structure given as argument.
+ */
+ttread(tp, uio)
+ register struct tty *tp;
+ struct uio *uio;
+{
+ register struct clist *qp;
+ register c, first;
+
+ if ((tp->t_state&TS_CARR_ON)==0)