Ausam/sys/dmr/dz.c

Find at most related files.
including files from this version of Unix.

/*
 *	     DZ-11 driver
 *	     ------------
 *
 *		Written to handle single dz - `carrier'|`ring' support non-existent
 *
 *					Piers Lauder
 *					SYDNEY UNIVERSITY
 *					July 1977
 *
 *		Re-written to handle multiple dz's and `carrier'|`ring'.
 *
 *					Ian Johnstone
 *					UNSW
 *					December 1977
 *					January  1978
 *
 *		General tidy up, new comments etc. Removal of ifdefs
 *		for CARRIER and RING. If you don't want them, tough.
 *
 *					Chris Maltby
 *					Basser October 1979
 */ 


/* ( no messages )
#define	MESSAGES
	/*
	 * Define this if you want parity and framing errors
	 * to be logged (via printf). It can be very wordy.
	 */

#define	INTR_ON_BREAK
	/*
	 * Define this to translate framing errors (breaks)
	 * to CINTR for terminals which lack a DEL key.
	 * Can be nasty if you get lots of line errors.
	 */

/* (not	DEBUG)
#define	DEBUG
	/*
	 * Define to debug info for dialup lines.
	 * costs approximately 128 bytes 
	 */

#include	"../defines.h"
#include	"../param.h"
#ifdef	DEBUG
#ifdef	AUSAML
#include	"../lnode.h"
#endif	AUSAML
#include	"../systm.h"
#endif	DEBUG
#include	"../conf.h"
#include	"../user.h"
#include	"../tty.h"
#include	"../proc.h"


#define	NDZ		2		/* number of DZ-11s */
#define NLINES		8*NDZ		/* total number of lines */
#define	TSCANRATE	2		/* dzscan called every 2 tics */
					/* Must be >= 2 always	      */

#define	RESPONDTIME	(25*HZ)		/* Carrier must be raised inside this */
#define	CARRIERTIME	(1*HZ)		/* Carrier must drop for this before hangup */

#define FLUSHTIME	5		/* time required to allow hardware buffered
					 * characters to flush before setting speed */

#define SSPEED		12		/* standard speed 4800 bd */

struct	dz	/* one for each dz-11 */ 
{
	int	*dzaddr;	/* dz device address */
	char	sopen;		/* bit set for single open lines */
	char	carrier;	/* bits set for carrier controlled lines */
	char	ring;		/* bits set for lines with dial in modems */ 
	char	active;		/* bits set for active dialup lines */ 
	char	openl;		/* bits set for open lines */ 
	unsigned pyerrors;	/* count of of parity errors on input */ 
	unsigned overrors;	/* count of of overrun errors on input */ 
}
dz[NDZ]
{
	/* dzaddr  sopen  carr  ring */ 
	{ 0160040,  0002, 0077, 0074 },
	{ 0160050,  0000, 0000, 0000 }
};
int	dzscanning;	/* set when scanning for input and modem change */

/*
 *	DZ11 register layout
 */ 

struct dzr_read
{
	int	dzcsr;	/* r/w */ 
	int	dzrbuf;	/* no bit, byte, or tst ops */ 
	char	dztcr;	/* r/w */ 
	char	dzdtr;	/* r/w */ 
	char	dzring;
	char	dzcarr;
};

struct dzr_write
{
	int	dzcsr;	/* r/w */
	int	dzlpr;	/* no bit or byte ops */ 
	char	dztcr;	/* r/w */
	char	dzdtr;	/* r/w */
	char	dztbuf;	/* no bit ops */ 
	char	dzbrk;	/* no bit ops */ 
};

/*
 *	register control bits
 */ 
#define TRDY		0100000 	/* dzcsr */
#define TIE		040000
#define SA		020000
#define SAE		010000
#define TLINE		03400
#define RDONE		0200
#define RIE		0100
#define MSE		040
#define CLR		020

