/* @(#)tt1.c	1.4 */
/*
 * Line discipline 0
 * No Virtual Terminal Handling
 */

#include "sys/param.h"
#include "sys/types.h"
#include "sys/systm.h"
#include "sys/conf.h"
#include "sys/dir.h"
#include "sys/signal.h"
#include "sys/user.h"
#include "sys/errno.h"
#include "sys/proc.h"
#include "sys/file.h"
#include "sys/tty.h"
#include "sys/termio.h"
#include "sys/sysinfo.h"
#include "sys/var.h"
#include "sys/reg.h"

extern char partab[];

/*
 * routine called on first teletype open.
 * establishes a process group for distribution
 * of quits and interrupts from the tty.
 */
ttopen(tp)
register struct tty *tp;
{
	register struct proc *pp;

	pp = u.u_procp;
	if ((pp->p_pid == pp->p_pgrp)
	 && (u.u_ttyp == NULL)
	 && (tp->t_pgrp == 0)) {
		u.u_ttyp = &tp->t_pgrp;
		tp->t_pgrp = pp->p_pgrp;
	}
	ttioctl(tp, LDOPEN, 0, 0);
	tp->t_state &= ~WOPEN;
	tp->t_state |= ISOPEN;
}

ttclose(tp)
register struct tty *tp;
{
	if ((tp->t_state&ISOPEN) == 0)
		return;
	tp->t_state &= ~ISOPEN;
	tp->t_pgrp = 0;
	ttioctl(tp, LDCLOSE, 0, 0);
}

/*
 * Called from device's read routine after it has
 * calculated the tty-structure given as argument.
 */
ttread(tp)
register struct tty *tp;
{
	register struct user *up;
	register struct clist *tq;

	up = &u;
	tq = &tp->t_canq;
	if (tq->c_cc == 0)
		canon(tp);
	while (up->u_count!=0 && up->u_error==0) {
		if (up->u_count >= CLSIZE) {
			register n;
			register struct cblock *cp;

			if ((cp = getcb(tq)) == NULL)
				break;
			n = MIN(up->u_count,
				(unsigned)(cp->c_last - cp->c_first));
			if (copyout((caddr_t)&cp->c_data[cp->c_first],
				(caddr_t)up->u_base, n))
				up->u_error = EFAULT;
			putcf((struct cblock *)cp);
			up->u_base += n;
			up->u_count -= n;
		} else {
			register c;

			if ((c = getc(tq)) < 0)
				break;
			if (subyte(up->u_base++, c))
				up->u_error = EFAULT;
			up->u_count--;
		}
	}
	if (tp->t_state&TBLOCK) {
		if (tp->t_rawq.c_cc<TTXOLO) {
			(*tp->t_proc)(tp, T_UNBLOCK);
		}
	}
}

/*
 * Called from device's write routine after it has
 * calculated the tty-structure given as argument.
 */
ttwrite(tp)
register struct tty *tp;
{
	register struct cblock *cp;
	register struct user *up;
	register a, n;

	if (!(tp->t_state&CARR_ON))
		return;
	up = &u;
	a = tthiwat[tp->t_cflag&CBAUD];
	if (up->u_count <= 4 && up->u_ar0[R0] & 0x80000000) {
		n = up->u_arg[3];
		SPL6();
		while (tp->t_outq.c_cc > a) {
			(*tp->t_proc)(tp, T_OUTPUT);
			/*
			 * For non-interrupting output devices sleep
			 * only when characters are still pending.
			 */
			if (tp->t_state&(TIMEOUT|TTSTOP|BUSY)) {
				tp->t_state |= OASLP;
				(void) sleep((caddr_t)&tp->t_outq, TTOPRI);
			}
		}
		SPL0();
		while (up->u_count) {
			ttxput(tp, n&0xFF, 0);
			up->u_base++;
			up->u_count--;
			n >>= 8;
		}
	} else 
	while (up->u_count) {
		SPL6();
		while (tp->t_outq.c_cc > a) {
			(*tp->t_proc)(tp, T_OUTPUT);
			/*
			 * For non-interrupting output devices sleep
			 * only when characters are still pending.
			 */
			if (tp->t_state&(TIMEOUT|TTSTOP|BUSY)) {
				tp->t_state |= OASLP;
				(void) sleep((caddr_t)&tp->t_outq, TTOPRI);
			}
		}
		SPL0();
		if (up->u_count >= (CLSIZE/4)) {
			if ((cp = getcf()) == NULL)
				break;
			n = MIN(up->u_count, (unsigned)cp->c_last);
			if (copyin((caddr_t)up->u_base, (caddr_t)cp->c_data,
				n)) {
				up->u_error = EFAULT;
				putcf((struct cblock *)cp);
				break;
			}
			/*
			 * Put trailing '\n' in a separate cblock
			 */
			if (n==up->u_count && cp->c_data[n-1]=='\n' && n>=3)
				n--;
			up->u_base += n;
			up->u_count -= n;
			cp->c_last = n;
			ttxput(tp, cp, n);
		} else {
			n = fubyte(up->u_base++);
			if (n<0) {
				up->u_error = EFAULT;
				break;
			}
			up->u_count--;
			ttxput(tp, n, 0);
		}
	}
	spltty();
	if (!(tp->t_state&BUSY))
		(*tp->t_proc)(tp, T_OUTPUT);
	SPL0();
}

