AUSAM/sys106/dmr/dh.c

Compare this file to the similar file:
Show the results in this format:

#
/*
**	DH-11 driver
*/

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

/*
**	Configuration definitions
*/

#define	DHADDR	0160060		/* device address */
#define	NDH11	16		/* number of lines */
#define	DHNCH	8		/* max number of DMA chars */
#define	DHSILO	32		/* silo interrupt level must be 0 1 2 4 8 16 or 32 */
#define	DHRATE	2		/* scan rate */
#define	DHSOPEN	0xe0d5		/* single open lines */

/*
**	Tty structures
*/

struct tty	dh11[NDH11];

/*
**	Place from which to do DMA on output
*/

char		dh_clist[NDH11][DHNCH];

/*
**	Miscellaneous Data
*/

int	dhsar;			/* Software copy of last dhbar */
int	dhscanning;		/* Is receiver scanning running */
int	dhopenl;		/* Bit set for each open line */

/*
**	Hardware register layout
*/

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

/*
**	Hardware control bits
*/

#define	BITS6		01
#define	BITS7		02
#define	BITS8		03
#define	TWOSB		04
#define	PENABLE		020
#define	OPAR		040
#define	HDUPLX		040000

#define	IENABLE		0030100
#define	MCLEAR		0004000
#define	PERROR		0010000
#define	FRERROR		0020000
#define	XINT		0100000
#define	SSPEED		13		/* standard speed: 9600 baud */




/*
**	Open a DH11 line.
*/

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

	if (dev.d_minor >= NDH11)
	{
		u.u_error = ENXIO;
		return;
	}
	if ( DHSOPEN & dhopenl & (1<<dev.d_minor) )
	{
		u.u_error = EOPENFAIL;
		return;
	}
	tp = &dh11[dev.d_minor];
	spl5();
	if(dhopenl == 0)
	{
		DHADDR->dhcsr = MCLEAR;
		DHADDR->dhcsr = IENABLE;
		DHADDR->dhsilo = DHSILO;
	}
	if ((tp->t_state&ISOPEN) == 0)
	{
		tp->t_addr = dhstart;
		tp->t_dev = dev;
		tp->t_state =| ISOPEN|CARR_ON|SSTART;
		tp->t_erase = CERASE;
		tp->t_kill = CKILL;
		tp->t_speeds = SSPEED | (SSPEED<<8);
		tp->t_flags = ODDP|EVENP|ECHO|XTABS|CRMOD;
		dhopenl =| 1<<dev.d_minor;
		dhparam(tp);
	}
	if ( dhscanning == 0 )
		dhscan();
	spl0();
	if (u.u_procp->p_ttyp == 0)
		u.u_procp->p_ttyp = tp;
}

/*
**	Close a DH11 line.
*/
dhclose(dev)
{
	register struct tty *tp;

	tp = &dh11[dev.d_minor];
	wflushtty(tp);
	tp->t_state = SSTART;
	if((dhopenl =& ~(1<<dev.d_minor)) == 0)
		DHADDR->dhcsr = 0;
}

/*
**	Read from a DH11 line.
*/
dhread(dev)
{
	ttread(&dh11[dev.d_minor]);
}

/*
**	write on a DH11 line
*/
dhwrite(dev)
{
	ttwrite(&dh11[dev.d_minor]);
}

/*
**	DH11 input scanning
*/
dhscan()
{
	register struct tty *	tp;

	if(dhopenl)
	{
		dhscanning = timeout(dhscan, 0, DHRATE);
		dhrint();
		for ( tp = dh11 ; tp < &dh11[NDH11] ; tp++ )
			if ( (tp->t_state & TIMEOUT) && --tp->t_char <= 0 )
			{
				tp->t_char = 0;
				tp->t_state =& ~TIMEOUT;
				dhstart(tp);
			}
	}
	else
		dhscanning = 0;
}

