V9/sys/dev.old/dk.c

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

/*
 *  Datakit driver
 */
#include "dk.h"
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/stream.h"
#include "../h/dkio.h"
#include "../h/pte.h"
#include "../h/map.h"
#include "../h/buf.h"
#include "../h/ubavar.h"
#include "../h/conf.h"
#include "../h/dkstat.h"
#include "../h/dkmod.h"
#include "sparam.h"

struct device {
	unsigned short csr;
	unsigned short dko;
	unsigned short dki;
};

struct	device	*DKADDR;
#ifndef	NDKLINE
#define	NDKLINE	64
#endif	NDKLINE

struct	dk {
	struct	queue *dkrq;
	char	flag;
	u_char	chan;
} dk[NDKLINE];

#define	DKXCL	01

int	dkalive;
struct	dkstat	dkstat;
extern	struct	dkmodule dkmod[];
struct	dkmodule *dkmodp;
char	dkstate[NDKLINE];

/*
 * channel states
 */
#define	CLOSED	0
#define	RCLOSE	1		/* remote hung up, local still around */
#define	LCLOSE	2		/* closed locally, CMC hasn't acked yet */
#define	OPEN	3		/* in use */

/*
 * Hardware control bits
 */
#define	DKTENAB	0100
#define	DKRENAB	040
#define	ENABS	(DKRENAB)
#define	DKTDONE	0200
#define	DKRDONE	0100000
#define	D_OSEQ	0
#define	D_READ	01
#define	D_WRITE	02
#define	D_XPACK	03
#define	DKMARK	01000
#define	DKDATA	0400
#define	DKPARITY 0100000

#define	DKISIZ	16

int	nodev(), dkopen(), dkclose(), dkput();

static	struct qinit dkrinit = { nodev, NULL, dkopen, dkclose, 0, 0 };
	struct qinit dkwinit = { dkput, NULL, dkopen, dkclose, 0, 0 };
struct	streamtab dkinfo = { &dkrinit, &dkwinit };

int	dkattach(), dkprobe();
struct	uba_device *dkstuff[NDK];
u_short	dkstd[] = { 0 };
struct	uba_driver dkdriver =
	{ dkprobe, 0, dkattach, 0, dkstd, "dk", dkstuff };

dkprobe(reg)
caddr_t reg;
{
	register int br, cvec;
	register struct device *dkaddr = (struct device *)reg;

	dkaddr->csr = D_OSEQ;
	dkaddr->dko = 0;	/* this clears fifos */
	DELAY(1000);		/* wait for board to reset */
	dkaddr->csr = D_WRITE;
	dkaddr->dko = DKMARK + 511;	/* pack on 511 */
	dkaddr->csr = D_XPACK+DKTENAB;
	dkaddr->dko = 0;
	DELAY(10000);
	dkaddr->csr = 0;
	DKADDR = dkaddr;
	return(1);
}

dkattach()
{
}

/*
 * open DK channel
 */
long
dkopen(q, dev)
register struct queue *q;
register dev_t dev;
{
	register struct dk *dkp;
	static opened, badtime;
	register maj = major(dev);

	dev = minor(dev);
	if (dev<=0 || dev>=NDKLINE)
		return(0);
	if (!opened) {
		register sane;

		if (DKADDR == NULL)
			return(0);
		DKADDR->csr = D_OSEQ;
		DKADDR->dko = 0;	/* Clear fifo's */
		sane = 256;
		DELAY(1000);		/* wait for board to reset */
		do {
			if (DKADDR->csr & DKTDONE) {
				dkalive = 0;
				if (time > badtime + 300) {
					badtime = time;
					printf("DK interface bad\n");
				}
				return(0);
			}
		} while (--sane);
		for (dkmodp=dkmod; ; dkmodp++) {
			if (dkmodp->dev==0 || dkmodp->dev==maj) {
				dkmodp->dev = maj;
				dkmodp->dkstate = dkstate;
				dkmodp->nchan = NDKLINE;
				break;
			}
		}
		dkalive = 1;
		for (dkp = &dk[0]; dkp < &dk[NDKLINE]; dkp++)
			dkp->chan = dkp - &dk[0];
		DKADDR->csr = ENABS;
		opened++;
		dkrecover(dev);
	}
	dkp = &dk[dev];
	if (dkmodp->dkstate[dev] != CLOSED) {	/* already open */
		if (dkp->flag & DKXCL)
			return(0);
		if (dkmodp->dkstate[dev] != OPEN)
			return(0);	/* closing channels can't reopen */
		return(1);
	}
	dkp->dkrq = q;
	q->ptr = (caddr_t)dkp;
	WR(q)->ptr = (caddr_t)dkp;
	dkp->flag = DKXCL;
	dkmodp->dkstate[dev] = OPEN;
	return(1);
}

/*
 * Timer to recover from lost interrupt condition.
 */
dkrecover(dev)
dev_t	dev;
{
	register int	ps = spl5();

	if (DKADDR->csr & DKRDONE)
		dkrint(dev);
	splx(ps);

	timeout(dkrecover, dev, hz/2);
}

/*
 * close DK channel
 */
