#
/*
 */

/*
 *   DC-11 driver
 */
#include "../head/param.h"
#include "../head/conf.h"
#include "../head/user.h"
#include "../head/userx.h"
#include "../head/tty.h"

/*
 * Base address of DC-11's. Minor device  i  is at
 * DCADDR + 10*i.
 */
#define	DCADDR	0174000	/* Std is 174000 */
#define	DCTYPE	02

/*
 * Number of DC's for which table space is allocated.
 */
#define	NDC11	1

/*
 * Control bits in device registers
 */
#define	IENABLE	0100	/* interrupt enable */
#define	DTR	01	/* data terminal ready */
#define	DCRQS	01	/* request to send */
#define	DCST	0400	/* secondary transmit */
#define	PARITY	040
#define	DCOVRN	010000	/* data overrun */
#define	MTRANS	040000	/* modem transition */


int	ndc11	NDC11;
struct	tty dc11[NDC11];

struct dcregs {
	int dcrcsr;
	int dcrbuf;
	int dctcsr;
	int dctbuf;
};

/*
 * Input-side speed and control bit table.
 * Each DC11 has 4 speeds which correspond to the 4 non-zero entries.
 * The table index is the same as the speed-selector
 * number for the DH11.
 * Attempts to set the speed to a zero entry are ignored.
 */
int dcrstab[] {
	0,		/* 0 baud */
	0,		/* 50 baud */
	0,		/* 75 baud */
	0,		/* 110 baud */
	01101,		/* 134.5 baud: 7b/ch, speed 0 */
	0111,		/* 150 baud: 8b/ch, speed 1 */
	0,		/* 200 baud */
	0121,		/* 300 baud: 8b/ch, speed 2 */
	0,		/* 600 baud */
	0131,		/* 1200 baud */
	0,		/* 1800 baud */
	0,		/* 2400 baud */
	0,		/* 4800 baud */
	0,		/* 9600 baud */
	0,		/* X0 */
	0,		/* X1 */
};

/*
 * Transmitter speed table
 */
int dctstab[] {
	0,		/* 0 baud */
	0,		/* 50 baud */
	0,		/* 75 baud */
	0,		/* 110 baud */
	0501,		/* 134.5 baud: stop 1 */
	0511,		/* 150 baud */
	0,		/* 200 baud */
	0521,		/* 300 baud */
	0,		/* 600 baud */
	0531,		/* 1200 baud */
	0,		/* 1800 baud */
	0,		/* 2400 baud */
	0,		/* 4800 baud */
	0,		/* 9600 baud */
	0,		/* X0 */
	0,		/* X1 */
};

/*
 * Open a DC11.
 */
dcopen(dev, flag)
{
	register struct tty *tp;
	register *addr;

	if (dev.d_minor >= NDC11) {
		u.u_error = ENXIO;
		return;
	}
	tp = &dc11[dev.d_minor];
	tp->t_addr = addr = DCADDR + dev.d_minor*8;
	tp->t_dev = dev;
	tp->t_dtype = DCTYPE;
	if (flag) {
		addr->dcrcsr =| IENABLE;
		(*linesw[tp->t_discp].l_open)(dev, tp);
	}
}

/*
 * Close a dc11
 */
dcclose(dev, flag)
{
	register struct tty *tp;

	tp = &dc11[dev.d_minor];
	(*linesw[tp->t_discp].l_close)(dev, tp);
}

dcparam(dev, atp)
struct tty *atp;
{
	register struct tty *tp;
	register r;

	tp = atp;
	if (r = dcrstab[tp->t_speeds.lobyte&017])
		tp->t_addr->dcrcsr = r;
	if (r = dctstab[tp->t_speeds.hibyte&017])
		tp->t_addr->dctcsr = r;
}

/*
 * Modem control for DC 11.
 */
dcmctl(dev, action)
{
	register struct tty *tp;
	register int sps, *addr;
	int tcsr, status;

	tp = &dc11[dev.d_minor];
	addr = tp->t_addr;
	status = 0;
	sps = PS->integ;
	spl5();
	switch(action&03) {

	case FSTATUS:
		tcsr = addr->dctcsr;
		status = (addr->dcrcsr&CARRIER)|(tcsr&CTS)|((tcsr>>15)&SR);
		break;

	case DISABLE:

	case HUP:
		addr->dcrcsr =& ~DTR;
		break;

	case TURNON:
	/*
	 * Set data terminal ready. Also set primary and secondary
	 * carrier status according to bits 2 and 3 of "action"
	 */
		addr->dcrcsr =| DTR;

		if(action&ST)
			addr->dcrcsr =| DCST;
		else
			addr->dcrcsr =& ~DCST;
		if(action&RQS)
			addr->dctcsr =| DCRQS;
		else
			addr->dctcsr =& ~DCRQS;
	}

	PS->integ = sps;
	return(status);
}

/*
 * Read a DC11
 */
dcread(dev)
{
	register struct tty *tp;

	tp = &dc11[dev.d_minor];
	(*linesw[tp->t_discp].l_read)(tp);
}

/*
 * Write a DC11
 */
dcwrite(dev)
{
	register struct tty *tp;

	tp = &dc11[dev.d_minor];
	(*linesw[tp->t_discp].l_write)(tp);
}

/*
 * DC11 transmitter interrupt.
 */
dcxint(dev)
{
	register struct tty *tp;

	ttstart(tp = &dc11[dev.d_minor]);
}


/*
 * DC11 receiver interrupt.
 */
dcrint(dev)
{
	register struct tty *tp;
	register int c, rcsr;
	int tcsr;
	int status, action;

	tp = &dc11[dev.d_minor];
	rcsr = tp->t_addr->dcrcsr;
	if(rcsr&MTRANS) {
		/*
		 * Only primary carrier transitions cause interrupts
		 */
		tcsr = tp->t_addr->dctcsr;
		status = (rcsr&CARRIER)|(tcsr&CTS)|((tcsr>>15)&SR);
		action = (*linesw[tp->t_discp].l_mt)(tp, status);
		if (action > 0)
			dcmctl(dev, action);
		if ((rcsr = tp->t_addr->dcrcsr)&DONE == 0)
			return;
	}
	c = tp->t_addr->dcrbuf;
	if(rcsr&DCOVRN)
		c =| OVERRUN;
	else {
		rcsr =& PARITY;
		if (tp->t_flags&RAW == 0)
			if(rcsr && (tp->t_flags&ODDP)==0 || 
			    !rcsr && (tp->t_flags&EVENP)==0)
				c =| PERROR;
	}
	(*linesw[tp->t_discp].l_rcvd)(c, tp);
}

/*
 * DC11 stty/gtty.
 * Perform general functions and set speeds.
 */
dcsgtty(dev, flag)
{
	register struct tty *tp;

	tp = &dc11[dev.d_minor];
	ttioctl(dev, tp, flag);
}