#define RCVR_ON 	010000		/* dzlpr */
#define S9600		07000
#define S300		02400
#define S134_5		01400
#define S110		01000
#define ODD_PAR 	0300
#define EVN_PAR 	0100
#define TWOSBIT		040
#define C8BIT		030
#define C7BIT		020
#define	C6BIT		010
/*
#define IBM2741		RCVR_ON|S134_5|ODD_PAR|C6BIT	/* if you must */ 

#define	RERROR		070000		/* dzrbuf */
#define OVR_RUN 	040000	
#define FRAME		020000
#define PARITY		010000
#define LINE_NO 	03400

/*
 *	table to map UNIX standard speeds to DZ11 speeds
 *	illegal speeds are ignored.
 */ 
char	dzspeedmap[16]
{
	    0 /*  0 - zero */ 
	, 020 /*  1 -   50 */ 
	, 021 /*  2 -   75 */ 
	, 022 /*  3 -  110 */ 
	, 023 /*  4 -  134.5 */ 
	, 024 /*  5 -  150 */ 
	,0200 /*  6 -  200 -- ## ILLEGAL ## */ 
	, 025 /*  7 -  300 */ 
	, 026 /*  8 -  600 */ 
	, 027 /*  9 - 1200 */ 
	, 030 /* 10 - 1800 */ 
	, 032 /* 11 - 2400 */ 
	, 034 /* 12 - 4800 */ 
	, 036 /* 13 - 9600 */ 
	, 031 /* 14 - ext A - maps to 2000 */ 
	, 037 /* 15 - ext B - maps to 19200 */ 
};



struct tty	dz11[NLINES];

char		dzdelays[NLINES];	/* Count of clock ticks for per-line
					 * delays. Count of <= 0 means no delay.
					 * Reduces requirement of timeouts.
					 */

int		dzringt[NLINES];	/* Delay counts for modem control */

/*
 *	open a DZ11 line
 */ 
dzopen(dev, flag)
{
	register struct tty	*tp;
	register struct dz	*dzp;
	register int		t_bit;
	extern	dzstart(), dzscan();


	if(dev.d_minor >= NLINES)
	{
		u.u_error = ENXIO;
		return;
	}
	dzp = &dz[dev.d_minor>>3];
	t_bit = (1<<(dev.d_minor&07));
	if((dzp->sopen&t_bit) && (dzp->openl&t_bit))
	{
		u.u_error = EOPENFAIL;
		return;
	}
	tp = &dz11[dev.d_minor];
	if(u.u_procp->p_ttyp == 0)
		u.u_procp->p_ttyp = tp;
	if((tp->t_state&ISOPEN) == 0)
	{
		tp->t_dev = dev;
		tp->t_addr = &dzstart;
		tp->t_speeds = SSPEED|(SSPEED<<8);
		tp->t_flags = ODDP|EVENP|XTABS|RAW;
		tp->t_erase = CERASE;
		tp->t_kill = CKILL;
		if(dzp->openl == 0)
			dzp->dzaddr->dzcsr =| (TIE|RIE|SAE|MSE);	/* reciever interrupt every 16 chars */ 
		dzp->openl =| t_bit;
		spl5();
		if(dzscanning == 0)
			dzscan();	/* start scanning */ 
		if(!(dzp->ring&t_bit) && !(dzp->carrier&t_bit))
			dzp->dzaddr->dzdtr =| t_bit;	/* turn on DTR for non-dialup lines */ 
		else
		{
#			ifdef	DEBUG
				printf("%d wo%d\n", time.loint, dev.d_minor);
#			endif	DEBUG
			while(!(dzp->dzaddr->dzcarr&t_bit))
			{
				tp->t_state =| WOPEN;
				sleep(&tp->t_rawq, TTIPRI);
			}
#			ifdef	DEBUG
				printf("%d op%d\n", time.loint, dev.d_minor);
#			endif	DEBUG
		}
		spl0();
		tp->t_state = (ISOPEN|CARR_ON|SSTART);
		dzparam(tp, 1);
	}
}


/*
 *	scan open lines for:
 *			1.  modem status changes
 *			2.  process timeouts as dictated by dzdelays
 *			3.  input by calling dzrint
 */ 
