#
/*
 *	Copyright 1973 Bell Telephone Laboratories Inc
 */

/*
 *	DH-11 driver
 *	This driver calls on the DHDM driver.
 *	If the DH has no DM11-BB, then this driver will
 *	be fake. To insure loading of the correct DM code,
 *	lib2 should have dhdm.o dh.o and dhfdm.o in that order.
 */

#include "../param.h"
#include "../conf.h"
#include "../user.h"
#include "../tty.h"
#include "../proc.h"

#define	DHADDR	0160020
#define	NDH11	16

struct	tty dh11[NDH11];
int	ndh11	NDH11;

#define	BITS6	01
#define	BITS7	02
#define	BITS8	03
#define	PENABLE	020
#define	OPAR	040	/* beware DEC manuals */
#define	HDUPLX	040000

#define	IENABLE	030100
#define	PERROR	010000
#define	FRERROR	020000
#define	SSPEED	7	/* standard speed: 300 baud */

#define	PS	0177776

int	dhsar;
struct dhregs {
	int dhcsr;
	int dhnxch;
	int dhlpr;
	int dhcar;
	int dhbcr;
	int dhbar;
	int dhbreak;
	int dhsilo;
};

dhopen(dev, flag)
{
	register struct tty *tp;
	extern dhstart();

	if (dev.d_minor >= NDH11) {
		u.u_error = ENXIO;
		return;
	}
	tp = &dh11[dev.d_minor];
	tp->t_addr = dhstart;
	DHADDR->dhcsr =| IENABLE;
	tp->t_state =| WOPEN|SSTART;
	if ((tp->t_state&ISOPEN) == 0) {
		tp->t_quit = 034;		/* FS */
		tp->t_intrup = 0177;		/* DEL */
		tp->t_speeds = SSPEED | (SSPEED<<8);
		tp->t_flags = ODDP|EVENP|ECHO;
		dhparam(tp);
	}
	dmopen(dev);
	tp->t_state =& ~WOPEN;
	tp->t_state =| ISOPEN;
	if (u.u_procp->p_ttyp == 0)
		u.u_procp->p_ttyp = tp;
}

dhclose(dev)
{
	register struct tty *tp;

	(tp = &dh11[dev.d_minor])->t_state =& (CARR_ON|SSTART);
	wflushtty(tp);
}

dhread(dev)
{
	register struct tty *tp;

	tp = &dh11[dev.d_minor];
	if ((tp->t_state&CARR_ON) != 0)
		ttread(tp);
}

dhwrite(dev)
{
	register struct tty *tp;

	tp = &dh11[dev.d_minor];
	if ((tp->t_state&CARR_ON) != 0)
		ttwrite(tp);
}

dhrint()
{
	register struct tty *tp;
	register int c;

	while ((c = DHADDR->dhnxch) < 0) {	/* char. present */
		tp = &dh11[(c>>8)&017];
		if (tp >= &dh11[NDH11])
			continue;
		if((tp->t_state&ISOPEN)==0 || (c&PERROR)) {
			wakeup(tp);
			continue;
		}
		if (c&FRERROR)		/* break, return null */
			c = 0;
		ttyinput(c, tp);
	}
}

dhsgtty(dev, av)
int *av;
{
	register struct tty *tp;
	register r;
	register int *v;

	tp = &dh11[dev.d_minor];
	v = av;
	if (v) {
		*v++ = tp->t_speeds;
		*v++ = 0;
		*v++ = tp->t_flags;
		return;
	}
	wflushtty(tp);
	tp->t_speeds = u.u_arg[0];
	tp->t_flags = u.u_arg[2];
	dhparam(tp);
}

dhparam(atp)
struct tty *atp;
{
	register struct tty *tp;
	register int lpr;

	tp = atp;
	spl5();
	DHADDR->dhcsr.lobyte = (tp - dh11) | IENABLE;
	lpr = (tp->t_speeds.hibyte<<10) | (tp->t_speeds.lobyte<<6);
	if (tp->t_speeds.lobyte == 4)		/* 134.5 baud */
		lpr =| BITS6|PENABLE|HDUPLX; else
		if (tp->t_flags&EVENP)
			if (tp->t_flags&ODDP)
				lpr =| BITS8; else
				lpr =| BITS7|PENABLE; else
			lpr =| BITS7|OPAR|PENABLE;
	DHADDR->dhlpr = lpr;
	spl0();
}

dhxint()
{
	register struct tty *tp;
	register ttybit, bar;

	bar = DHADDR->dhbar;
	DHADDR->dhcsr =& ~0101060;
	bar = (bar|dhsar)^bar;
	ttybit = 1;
	for (tp = dh11; tp < &dh11[NDH11]; tp++) {
		if(bar&ttybit) {
			dhsar =& ~ttybit;
			tp->t_state =& ~BUSY;
			dhstart(tp);
		}
		ttybit =<< 1;
	}
}

dhstart(atp)
struct tty *atp;
{
	extern ttrstrt();
	register lineno, c;
	register struct tty *tp;
	int sps;
	struct { int int; };

	sps = PS->int;
	spl5();
	tp = atp;
	if (tp->t_state&(TIMEOUT|BUSY) || (tp->t_outq.c_cc==0))
		return;
	if ((c = getc(&tp->t_outq))<=0177) {
		tp->t_char = c;
		lineno = tp-dh11;
		DHADDR->dhcsr.lobyte = lineno | IENABLE;
		DHADDR->dhcar = &tp->t_char;
		DHADDR->dhbcr = -1;
		lineno = 1<<lineno;
		DHADDR->dhbar =| lineno;
		dhsar =| lineno;
		tp->t_state =| BUSY;
	} else {
		timeout(ttrstrt, tp, (c&0177)+6);
		tp->t_state =| TIMEOUT;
	}
	if (tp->t_outq.c_cc == 0 || tp->t_outq.c_cc == TTLOWAT)
		wakeup(&tp->t_outq);
	PS->int = sps;
}