/*
 * Place a character on raw TTY input queue, putting in delimiters
 * and waking up top half as needed.
 * Also echo if required.
 */
#define	LCLESC	0400

ttin(tp)
register struct tty *tp;
{
	register c;
	register flg;
	register char *cp;
	ushort nchar, nc;

	nchar = tp->t_rbuf.c_size - tp->t_rbuf.c_count;
	/* reinit rx control block */
	tp->t_rbuf.c_count = tp->t_rbuf.c_size;
	if (nchar==0)
		return;
	flg = tp->t_iflag;
	nc = nchar;
	cp = tp->t_rbuf.c_ptr;
	if (nc < cfreelist.c_size || (flg & (INLCR|IGNCR|ICRNL|IUCLC))) {
			/* must do per character processing */
		for ( ;nc--; cp++) {
			c = *cp;
			if (c == '\n' && flg&INLCR)
				*cp = c = '\r';
			else if (c == '\r')
				if (flg&IGNCR)
					continue;
				else if (flg&ICRNL)
					*cp = c = '\n';
			if (flg&IUCLC && 'A' <= c && c <= 'Z')
				c += 'a' - 'A';
			if (putc(c, &tp->t_rawq))
				continue;
			sysinfo.rawch++;
		}
		cp = tp->t_rbuf.c_ptr;
	} else {
		/* may do block processing */
		putcb(CMATCH((struct cblock *)cp), &tp->t_rawq);
		sysinfo.rawch += nc;
		/* allocate new rx buffer */
		if ((tp->t_rbuf.c_ptr = getcf()->c_data)
			== ((struct cblock *)NULL)->c_data) {
			tp->t_rbuf.c_ptr = NULL;
			return;
		}
		tp->t_rbuf.c_count = cfreelist.c_size;
		tp->t_rbuf.c_size = cfreelist.c_size;
	}


	if (tp->t_rawq.c_cc > TTXOHI) {
		if (flg&IXOFF && !(tp->t_state&TBLOCK))
			(*tp->t_proc)(tp, T_BLOCK);
		if (tp->t_rawq.c_cc > TTYHOG) {
			ttyflush(tp, FREAD);
			return;
		}
	}
	flg = lobyte(tp->t_lflag);
	if (tp->t_outq.c_cc > (tthiwat[tp->t_cflag&CBAUD] + TTECHI))
		flg &= ~(ECHO|ECHOK|ECHONL|ECHOE);
	if (flg) while (nchar--) {
		c = *cp++;
		if (flg&ISIG) {
			if (c == tp->t_cc[VINTR]) {
				signal(tp->t_pgrp, SIGINT);
				if (!(flg&NOFLSH))
					ttyflush(tp, (FREAD|FWRITE));
				continue;
			}
			if (c == tp->t_cc[VQUIT]) {
				signal(tp->t_pgrp, SIGQUIT);
				if (!(flg&NOFLSH))
					ttyflush(tp, (FREAD|FWRITE));
				continue;
			}
		}
#ifdef notdef
		if (flg&ICANON) {
			if (tp->t_state&CLESC) {
				flg |= LCLESC;
				tp->t_state &= ~CLESC;
			}
			if (c == '\n') {
				if (flg&ECHONL)
					flg |= ECHO;
				tp->t_delct++;
			} else if (c == '\\') {
				tp->t_state |= CLESC;
				if (flg&XCASE) {
					c |= QESC;
					if (flg&LCLESC)
						tp->t_state &= ~CLESC;
				}
			} else if (c == tp->t_cc[VEOL] || c == tp->t_cc[VEOL2])
				tp->t_delct++;
			else if (!(flg&LCLESC)) {
				if (c == tp->t_cc[VERASE] && flg&ECHOE) {
					if (flg&ECHO)
						ttxput(tp, '\b', 0);
					flg |= ECHO;
					ttxput(tp, ' ', 0);
					c = '\b';
				} else if (c == tp->t_cc[VKILL] && flg&ECHOK) {
					if (flg&ECHO)
						ttxput(tp, c, 0);
					flg |= ECHO;
					c = '\n';
				} else if (c == tp->t_cc[VEOF]) {
					flg &= ~ECHO;
					tp->t_delct++;
				}
			}
		}
		if (flg&ECHO) {
			ttxput(tp, c, 0);
			(*tp->t_proc)(tp, T_OUTPUT);
		}
#else
		if (flg&ICANON) {
			if (c == '\n') {
				if (flg&ECHONL)
					flg |= ECHO;
				tp->t_delct++;
			} else if (c == tp->t_cc[VEOL] || c == tp->t_cc[VEOL2])
				tp->t_delct++;
			if (!(tp->t_state&CLESC)) {
				if (c == '\\')
					tp->t_state |= CLESC;
				if (c == tp->t_cc[VERASE] && flg&ECHOE) {
					if (flg&ECHO)
						ttxput(tp, '\b', 0);
					flg |= ECHO;
					ttxput(tp, ' ', 0);
					c = '\b';
				} else if (c == tp->t_cc[VKILL] && flg&ECHOK) {
					if (flg&ECHO)
						ttxput(tp, c, 0);
					flg |= ECHO;
					c = '\n';
				} else if (c == tp->t_cc[VEOF]) {
					flg &= ~ECHO;
					tp->t_delct++;
				}
			} else {
				if (c != '\\' || (flg&XCASE))
					tp->t_state &= ~CLESC;
			}
		}
		if (flg&ECHO) {
			ttxput(tp, c, 0);
			(*tp->t_proc)(tp, T_OUTPUT);
		}
#endif
	}
	if (!(flg&ICANON)) {
		tp->t_state &= ~RTO;
		if (tp->t_rawq.c_cc >= tp->t_cc[VMIN])
			tp->t_delct = 1;
		else if (tp->t_cc[VTIME]) {
			if (!(tp->t_state&TACT))
				tttimeo(tp);
		}
	}
	if (tp->t_delct && (tp->t_state&IASLP)) {
		tp->t_state &= ~IASLP;
		wakeup((caddr_t)&tp->t_rawq);
	}
}