/*
**	DH11 receiver interrupt.
*/
dhrint()
{
	register struct tty *tp;
	register int c;

	while ((c = DHADDR->dhnxch) < 0)
	{	/* char. present */
		tp = &dh11[(c>>8)&017];
		if((tp->t_state&ISOPEN)==0 || (c&PERROR))
		{
			wakeup(tp);
			continue;
		}
		if (c&FRERROR)		/* break */
			if (tp->t_flags&RAW)
				c = 0;		/* null (for getty) */
			else
				c = 0177;	/* DEL (intr) */
		if ( c & PERROR )	/* parity */
			continue;	/* ignored */
		ttyinput(c, tp);
	}
}

/*
**	stty/gtty for DH11
*/

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

	tp = &dh11[dev.d_minor];
	if (ttystty(tp, av))
		return;
	spl5();
	dhparam(tp);
	spl0();
}

/*
**	Set parameters from open or stty into the DH hardware
**	registers.
*/

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

	tp = atp;
	lpr = (tp->t_speeds.hibyte<<10) | (tp->t_speeds.lobyte<<6);
	if (tp->t_flags&EVENP)
		if (tp->t_flags&ODDP)
			lpr =| BITS8;
		else
			lpr =| BITS7|PENABLE;
	else
		if ( tp->t_flags&ODDP )
			lpr =| BITS7|OPAR|PENABLE;
		else
			lpr =| BITS8;
	if (tp->t_speeds.lobyte == 3)	/* 110 baud */
		lpr =| TWOSB;
	delay(5);	/* delay while controller flushes */
	DHADDR->dhcsr.lobyte = tp->t_dev.d_minor | IENABLE;
	DHADDR->dhlpr = lpr;
}

/*
**	DH11 transmitter interrupt.
**	Restart each line which used to be active but has
**	terminated transmission since the last interrupt.
*/

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

	bar = dhsar & ~DHADDR->dhbar;
	DHADDR->dhcsr =& ~XINT;
	ttybit = 1;
	for (tp = dh11; bar; tp++)
	{
		if(bar&ttybit)
		{
			dhsar =& ~ttybit;
			bar =& ~ttybit;
			tp->t_state =& ~BUSY;
			dhstart(tp);
		}
		ttybit =<< 1;
	}
}

/*
**	Start (restart) transmission on the given DH11 line.
*/

dhstart(tp)
	register struct tty *tp;
{
	extern ttrstrt();
	register c, nch;
	char *cp;

	/*
	**	If it's currently active, or delaying,
	**	no need to do anything.
	*/
	if (tp->t_state&(TIMEOUT|BUSY))
		return;
	/*
	**	t_char is a delay indicator which may have been
	**	left over from the last start.
	**	Arrange for the delay.
	*/
	if (c = tp->t_char)
	{
		tp->t_char = (((c&0177)+(DHRATE-1))/DHRATE)+1;
		tp->t_state =| TIMEOUT;
		return;
	}
	cp = dh_clist[tp->t_dev.d_minor];
	nch = 0;
	/*
	**	Copy DHNCH characters, or up to a delay indicator,
	**	to the DMA area.
	*/
	while (nch > -DHNCH && (c = getc(&tp->t_outq))>=0)
	{
		if (c >= 0200 && tp->t_flags != RAW)
		{
			tp->t_char = c;
			break;
		}
		*cp++ = c;
		nch--;
	}
	/*
	**	If the writer was sleeping on output overflow,
	**	wake him when low tide is reached.
	*/
	if (tp->t_outq.c_cc<=TTLOWAT && tp->t_state&ASLEEP)
	{
		tp->t_state =& ~ASLEEP;
		wakeup(&tp->t_outq);
	}
	/*
	**	If any characters were set up, start transmission;
	**	otherwise, check for possible delay.
	*/
	if (nch)
	{
		DHADDR->dhcsr.lobyte = tp->t_dev.d_minor | IENABLE;
		DHADDR->dhcar = cp+nch;
		DHADDR->dhbcr = nch;
		c = 1<<tp->t_dev.d_minor;
		DHADDR->dhbar =| c;
		dhsar =| c;
		tp->t_state =| BUSY;
	}
	else
	if (c = tp->t_char)
	{
		tp->t_char = (((c&0177)+(DHRATE-1))/DHRATE)+1;
		tp->t_state =| TIMEOUT;
	}
}