/*
 *	DM-BB driver
 */
#include "param.h"
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/conf.h>

/*
 *	SCCS id	@(#)dhdm.c	2.1 (Berkeley)	8/5/83
 */

#define	DMADDR	((struct device *)0170500)

struct	tty dh11[];

int	dhlowdm;	/* minor device of first line with DM11-BB */
int	dhndm;		/* number of lines with DM11-BB (both set in dh.c) */

#define	DONE	0200
#define	SCENABL	040
#define	CLSCAN	01000
#define	TURNON	03	/* CD lead, line enable */
#define	SECX	010	/* secondary xmit */
#define	RQS	04	/* request to send */
#define	TURNOFF	1	/* line enable only */
#define	CARRIER	0100
#define	CLS	040	/* clear to send */
#define	SECR	020	/* secondary receive */

struct device
{
	int	dmcsr;
	int	dmlstat;
	int	junk[2];
};

#define	B1200	9
#define	B300	7

/*
 * Turn on the line associated with the (DH) device dev.
 */
dmopen(dev)
{
	register struct tty *tp;
	register struct device *addr;
	register d;

	d = minor(dev);
	tp = &dh11[d];
	if(d < dhlowdm || d >= dhlowdm+dhndm) {
		tp->t_state |= CARR_ON;
		return;
	}
	addr = DMADDR;
	addr += (d - dhlowdm) >> 4;
	(void) _spl5();
	addr->dmcsr = d&017;
	addr->dmlstat = TURNON;
	if (addr->dmlstat&CARRIER) {
		tp->t_state |= CARR_ON;
	}
	addr->dmcsr = IENABLE|SCENABL;
	while ((tp->t_state&CARR_ON)==0)
		sleep((caddr_t)&tp->t_rawq, TTIPRI);
	addr->dmcsr = d&017;
	if (addr->dmlstat&SECR) {
		tp->t_ispeed = B1200;
		tp->t_ospeed = B1200;
		dhparam(dev);
	}
	addr->dmcsr = IENABLE|SCENABL;
	(void) _spl0();
}

/*
 * Dump control bits into the DM registers.
 */
dmctl(dev, bits)
{
	register struct device *addr;
	register d, s;

	d = minor(dev);
	if(d < dhlowdm || d >= dhlowdm+dhndm)
		return;
	addr = DMADDR;
	addr += (d - dhlowdm) >> 4;
	s = spl5();
	addr->dmcsr = d&017;
	addr->dmlstat = bits;
	addr->dmcsr = IENABLE|SCENABL;
	splx(s);
}

/*
 * DM11 interrupt.
 * Mainly, deal with carrier transitions.
 */
dmint(dev)
{
	register struct tty *tp;
	register struct device *addr;
	register d;

	d = minor(dev);
	addr = DMADDR;
	addr += d;
	if (addr->dmcsr&DONE) {
		tp = &dh11[(d<<4)+(addr->dmcsr&017)];
		tp += dhlowdm;
		if (tp < &dh11[dhlowdm+dhndm]) {
			wakeup((caddr_t)&tp->t_rawq);
			if ((addr->dmlstat&CARRIER)==0) {
				if ((tp->t_state&WOPEN)==0 &&
				     (tp->t_local&LNOHANG)==0) {
					gsignal(tp->t_pgrp, SIGHUP);
					addr->dmlstat = 0;
					flushtty(tp, FREAD|FWRITE);
				}
				tp->t_state &= ~CARR_ON;
			} else {
				tp->t_state |= CARR_ON;
			}
		}
		addr->dmcsr = IENABLE|SCENABL;
	}
}