/*
 * Scan a list of characters and assure that they require no
 * post processing
 */
ttxchk(ncode, cp)
register short ncode;
register unsigned char *cp;
{
	register c, n;

	n = 0;
	ncode--;
	do {
		c = *cp++;
		if (c & 0200)
			return(-1);
		c = partab[c] & 077;
		if (c == 0)
			n++;
		else if (c != 1)
			return(-1);
	} while (--ncode != -1);
	return(n);
}

/*
 * Put character(s) on TTY output queue, adding delays,
 * expanding tabs, and handling the CR/NL bit.
 * It is called both from the base level for output, and from
 * interrupt level for echoing.
 */
/* VARARGS1 */
ttxput(tp, ucp, ncode)
register struct tty *tp;
register ncode;
union {
	struct ch {		/*  machine dependent union */
		char dum[3];
		unsigned char theaddr;
	} ch;
	int thechar;
	struct cblock *ptr;
} ucp;
{
	register struct clist *outqp;
	register unsigned char *cp;
	register c, flg, ctype;
	register char *colp;
	struct cblock *scf;
	int cs;

	flg = tp->t_oflag;
	outqp = &tp->t_outq;
	if (ncode == 0) {
		if (!(flg&OPOST)) {
			sysinfo.outch++;
			(void) putc(ucp.thechar, outqp);
			return;
		}
		ncode++;
		cp = (unsigned char *)&ucp.ch.theaddr;
		scf = NULL;
	} else {
		if (!(flg&OPOST)) {
			sysinfo.outch += ncode;
			putcb(ucp.ptr, outqp);
			return;
		}
		cp = (unsigned char *)&ucp.ptr->c_data[ucp.ptr->c_first];
		scf = ucp.ptr;
	}
	if ((tp->t_lflag&XCASE)==0 && (flg&OLCUC)==0) {
		colp = &tp->t_col;
		if (ncode > 1 && (c = ttxchk(ncode, cp)) >= 0) {
			(*colp) += c;
			sysinfo.outch += ncode;
			putcb(ucp.ptr, outqp);
			return;
		}
		while (ncode--) {
			ctype = partab[c = *cp++] & 077;
			if (ctype==0) {
				(*colp)++;
				sysinfo.outch++;
				(void) putc(c, outqp);
				continue;
			}
			else if (ctype==1) {
				sysinfo.outch++;
				(void) putc(c, outqp);
				continue;
			}
			if (c >= 0200) {
				if (c == QESC)
					(void) putc(QESC, outqp);
				sysinfo.outch++;
				(void) putc(c, outqp);
				continue;
			}
			cs = 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.
			 */
			c = 0;
			switch (ctype) {

			case 0:	/* ordinary */
				(*colp)++;

			case 1:	/* non-printing */
				break;

			case 2:	/* backspace */
				if (flg&BSDLY)
					c = 2;
				if (*colp)
					(*colp)--;
				break;

			case 3:	/* line feed */
				if (flg&ONLRET)
					goto qcr;
				if (flg&ONLCR) {
					if (!(flg&ONOCR && *colp==0)) {
						sysinfo.outch++;
						(void) putc('\r', outqp);
					}
					goto qcr;
				}
			qnl:
				if (flg&NLDLY)
					c = 5;
				break;

			case 4:	/* tab */
				c = 8 - ((*colp)&07);
				*colp += c;
				ctype = flg&TABDLY;
				if (ctype == TAB0) {
					c = 0;
				} else if (ctype == TAB1) {
					if (c < 5)
						c = 0;
				} else if (ctype == TAB2) {
					c = 2;
				} else if (ctype == TAB3) {
					sysinfo.outch += c;
					do
						(void) putc(' ', outqp);
					while (--c);
					continue;
				}
				break;

			case 5:	/* vertical tab */
				if (flg&VTDLY)
					c = 0177;
				break;

			case 6:	/* carriage return */
				if (flg&OCRNL) {
					cs = '\n';
					goto qnl;
				}
				if (flg&ONOCR && *colp == 0)
					continue;
			qcr:
				ctype = flg&CRDLY;
				if (ctype == CR1) {
					if (*colp)
						c = max((unsigned)((*colp>>4) + 3), 6);
				} else if (ctype == CR2) {
					c = 5;
				} else if (ctype == CR3) {
					c = 9;
				}
				*colp = 0;
				break;

			case 7:	/* form feed */
				if (flg&FFDLY)
					c = 0177;
				break;
			}
			sysinfo.outch++;
			(void) putc(cs, outqp);
			if (c) {
				if ((c < 32) && flg&OFILL) {
					if (flg&OFDEL)
						cs = 0177;
					else
						cs = 0;
					(void) putc(cs, outqp);
					if (c > 3)
						(void) putc(cs, outqp);
				} else {
					(void) putc(QESC, outqp);
					(void) putc(c|0200, outqp);
				}
			}
		}
	} else
	while (ncode--) {
		c = *cp++;
		if (c >= 0200) {
	/* spl5-0 */
			if (c == QESC)
				(void) putc(QESC, outqp);
			sysinfo.outch++;
			(void) putc(c, outqp);
			continue;
		}
		/*
		 * Generate escapes for upper-case-only terminals.
		 */
		if (tp->t_lflag&XCASE) {
			colp = "({)}!|^~'`\\\\";
			while(*colp++)
				if (c == *colp++) {
					ttxput(tp, '\\'|0200, 0);
					c = colp[-2];
					break;
				}
			if ('A' <= c && c <= 'Z')
				ttxput(tp, '\\'|0200, 0);
		}
		if (flg&OLCUC && 'a' <= c && c <= 'z')
			c += 'A' - 'a';
		cs = 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.
		 */
		ctype = partab[c];
		colp = &tp->t_col;
		c = 0;
		switch (ctype&077) {

		case 0:	/* ordinary */
			(*colp)++;

		case 1:	/* non-printing */
			break;

		case 2:	/* backspace */
			if (flg&BSDLY)
				c = 2;
			if (*colp)
				(*colp)--;
			break;

		case 3:	/* line feed */
			if (flg&ONLRET)
				goto cr;
			if (flg&ONLCR) {
				if (!(flg&ONOCR && *colp==0)) {
					sysinfo.outch++;
					(void) putc('\r', outqp);
				}
				goto cr;
			}
		nl:
			if (flg&NLDLY)
				c = 5;
			break;

		case 4:	/* tab */
			c = 8 - ((*colp)&07);
			*colp += c;
			ctype = flg&TABDLY;
			if (ctype == TAB0) {
				c = 0;
			} else if (ctype == TAB1) {
				if (c < 5)
					c = 0;
			} else if (ctype == TAB2) {
				c = 2;
			} else if (ctype == TAB3) {
				sysinfo.outch += c;
				do
					(void) putc(' ', outqp);
				while (--c);
				continue;
			}
			break;

		case 5:	/* vertical tab */
			if (flg&VTDLY)
				c = 0177;
			break;

		case 6:	/* carriage return */
			if (flg&OCRNL) {
				cs = '\n';
				goto nl;
			}
			if (flg&ONOCR && *colp == 0)
				continue;
		cr:
			ctype = flg&CRDLY;
			if (ctype == CR1) {
				if (*colp)
					c = max((unsigned)((*colp>>4) + 3), 6);
			} else if (ctype == CR2) {
				c = 5;
			} else if (ctype == CR3) {
				c = 9;
			}
			*colp = 0;
			break;

		case 7:	/* form feed */
			if (flg&FFDLY)
				c = 0177;
			break;
		}
		sysinfo.outch++;
		(void) putc(cs, outqp);
		if (c) {
			if ((c < 32) && flg&OFILL) {
				if (flg&OFDEL)
					cs = 0177;
				else
					cs = 0;
				(void) putc(cs, outqp);
				if (c > 3)
					(void) putc(cs, outqp);
			} else {
				(void) putc(QESC, outqp);
				(void) putc(c|0200, outqp);
			}
		}

	}
	if (scf != NULL)
		putcf(scf);
}