dkclose(q)
register struct queue *q;
{
	register struct dk *dkp;

	dkp = (struct dk *)q->ptr;
	dkp->dkrq = NULL;
	dkp->flag = 0;
	if (dkmodp->dkstate[dkp->chan] == RCLOSE || dkmodp->listnrq==NULL)
		dkmodp->dkstate[dkp->chan] = CLOSED;
	else if (dkmodp->dkstate[dkp->chan] == OPEN)
		dkmodp->dkstate[dkp->chan] = LCLOSE;
	if (dkmodp->listnrq)
		putctl1(RD(dkmodp->listnrq), M_CLOSE, dkp->chan);
}

/*
 * DK receiver interrupt.
 */
dkrint(dev)
{
	register struct queue *q;
	register struct block *bp, **bpp;
	register c, nbytes, sts, sane, chan;
	struct block *blist[DKISIZ+1];

	sts = DKADDR->csr;
	c = 0;
	while (DKADDR->csr & DKRDONE) {
		DKADDR->csr = D_READ|ENABS;
		if ((c & DKMARK) == 0) {
			/* Search for channel number */
			sane = 256;
			do {
				c = DKADDR->dki;
				if (c & DKMARK || --sane==0)
					break;
			} while (DKADDR->csr & DKRDONE);
		}
		if ((c & DKMARK) == 0) {
			dkstat.markflt++;
			continue;
		}
		if ((c & DKPARITY) == 0) {
			dkstat.markparity++;
			c = 0;
			continue;
		}
		/* check channel */
		chan = c & 0777;
		if (chan == 0 || chan >= NDKLINE || (q = dk[chan].dkrq)==NULL) {
			if (chan>0 && chan<NDKLINE) {
				if (dkmodp->listnrq)
					putctl1(RD(dkmodp->listnrq),
						M_CLOSE, chan);
				dkstat.closepack++;
			} else if (chan == 0)
				dkstat.pack0++;
			else
				dkstat.packstrange++;
			for (nbytes=0; nbytes<DKISIZ; nbytes++) {
				c = DKADDR->dki;
				if (c & DKMARK)
					break;
			}
			continue;
		}
		bp = allocb(DKISIZ);
		if (bp == NULL)
			return;
		bpp = blist;
		for (nbytes=0; nbytes<DKISIZ; nbytes++) {
			if ((DKADDR->csr&DKRDONE) == 0)
				break;
			c = DKADDR->dki;
			if ((c & (DKPARITY|DKDATA|DKMARK))!=(DKPARITY|DKDATA)) {
				if (c & DKMARK) {
					dkstat.shortpack++;
					break;
				}
				if ((c & DKPARITY) == 0) {
					dkstat.parity++;
					break;
				} else { /* it's control */
					if ((c & 0377) == 0)
						continue;
					if (bp->wptr > bp->rptr) {
						*bpp++ = bp;
						bp = allocb(DKISIZ);
						if (bp == NULL)
							break;
					}
				}
				bp->type = M_CTL;
			}
			*bp->wptr++ = c;
		}
		*bpp++ = bp;
		*bpp++ = NULL;
		bpp = blist;
		if (nbytes!=DKISIZ) {
			while (*bpp)
				freeb(*bpp++);
			continue;
		}
		while (*bpp) {
			dkstat.input += bp->wptr - bp->rptr;
			if ((q->next->flag & QFULL) == 0)
				(*q->next->qinfo->putp)(q->next, *bpp++);
			else
				freeb(*bpp++);
		}
	}
	DKADDR->csr = sts;
}

/*
 * DK put procedure
 */
dkput(q, bp)
register struct queue *q;
register struct block *bp;
{
	register n, isdata = DKDATA;
	struct dk *dkp;
	int chan, s;
	struct ioctl1 {
		int	com;
	} *iop;

	dkp = (struct dk *)q->ptr;
	chan = dkp->chan;
	switch (bp->type) {

	case M_IOCTL:
		bp->type = M_IOCACK;
		iop = (struct ioctl1 *)bp->rptr;
		switch (iop->com) {
		case DIOCNXCL:
			dkp->flag &=~ DKXCL;
			bp->wptr = bp->rptr;
			bp->type = M_IOCACK;
			break;

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

	case M_CTL:
		isdata = 0;
	case M_DATA:
		break;

	case M_CLOSE:
		n = *bp->rptr;
		if (n < NDKLINE) {
			if (dkmodp->dkstate[n] == OPEN) {
				dkmodp->dkstate[n] = RCLOSE;
				putctl(dk[n].dkrq->next, M_HANGUP);
			} else if (dkmodp->dkstate[n] == LCLOSE)
				dkmodp->dkstate[n] = CLOSED;
		}
		freeb(bp);
		return;

	default:
		freeb(bp);
		return;
	}
	dkstat.output += bp->wptr - bp->rptr;
	s = spl6();
	if (dkalive) {
		register struct device *dkaddr = DKADDR;
		int r = dkaddr->csr;
		while ((n = bp->wptr - bp->rptr) > 0) {
			if (n > DKISIZ)
				n = DKISIZ;
			dkaddr->csr = D_WRITE + ENABS;
			dkaddr->dko = DKMARK + chan;
			dkaddr->dko = *bp->rptr++ | isdata;
			while (--n)
				dkaddr->dko = *bp->rptr++ | DKDATA;
			dkaddr->csr = D_XPACK + ENABS;
			dkaddr->dko = 0;
		}
		dkaddr->csr = r;
	}
	splx(s);
	freeb(bp);
}

/*
 * unibus reset
 */
dkreset()
{
	if (DKADDR)
		DKADDR->csr = ENABS;
}