dzscan()	/* at spl5 */ 
{
	register struct dz	*dzp;
	struct tty		*tp;
	int			*p;
	extern dzstart(), dzrint(), dzscan();
#	define	openring	(dzp->openl & dzp->ring)
#	define	opencarrier	(dzp->openl & dzp->carrier)

	/*
	 *	scan open dialup/carrier lines.
	 */ 
	tp = &dz11[0];
	p = &dzringt[0];
	for(dzp = dz; dzp < &dz[NDZ]; dzp++)
	{
	    register int	*dzaddr;
	    char	scanl, scanc;

	    dzaddr = dzp->dzaddr;
	    if((scanl = openring) | (scanc = opencarrier))
	    {
		register int	t_bit;

		for(t_bit = 1; t_bit&0377; t_bit =<< 1, tp++, p++)
		{
		    if(scanl&t_bit)
		    {
			/* this is an open `dialup' line */ 
			if(dzp->active&t_bit)
			{
			    if(!(dzaddr->dzcarr&t_bit))
			    {
				if(*p == 0)
				    *p = CARRIERTIME;
				else if((*p =- TSCANRATE) <= 0)
				{
				    *p = 0;	/* disable */ 
#				    ifdef	DEBUG
					printf("%d hu%d\n", time.loint, tp->t_dev.d_minor);
#				    endif	DEBUG
				    dzaddr->dzdtr =& ~t_bit;	/* hang up the phone */ 
				    signal(tp, SIGHUP);
				    flushtty(tp);
				    dzaddr->dztcr =& ~t_bit;	/* disable transmit */ 
				    dzp->active =& ~t_bit;
				}
			    }
			    else
			    {
				if(tp->t_state&WOPEN)
				    wakeup(&tp->t_rawq);
				*p = 0;
				if(!(tp->t_state&TIMEOUT) && (tp->t_outq.c_cc))
				    dzaddr->dztcr =| t_bit;
			    }
			}
			else
			{
			    if(!(dzaddr->dzdtr&t_bit) && (dzaddr->dzring&t_bit))
			    {
				dzaddr->dzdtr =| t_bit;	/* answer the phone */ 
				*p = RESPONDTIME;
				dzp->active =| t_bit;
#				ifdef	DEBUG
				    printf("%d ap%d\n", time.loint, tp->t_dev.d_minor);
#				endif	DEBUG
			    }
			}
		    }
		    else if((scanc&t_bit) && (dzaddr->dzcarr&t_bit))
		    {	/* carrier only line */
			if(tp->t_state&WOPEN)
			{
			    dzaddr->dzdtr =| t_bit;
			    wakeup(&tp->t_rawq);
			}
			else if((!(tp->t_state&TIMEOUT)) && (tp->t_outq.c_cc))
			    dzaddr->dztcr =| t_bit;
		    }
		}
	    }
	    else
	    {
		tp =+ 8; p =+ 8;	/* in the case where no dialup/carrier lines on current dz */ 
	    }
	}

	/*
	 *	process timeouts for each line
	 */ 

	{
		register i;

		for(i = 0; i < NLINES; i++)
			if((dzdelays[i] > 0) && (--dzdelays[i] <= 0))
			{
				dz11[i].t_state =& ~TIMEOUT;
				dzstart(&dz11[i]);
			}
	}

	/*
	 *	scan each dz for input
	 */ 

	dzrint(0);

	/*
	 *	restart scanning if necessary
	 */ 

	dzp = dz;
	do
	{
		if(dzp->openl)
		{
			dzscanning = timeout(&dzscan, 0, TSCANRATE);
			return;
		}
		dzp++;
	} while(dzp < &dz[NDZ]);
	dzscanning = 0;
}

/*
 *	close a DZ11 line
 */ 
