V9/sys/dev.old/dz.c

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

/*
 *  DZ-11 Driver
 */

/* Modified 4/84 by J. Wolitzky to allow dialout operation with smart modems */

#include "dz.h"
#define	TRC(c)

#include "../h/param.h"
#include "../h/stream.h"
#include "../h/ttyio.h"
#include "../h/ttyld.h"
#include "../h/pte.h"
#include "../h/map.h"
#include "../h/buf.h"
#include "../h/systm.h"
#include "../h/ubavar.h"
#include "../h/conf.h"
#define	NDZLINE	(8*NDZ)
 
#define BITS7	020
#define BITS8	030
#define TWOSB	040
#define PENABLE	0100
#define OPAR	0200
#define	CLR	020		/* Clear */
#define MSE	040		/* Master Scan Enable */
#define RIE	0100		/* Receiver Interrupt Enable */
#define	SAE	010000		/* Silo Alarm Enable */
#define TIE	040000		/* Transmit Interrupt Enable */
#define	TRDY	0100000		/* Transmitter ready */
#define DZ_IEN	(MSE+RIE+TIE)
#define PERROR	010000
#define FRERROR	020000
#define	OVERRUN	040000
#define SSPEED	9		/* std speed = 1200 baud */

#define	EXISTS	01
#define	ISOPEN	02
#define	WOPEN	04
#define	TIMEOUT	010
#define	CARR_ON	020
#define	DZSTOP	040
#define	HPCL	0100
#define	BRKING	0200
#define	DIALOUT	0400	/* set when used as dialout with smart modems */

#define	DZPRI	30

struct device {
	short	dzcsr;
	short	dzrbuf;
#define	dzlpr	dzrbuf
	char	dztcr;
	char	dzdtr;
	char	dztbuf;
#define	dzrind	dztbuf
	char	dzbrk;
#define	dzmsr	dzbrk
};

int	dzprobe(), dzattach(), dzrint();
struct	uba_device *dzboard[NDZ];
u_short dzstd[] = { 0 };
struct uba_driver dzdriver = { dzprobe, 0, dzattach, 0, dzstd, "dz", dzboard };

/*
 * One structure per line
 */
struct	dz {
	short	state;
	short	flags;
	struct	block	*oblock;
	struct	queue	*rdq;
	char	board;
	char	line;
	char	speed;
	char	brking;
} dz[NDZLINE];
int	dzoverrun;

char	dz_speeds[] = {
	0, 020 , 021 , 022 , 023 , 024 , 0, 025,
	026 , 027 , 030 , 032 , 034 , 036 , 037 , 0
};

int	dzopen(), dzclose(), dzoput(), nodev();

static	struct qinit dzrinit = { nodev, NULL, dzopen, dzclose, 0, 0 };
	struct qinit dzwinit = { dzoput, NULL, dzopen, dzclose, 200, 100 };
struct	streamtab dzinfo = { &dzrinit, &dzwinit };

int	dzmiss;

dzprobe(reg)
caddr_t reg;
{
	register int br, cvec;
	register struct device *dzaddr = (struct device *)reg;

	dzaddr->dzcsr = TIE|MSE;
	dzaddr->dztcr = 1;		/* enable any line */
	DELAY(100000);
	dzaddr->dzcsr = CLR;		/* reset everything */
	if (cvec && cvec != 0x200)
		cvec -= 4;
	return (1);
}

dzattach(ui)
register struct uba_device *ui;
{
	extern dzscan();
	static dz_timer;
	register i;

	for (i=0; i<8; i++) {
		dz[ui->ui_unit*8+i].state = EXISTS;
		dz[ui->ui_unit*8+i].board = ui->ui_unit;
		dz[ui->ui_unit*8+i].line = i;
	}
	if (dz_timer == 0) {
		dz_timer++;
		timeout(dzscan, (caddr_t)0, hz);
	}
	return (1);
}
 
/*ARGSUSED*/
dzopen(q, d, flag)
register struct queue *q;
{
	register dev;
	register struct dz *dzp;
	int dzflag;
 
	dev = minor(d);
	dzp = &dz[dev];
	if (dev >= NDZLINE || (dzp->state&EXISTS)==0)
		return(0);
	q->ptr = (caddr_t)dzp;
	WR(q)->ptr = (caddr_t)dzp;
	dzscan((caddr_t)1);			/* update CARR_ON */
	if ((dzp->state&ISOPEN)==0 || (dzp->state&CARR_ON)==0) {
		register s = spl5();
		for (;;) {
			dzp->flags = F8BIT|ODDP|EVENP;
			dzp->speed = SSPEED;
			dzparam(dzp);
			if (dzp->state & CARR_ON)
				break;
			dzflag = dzboard[dev / 8]->ui_flags;
			/* ignore carrier? */
			if (dzflag & (1 << (dev % 8))) {
				dzp->state |= (DIALOUT | CARR_ON);
				break;
			}
			if (tsleep((caddr_t)dzp, DZPRI, 0) != TS_OK) {
				wakeup((caddr_t)dzp);
				dzp->speed = 0;
				dzparam(dzp);
				splx(s);
				return(0);
			}
		}
		dzp->rdq = q;
		dzp->state |= ISOPEN;
		splx(s);
	}
	TRC('o');
	return(1);
}