/*
 * Get next packet from output queue.
 * Called from xmit interrupt complete.
 */

ttout(tp)
register struct tty *tp;
{
	register struct ccblock *tbuf;
	register c;
	register char *cptr;
	register retval;
	register struct clist *outqp;
	extern ttrstrt();

	outqp = &tp->t_outq;
	if (tp->t_state&TTIOW && outqp->c_cc==0) {
		tp->t_state &= ~TTIOW;
		wakeup((caddr_t)&tp->t_oflag);
	}
delay:
	tbuf = &tp->t_tbuf;
	if (hibyte(tp->t_lflag)) {
		if (tbuf->c_ptr) {
			putcf(CMATCH((struct cblock *)tbuf->c_ptr));
			tbuf->c_ptr = NULL;
		}
		tp->t_state |= TIMEOUT;
		timeout(ttrstrt, (caddr_t)tp,
			(int)((hibyte(tp->t_lflag)&0177)+6));
		hibyte(tp->t_lflag) = 0;
		return(0);
	}
	retval = 0;
	if (!(tp->t_oflag&OPOST)) {
		if (tbuf->c_ptr)
			putcf(CMATCH((struct cblock *)tbuf->c_ptr));
		if ((tbuf->c_ptr = (char *)getcb(outqp)) == NULL)
			goto out;
			/* return(0); */
		tbuf->c_count = ((struct cblock *)tbuf->c_ptr)->c_last -
				((struct cblock *)tbuf->c_ptr)->c_first;
		tbuf->c_size = tbuf->c_count;
		tbuf->c_ptr = &((struct cblock *)tbuf->c_ptr)->c_data
				[((struct cblock *)tbuf->c_ptr)->c_first];
		retval = CPRES;
	} else {		/* watch for timing	*/
		if (tbuf->c_ptr == NULL) {
			if ((tbuf->c_ptr = getcf()->c_data)
				== ((struct cblock *)NULL)->c_data) {
				tbuf->c_ptr = NULL;
				goto out;
				/* return(0);	/* Add restart? */
			}
		}
		tbuf->c_count = 0;
		cptr = tbuf->c_ptr;
		while ((c=getc(outqp)) >= 0) {
			if (c == QESC) {
				if ((c = getc(outqp)) < 0)
					break;
				if (c > 0200) {
					hibyte(tp->t_lflag) = c;
					if (!retval)
						goto delay;
					break;
				}
			}
			retval = CPRES;
			*cptr++ = c;
			tbuf->c_count++;
			if (tbuf->c_count >= cfreelist.c_size)
				break;
		}
		tbuf->c_size = tbuf->c_count;
	}
out:
	if (tp->t_state&OASLP &&
		outqp->c_cc<=ttlowat[tp->t_cflag&CBAUD]) {
		tp->t_state &= ~OASLP;
		wakeup((caddr_t)outqp);
	}
	return(retval);
}