dzclose(dev)
{
	register struct tty *tp;
	register t_bit;
	register struct dz *dzp;

	tp = &dz11[dev.d_minor];
	wflushtty(tp);
	tp->t_state = SSTART;
	dzp = &dz[dev.d_minor>>3];
	t_bit = 1<<(dev.d_minor&07);
	if(dzp->ring&t_bit)
	{
		if(tp->t_flags&HUPCL)
			dzp->dzaddr->dzdtr =& ~t_bit;	/* hang up the phone */ 
	}
	else
	{
		dzp->dzaddr->dzdtr =& ~t_bit;	/* turn off dtr for non-dialup lines */ 
	}
	if((dzp->openl =& ~t_bit) == 0)
		dzp->dzaddr->dzcsr = 0;	/* disable receive on final close */ 
}



/*
 *	read from a DZ11 line
 */ 
dzread(dev)
{
	ttread(&dz11[dev.d_minor]);
}



/*
 *	write on a DZ11 line
 */ 
dzwrite(dev)
{
	ttwrite(&dz11[dev.d_minor]);
}



/*
 *	stty/gtty for DZ11
 */ 
dzsgtty(dev, av)
int *av;
{
	register struct tty *tp;

	if((av == 0) && (dzspeedmap[u.u_arg[0]&017] < 0))
	{
		u.u_error = ENXIO;	/* illegal speed */ 
		return;
	}
	tp = &dz11[dev.d_minor];
	if(ttystty(tp, av))
		return;
	dzparam(tp, 1);
}



/*
 *	set parameters from open or stty into DZ hardware registers
 */ 
dzparam(tp, dflag)
register struct tty *tp;
{
	register lpr, x;
	extern wakeup();


	lpr = dzspeedmap[tp->t_speeds&017]<<8;

#ifdef	IBM2741
	if(lpr == (RCVR_ON|S134_5))
		lpr = IBM2741;
	else
	{
#endif	IBM2741
		if(lpr == (RCVR_ON|S110))
			lpr =| TWOSBIT;

		if((x = tp->t_flags)&EVENP)
			if((x&ODDP) == 0)
				lpr =| (EVN_PAR|C7BIT);
			else
				lpr =| C8BIT;
		else if(x&ODDP)
			lpr =| (ODD_PAR|C7BIT);
		else
			lpr =| C8BIT;
#ifdef	IBM2741
	}
#endif	IBM2741

	if(dflag)
	{
		/* delay only if it is permissible */ 
#ifndef	DELAY
		timeout(&wakeup, tp, FLUSHTIME);	/* wakeup in 5 tics */ 
		sleep(tp, TTOPRI);	/* delay while controller flushes */ 
#else
		delay(FLUSHTIME);	/* hang 5 */ 
#endif	DELAY
	}

	dz[tp->t_dev.d_minor>>3].dzaddr->dzlpr = lpr|(tp->t_dev.d_minor&07);
}



/*
 *	start (restart) transmission on a DZ11 line
 */ 
dzstart(tp)
register struct tty *tp;
{
	register t_bit;
	register struct dz *dzp;


	t_bit = 1<<(tp->t_dev.d_minor&07);
	dzp = &dz[tp->t_dev.d_minor>>3];
	if((!(dzp->carrier&t_bit)) || (dzp->dzaddr->dzcarr&t_bit))
		dzp->dzaddr->dztcr =| t_bit;
}


/*
 *	DZ11 transmitter interrupt.
 *
 *	Scan every line on each dz.
 *	Commencing with the device that caused
 *	dzxint to be called.
 */ 