dzclose(q, d)
register struct queue *q;
{
	register struct dz *dzp;
	register s;

	dzp = (struct dz *)q->ptr;
	s = spl5();
	if (dzp->oblock) {
		register struct block *bp = dzp->oblock;
		dzp->oblock = NULL;
		freeb(bp);
	}
	flushq(WR(q), 1);
	dzp->rdq = NULL;
	if (dzp->state&HPCL || (dzp->state&CARR_ON)==0) {
		dzp->speed = 0;
		dzparam(dzp);
	}
	dzp->state &= EXISTS;
	splx(s);
	TRC('c');
}

/*
 * DZ write put routine
 */
dzoput(q, bp)
register struct queue *q;
register struct block *bp;
{
	register struct dz *dzp = (struct dz *)q->ptr;
	register union stmsg *sp;
	register s;
	int delaytime;

	TRC('p');
	switch(bp->type) {

	case M_IOCTL:
		TRC('i');
		sp = (union stmsg *)bp->rptr;
		switch (sp->ioc0.com) {

		case TIOCSDEV:
			delaytime = 0;
			if (dzp->speed != sp->ioc3.sb.ispeed)
				delaytime = 20;
			dzp->speed = sp->ioc3.sb.ispeed;
			dzp->flags = sp->ioc3.sb.flags;
			bp->type = M_IOCACK;
			bp->wptr = bp->rptr;
			qreply(q, bp);
			qpctl1(q, M_DELAY, delaytime);	/* wait a bit */
			qpctl(q, M_CTL);		/* means do dzparam */
			dzstart(dzp);
			return;

		case TIOCGDEV:
			sp->ioc3.sb.ispeed =
			  sp->ioc3.sb.ospeed = dzp->speed;
			sp->ioc3.sb.flags = dzp->flags;
			bp->type = M_IOCACK;
			qreply(q, bp);
			return;

		case TIOCHPCL:
			dzp->state |= HPCL;
			bp->type = M_IOCACK;
			bp->wptr = bp->rptr;
			qreply(q, bp);
			return;

		default:
			bp->wptr = bp->rptr;
			bp->type = M_IOCNAK;
			qreply(q, bp);
			return;
		}

	case M_STOP:
		s = spl5();
		dzp->state |= DZSTOP;
		freeb(bp);
		if (bp = dzp->oblock) {
			dzp->oblock = NULL;
			putbq(q, bp);
		}
		splx(s);
		return;

	case M_START:
		dzp->state &= ~DZSTOP;
		dzstart(dzp);
		break;

	case M_FLUSH:
		flushq(q, 1);
		freeb(bp);
		s = spl5();
		if (bp = dzp->oblock) {
			dzp->oblock = NULL;
			freeb(bp);
		}
		splx(s);
		return;

	case M_BREAK:
		qpctl1(q, M_DELAY, 10);
		putq(q, bp);
		qpctl1(q, M_DELAY, 10);
		dzstart(dzp);
		return;

	case M_HANGUP:
		dzp->state &= ~DZSTOP;
	case M_DELAY:
	case M_DATA:
		putq(q, bp);
		TRC('d');
		dzstart(dzp);
		return;

	default:		/* not handled; just toss */
		break;
	}
	freeb(bp);
}
 
/*
 * Receive interrupt.  Argument is DZ board number
 */
dzrint(dev)
{
	register struct dz *dzp;
	register struct block *bp;
	register struct device *dzaddr;
	register int c;
 
	if (dev >= NDZ) {
		printf("bad dz rd intr\n");
		return;
	}
	dzaddr = (struct device *)dzboard[dev]->ui_addr;
	while ((c = dzaddr->dzrbuf) < 0) {	/* char present */
		dzp = &dz[dev*8 + ((c>>8)&07)];
		if (c&(OVERRUN/*|PERROR*/)) {
			if (c&OVERRUN)
				dzoverrun++;
			continue;
		}
		if (dzp->rdq == NULL)
			continue;
		if (dzp->rdq->next->flag&QFULL) {
			dzmiss++;
			continue;
		}
		if ((bp = allocb(16)) == NULL)
			continue;			/* no space */
		if (c&FRERROR)			/* frame err (break) */
			bp->type = M_BREAK;
		else
			*bp->wptr++ = c;
		(*dzp->rdq->next->qinfo->putp)(dzp->rdq->next, bp);
	}
}
 