tttimeo(tp)
register struct tty *tp;
{
	tp->t_state &= ~TACT;
	if (tp->t_lflag&ICANON || tp->t_cc[VTIME] == 0)
		return;
	if (tp->t_rawq.c_cc == 0 && tp->t_cc[VMIN])
		return;
	if (tp->t_state&RTO) {
		tp->t_delct = 1;
		if (tp->t_state&IASLP) {
			tp->t_state &= ~IASLP;
			wakeup((caddr_t)&tp->t_rawq);
		}
	} else {
		tp->t_state |= RTO|TACT;
		timeout(tttimeo, (caddr_t)tp,
			(int)(tp->t_cc[VTIME]*(short)((short)v.v_hz/10)));
	}
}

/*
 * I/O control interface
 */
/* ARGSUSED */
ttioctl(tp, cmd, arg, mode)
register struct tty *tp;
{
	ushort	chg;

	switch(cmd) {
	case LDOPEN:
		if (tp->t_rbuf.c_ptr == NULL) {
			/* allocate RX buffer */
			while((tp->t_rbuf.c_ptr = getcf()->c_data)
				== ((struct cblock *)NULL)->c_data) {
				tp->t_rbuf.c_ptr = NULL;
				cfreelist.c_flag = 1;
				(void) sleep((caddr_t)&cfreelist, TTOPRI);
			}
			tp->t_rbuf.c_count = cfreelist.c_size;
			tp->t_rbuf.c_size  = cfreelist.c_size;
			(*tp->t_proc)(tp, T_INPUT);
		}
		break;

	case LDCLOSE:
		spltty();
		(*tp->t_proc)(tp, T_RESUME);
		SPL0();
		ttywait(tp);
		ttyflush(tp, (FREAD|FWRITE));
		if (tp->t_tbuf.c_ptr) {
			putcf(CMATCH((struct cblock *)tp->t_tbuf.c_ptr));
			tp->t_tbuf.c_ptr = NULL;
			tp->t_tbuf.c_count = 0;
			tp->t_tbuf.c_size = 0;
		}
		if (tp->t_rbuf.c_ptr) {
			putcf(CMATCH((struct cblock *)tp->t_rbuf.c_ptr));
			tp->t_rbuf.c_ptr = NULL;
			tp->t_rbuf.c_count = 0;
			tp->t_rbuf.c_size = 0;
		}
		tp->t_tmflag = 0;
		break;

	case LDCHG:
		chg = tp->t_lflag^arg;
		if (!(chg&ICANON))
			break;
		spltty();
		if (tp->t_canq.c_cc) {
			if (tp->t_rawq.c_cc) {
				tp->t_canq.c_cc += tp->t_rawq.c_cc;
				tp->t_canq.c_cl->c_next = tp->t_rawq.c_cf;
				tp->t_canq.c_cl = tp->t_rawq.c_cl;
			}
			tp->t_rawq = tp->t_canq;
			tp->t_canq = ttnulq;
		}
		tp->t_delct = tp->t_rawq.c_cc;
		SPL0();
		break;

	default:
		break;
	}
}