dzxint(dev)
{
	register struct tty *tp;
	register c;
	register struct dzr_read *dzaddr;
	struct dz *dzp;
	struct tty *dzbase;
	int t_bit, lino, i, n;

	n = dev.d_minor;
	for(i = 0; i < NDZ; i++)
	{
		dzaddr = (dzp = &dz[n])->dzaddr;
		dzbase = &dz11[n*8];
		while((c = dzaddr->dzcsr) < 0)	/* xmit line ready */ 
		{
			t_bit = 1<<(lino = (c>>8)&07);

			tp = &dzbase[lino];

			if((!(dzp->carrier&t_bit) || (dzaddr->dzcarr&t_bit)) && (c = getc(&tp->t_outq)) >= 0)
				if(c <= 0177 || tp->t_flags == RAW)
					dzaddr->dztbuf = c;
				else
				{
					dzaddr->dztcr =& ~t_bit;
					tp->t_state =| TIMEOUT;
					dzdelays[tp-dz11] = ((c&0177)+(TSCANRATE-1))/TSCANRATE+1;	/* set up timeout */ 
					continue;
				}
			else
				dzaddr->dztcr =& ~t_bit;

#ifdef	TTY_HISPEED
			if(tp->t_outq.c_cc <= ((tp->t_speeds&017) > B1200?TTHSLOWAT:TTLOWAT) && (tp->t_state&ASLEEP))
#else
			if(tp->t_outq.c_cc <= TTLOWAT && (tp->t_state&ASLEEP))
#endif	TTY_HISPEED
			{
				tp->t_state =& ~ASLEEP;
				wakeup(&tp->t_outq);
			}
		}
		if(++n >= NDZ)
			n = 0;
	}
}



/*
 *	DZ11 receiver interrupt
 *
 *	Scan each dz commencing with the
 *	particular device that caused this call.
 *	Storing each charater as it comes.
 */ 
dzrint(dev)
{
	register struct tty *tp;
	register c;
	register struct dzr_read *dzaddr;
	struct dz *dzp;
	struct tty *dzbase;
	int i, n, lino, t_bit;

	n = dev.d_minor;
	for(i = 0; i < NDZ; i++)
	{
		dzp = &dz[n];
		if(dzp->openl)
		{
			dzbase = &dz11[n*8];
			while((c = dzp->dzaddr->dzrbuf) < 0)	/* char present in silo */ 
			{
				tp = &dzbase[lino = ((c>>8)&07)];
				t_bit = 1<<lino;
				if(c&RERROR)
				{
					if(c&OVR_RUN)
					{
						dzp->overrors++;
#						ifdef	MESSAGES
							printf("over run on dz %d/%d\n", n, lino);
#						endif	MESSAGES
					}
					if(c&FRAME)	/* break */ 
						if(tp->t_flags&RAW)
							c = 0;	/* null ( for getty ) */ 
						else
#						    ifdef	INTR_ON_BREAK
							c = CINTR;	/* del for NCRs. */ 
#						    else
							continue;	/* ignore framing errors if not raw */ 
#						    endif	INTR_ON_BREAK
					else if(c&PARITY)
					{
						dzp->pyerrors++;
#						ifdef	MESSAGES
							printf("parity on dz %d/%d\n", n, lino);
#						endif	MESSAGES
						continue;	/* throw away bad chars */ 
					}
				}
				if((!(dzp->carrier&t_bit)) || (dzp->dzaddr->dzcarr&t_bit))
					ttyinput(c, tp);
			}
		}
		if(++n >= NDZ)
			n = 0;
	}
}
#ifdef	POWER_FAIL

dzpowf()
{
	register line;
	register struct dz *dzp;
	register struct tty *tp;
	int dzn, t_bit;

	tp = &dz11[0];
	for(dzn = 0; dzn < NDZ; dzn++)
	{
		dzp = &dz[dzn];
		if(dzp->openl)
		{
			(dzp->dzaddr)->dzcsr =| (TIE|RIE|SAE|MSE);	/* reciever interrupt every 16 chars */ 
			for(line = 0; line < 8; line++, tp++)
				if(tp->t_state&ISOPEN)
				{
					t_bit = 1<<line;
					dzparam(tp, 0);	/* set speeds */ 
					(dzp->dzaddr)->dztcr =| t_bit;	/* enable transmit */ 
					if(!(dzp->ring&t_bit))
						dzp->dzaddr->dzdtr =| t_bit;	/* turn on DTR for non-dialup li	 n	 e	 s	 */ 
				}
		}
		else
			tp =+ 8;
	}
}
#endif	POWER_FAIL