/*
 * set device parameters
 */
dzparam(dzp)
register struct dz *dzp;
{
	register short lpr;
	struct device *dzaddr = (struct device *)dzboard[dzp->board]->ui_addr; 

	dzaddr->dzcsr = DZ_IEN;
	if (dzp->speed == 0) {
		dzaddr->dzdtr &= ~(1 << dzp->line);	/* hang up */
		return;
	}
	dzaddr->dzdtr |= 1 << dzp->line;
	lpr = (dz_speeds[dzp->speed]<<8) | dzp->line;
	if (dzp->flags & F8BIT)
		lpr |= BITS8;
	else
		lpr |= (BITS7|PENABLE);
	if ((dzp->flags & EVENP) == 0)
		lpr |= OPAR;
	if (dzp->speed == 3)
		lpr |= TWOSB; 			/* 110 baud: 2 stop bits */
	dzaddr->dzlpr = lpr;
}
 
/*
 * Transmitter interrupt. dev is board number.
 */
dztint(dev)
{
	register struct device *dzaddr = (struct device *)dzboard[dev]->ui_addr;
	register struct dz *dzp;
	register struct block *bp;
	register sts;
 
	while ((sts = dzaddr->dzcsr) & TRDY) {
		dzp = &dz[dev*8 + ((sts>>8)&07)];
		if (bp = dzp->oblock) {
			if (bp->rptr < bp->wptr) {
				dzaddr->dztbuf = *bp->rptr++;
				continue;
			}
			freeb(bp);
			dzp->oblock = NULL;
		}
		dzaddr->dztcr &= ~(1 << (dzp->line));
		dzstart(dzp);
	}
}

dztimo(dzp)
register struct dz *dzp;
{
	if (dzp->state&BRKING) {
		dzp->brking &= ~(1 << dzp->line);
		((struct device *)dzboard[dzp->board]->ui_addr)->dzbrk =
		    dzp->brking;
	}
	dzp->state &= ~(TIMEOUT|BRKING);
	dzstart(dzp);
}

dzstart(dzp)
register struct dz *dzp;
{
	register s = spl5();
	register struct block *bp;
	register struct device *dzaddr;
 
	TRC('s');
again:
	if (dzp->state & (TIMEOUT|DZSTOP|BRKING) || dzp->oblock) {
		TRC('t');
		goto out;
	}
	if (dzp->rdq == NULL)
		goto out;
	if ((bp = getq(WR(dzp->rdq))) == NULL) {
		TRC('n');
		goto out;
	}
	switch (bp->type) {

	case M_DATA:
		dzp->oblock = bp;
		dzaddr = (struct device *)dzboard[dzp->board]->ui_addr;
		dzaddr->dztcr |= 1 << (dzp->line);
		break;

	case M_BREAK:
		dzaddr = (struct device *)dzboard[dzp->board]->ui_addr;
		dzp->brking |= 1 << dzp->line;
		dzaddr->dzbrk = dzp->brking;
		dzp->state |= BRKING|TIMEOUT;
		timeout(dztimo, (caddr_t)dzp, 15);	/* about 250 ms */
		freeb(bp);
		break;

	case M_DELAY:
		dzp->state |= TIMEOUT;
		timeout(dztimo, (caddr_t)dzp, (int)*bp->rptr + 6);
		freeb(bp);
		break;

	case M_HANGUP:
		dzp->speed = 0;
	case M_CTL:
		freeb(bp);
		dzparam(dzp);
		goto again;

	}
out:
	splx(s);
}
 
dzscan(timo)
caddr_t timo;
{
	register struct device *dzaddr;
	register struct dz *dzp;
	register i, j;
 
	for (i=0; i<NDZ; i++) {
		if (dzboard[i] == NULL)
			continue;
		dzaddr = (struct device *)dzboard[i]->ui_addr;
		for (j=0,dzp = &dz[i*8]; j<8; j++, dzp++) {
			if (dzaddr->dzmsr & (1<<j)) {
				/* carrier present */
				if ((dzp->state & CARR_ON)==0)
					wakeup((caddr_t)dzp);
				dzp->state |= CARR_ON;
			} else if ((dzp->state & CARR_ON)
			  && !(dzp->state & DIALOUT)) {
				/* carrier lost */
				if (dzp->state&ISOPEN) {
					dzaddr->dzdtr &= ~(1<<j);
					if (dzp->rdq)
						putctl(dzp->rdq->next,M_HANGUP);
				}
				dzp->state &= ~CARR_ON;
			}
		}
	}
	if (timo == 0)
		timeout(dzscan, (caddr_t)0, 2*hz);
}