static char rcsid[] = "$Header: tty_bk.c,v 820.1 86/12/04 19:58:55 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*	tty_bk.c	6.1	83/07/29	*/

#include "bk.h"

#if NBK > 0
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/ioctl.h"
#include "../h/tty.h"
#include "../h/proc.h"
#include "../h/inode.h"
#include "../h/file.h"
#include "../h/conf.h"
#include "../h/buf.h"
#include "../h/uio.h"
#include "../s32dev/circbuf.h"
#include "../h/bk.h"

/*
** This line disc. was previously changed by John Rieser 
** to work like a circular buffer. It is NOT the real
** bk line discipline and probably should be given
** it's own name. -- Chris Winters  6/27/86
*/ 

/*
 * Line discipline for Berkeley network.
 *
 * This supplies single lines to a user level program
 * with a minimum of fuss.  Lines are newline terminated.
 *
 * 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.
 */
/*ARGSUSED*/
bkopen(dev, tp)
	dev_t dev;
	register struct tty *tp;
{
	register struct buf *bp;
	register union cb2 *cbp;

	if (tp->t_line == NETLDISC)
		return (EBUSY);	/* sometimes the network opens /dev/tty */
	ttyflush(tp, FREAD|FWRITE);
	bp = geteblk(BKBUFSIZ);
	tp->t_bufp = bp;
	cbp = (union cb2 *)(bp->b_un.b_addr);
	cbp->cb2fwa=8; cbp->cb2in=8; cbp->cb2out=8; cbp->cb2lwa=BKBUFSIZ;
	tp->t_cp = cbp->cb2in+(char *)cbp;
	tp->t_inbuf = 0;
	tp->t_rec = 0;
	return (0);
}

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

	s = spl5();
	wakeup((caddr_t)&tp->t_rawq);
	if (tp->t_bufp) {
		brelse(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 = 0;		/* paranoid: avoid races */
	splx(s);
}

#define BKWATER 256
/*
 * 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, uio)
	register struct tty *tp;
	struct uio *uio;
{
	register union cb2 *cbp=(union cb2 *)(tp->t_bufp->b_un.b_addr);
	register int s;

	if ((tp->t_state&TS_CARR_ON)==0)
		return (-1);
	if (tp->t_flags&RAW && tp->t_rec==0 && cbp->cb2in!=cbp->cb2out)
		tp->t_rec=1;  /* TIOCSET became RAW with partial line */
	s = spl5();
	while (tp->t_rec == 0 && tp->t_line == NETLDISC) {
		tp->t_state|=TS_ISLEEP; sleep((caddr_t)&tp->t_rawq, TTIPRI);
	}
	splx(s);
	if (tp->t_line != NETLDISC)
		return (-1);
	for (;;) {
		register char *p;
		register int n=cbp->cb2in-cbp->cb2out;
		register int error;
		if (n==0) tp->t_rec=0;
		if (n<0) n=cbp->cb2lwa-cbp->cb2out;  /* off end */
		if (n>uio->uio_resid) n=uio->uio_resid;
		if (n<=0) return(0);
		if (error=uiomove(p=cbp->cb2out+(char *)cbp,n,UIO_READ,uio))
			return(error);
		if (!(tp->t_flags&RAW)) for (s=n; --s>=0; )
			if (0x7F&*p++=='\n') tp->t_rec--;
		n+=cbp->cb2out; if (n>=cbp->cb2lwa) n=cbp->cb2fwa;
		cbp->cb2out=n;
		if (0>(n=cbp->cb2in-n)) n+=cbp->cb2lwa-cbp->cb2fwa;
		if (tp->t_flags&RAW) tp->t_rec=n;
		if (n<BKWATER) tp->t_state&=~TS_TBLOCK;  /* nearly empty */
	}
}

/*
 * 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;
{
	register union cb2 *cbp=(union cb2 *)(tp->t_bufp->b_un.b_addr);
	register int n;

	*tp->t_cp++=c; cbp->cb2in++;
	if (cbp->cb2in>=cbp->cb2lwa) {
		cbp->cb2in=cbp->cb2fwa;
		tp->t_cp=cbp->cb2fwa+(char *)cbp;
	}
	if (0>(n=cbp->cb2out-cbp->cb2in)) n+=cbp->cb2lwa-cbp->cb2fwa;
	if (n<BKWATER) tp->t_state|=TS_TBLOCK;  /* nearly full */
	c&=0x7F;
	if (tp->t_flags&RAW || c=='\n') {
		if (tp->t_flags&RAW) tp->t_rec=n;
		else tp->t_rec++;
		if (tp->t_state&TS_ISLEEP || tp->t_rsel) {
			tp->t_state&=~TS_ISLEEP; ttwakeup(tp);
		}
	}
}

/*
 * 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, data, flag)
	struct tty *tp;
	caddr_t data;
{

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

	case TIOCSETD:
#ifdef s32
	case TIOCSETP: case TIOCSETN: case TIOCSET: case TIOCBIS: case TIOCBIC:
#endif s32
	case TIOCGETD:
	case TIOCGETP:
	case TIOCGETC:
		return (-1);
	}
	return (ENOTTY);
}
#endif
