#include "param.h"
#include <sys/systm.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/tty.h>
#include <sys/proc.h>
#ifdef	MPX_FILS
#include <sys/mx.h>
#endif
#include <sys/inode.h>
#include <sys/file.h>
#include <sys/conf.h>
#include <sys/buf.h>

/*
 *	SCCS id	@(#)bk.c	2.1 (Berkeley)	8/5/83
 */

#ifdef UCB_NTTY

/*
 * When running dz's using only SAE (silo alarm) on input
 * it is necessary to call dzrint() at clock interrupt time.
 * This is unsafe unless spl5()s in tty code are changed to
 * spl6()s to block clock interrupts.  Note that the dh driver
 * currently in use works the same way as the dz, even though
 * we could try to more intelligently manage its silo.
 * Thus don't take this out if you have no dz's unless you
 * change clock.c and dhtimer().
 */
#define	spl5	spl6

/*
 * Line discipline for Berkeley network.
 *
 * This supplies single lines to a user level program
 * with a minimum of fuss.  Lines are newline terminated.
 * A later version will implement full 8-bit paths by providing
 * an escape sequence to include a newline in a record.
 *
 * This discipline requires that tty device drivers call
 * the line specific l_ioctl routine from their ioctl routines,
 * assigning the result to cmd so that we can refuse most tty specific
 * ioctls which are unsafe because we have ambushed the
 * teletype input queues, overlaying them with other information.
 */

/*
 * Open as networked discipline.  Called when discipline changed
 * with ioctl, this assigns a buffer to the line for input, and
 * changing the interpretation of the information in the tty structure.
 */
bkopen(tp)
register struct tty *tp;
{
	register struct buf *bp;

	if (u.u_error)
		return;		/* paranoia */
	/*
	 * The suser check was added since once it gets set you can't turn
	 * it off, even as root.  Theoretically a setuid root program could
	 * be run over the net which opened /dev/tty but this seems farfetched.
	 */
	if (tp->t_line == NETLDISC && !suser()) {
		u.u_error = EBUSY;		/* sometimes the network */
		return;				/* ... opens /dev/tty */
	}
	bp = geteblk();
	flushtty(tp,FREAD|FWRITE);
	tp->t_bufp = bp;
	tp->t_cp = (char *)bp->b_un.b_addr;
	tp->t_inbuf = 0;
	tp->t_rec = 0;
}

/*
 * Break down... called when discipline changed or from device
 * close routine.
 */
bkclose(tp)
register struct tty *tp;
{
	register s;
	register struct buf *bp;

	s = spl5();
	wakeup((caddr_t)&tp->t_rawq);
	if (tp->t_bufp) {
		abrelse(tp->t_bufp);
		tp->t_bufp = 0;
	} else
		printf("bkclose: no buf\n");
	tp->t_cp = 0;
	tp->t_inbuf = 0;
	tp->t_rec = 0;
	tp->t_line = DFLT_LDISC;		/* paranoid: avoid races */
	splx(s);
}

/*
 * Read from a network line.
 * Characters have been buffered in a system buffer and are
 * now dumped back to the user in one fell swoop, and with a
 * minimum of fuss.  Note that no input is accepted when a record
 * is waiting.  Our clearing tp->t_rec here allows further input
 * to accumulate.
 */
bkread(tp)
register struct tty *tp;
{
	register int i;
	register s;

	if ((tp->t_state&CARR_ON)==0)
		return (-1);
	s = spl5();
	while (tp->t_rec == 0 && tp->t_line == NETLDISC)
		sleep((caddr_t)&tp->t_rawq, TTIPRI);
	splx(s);
	if (tp->t_line != NETLDISC)
		return (-1);
	i = MIN(tp->t_inbuf, (int)u.u_count);
	if (copyout(tp->t_bufp->b_un.b_addr, u.u_base, (unsigned)i)) {
		u.u_error = EFAULT;
		return (-1);
	}
	u.u_count -= i;
	u.u_base += i;
	u.u_offset += i;
	tp->t_cp = (char *)tp->t_bufp->b_un.b_addr;
	tp->t_inbuf = 0;
	tp->t_rec = 0;
	return (0);
}

/*
 * Low level character input routine.
 * Stuff the character in the buffer, and wake up the top
 * half after setting t_rec if this completes the record
 * or if the buffer is (ick!) full.
 *
 * This is where the formatting should get done to allow
 * 8 character data paths through escapes.
 *
 * This routine should be expanded in-line in the receiver
 * interrupt routine of the dh-11 to make it run as fast as possible.
 */
bkinput(c, tp)
register c;
register struct tty *tp;
{

	if (tp->t_rec)
		return;
	*tp->t_cp++ = c;
	if (++tp->t_inbuf == BSIZE || c == '\n') {
		tp->t_rec = 1;
		wakeup((caddr_t)&tp->t_rawq);
	}
}

/*
 * This routine is called whenever a ioctl is about to be performed
 * and gets a chance to reject the ioctl.  We reject all teletype
 * oriented ioctl's except those which set the discipline, and
 * those which get parameters (gtty and get special characters).
 */
/*ARGSUSED*/
bkioctl(tp, cmd, addr)
struct tty *tp;
caddr_t addr;
{

	if ((cmd>>8) != 't')
		return (cmd);
	switch (cmd) {

	case TIOCSETD:
	case TIOCGETD:
	case TIOCGETP:
	case TIOCGETC:
		return (cmd);
	}
	u.u_error = ENOTTY;
	return (0);
}
#endif UCB_NTTY
