V9/sys/dev.old/scn.c

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

/*	scn.c		84/09/05	*/

#include "scn.h"
#if NSCN > 0
/*
 * UNIBUS DR11-B driver for teletype scanner
 *
 */

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/cpu.h"
#include "../h/nexus.h"
#include "../h/dk.h"
#include "../h/buf.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/map.h"
#include "../h/pte.h"
#include "../h/mtpr.h"
#include "../h/vm.h"
#include "../h/ubavar.h"
#include "../h/ubareg.h"
#include "../h/cmap.h"

#include "../h/scncmd.h"

struct scndevice{
	u_short scn_recvst;	/* receive status register */
	u_short scn_recv;	/* receive data register */
	u_short scn_sendst;	/* send status register */
	u_short scn_send;	/* send data register */
	short scnwc;		/* word count reg - unused but load -1 */
	u_short scnba;		/* base address reg - must be 16k bdry */
	u_short scncs;		/* command/status reg */
	u_short scndata;	/* data reg */
};
struct scnsoftc {
	u_short sbmode;		/*select bit mode*/
	u_short bpmode;		/* bit pack mode*/
	u_short sc_intno;	/* dr11b interrupt number */
	int scnreg;		/* index into uba_map */
	u_short scn_offset;	/* offset from 16k bdry */
	u_int sc_maxi;	/* max interrupt */
	caddr_t scnb_addr;
	unsigned scn_bdp;
	u_short scn_sync;
} scnsoftc[NSCN];

#define	SCN_GO	01
#define	SCN_IE	0100
#define	SCN_NEX	040000
#define	SCN_ERROR	0100000

#define SCNSIZE 16384
#define SCNPAD	16384
#define SCNMASK (SCNPAD-1)
#define SCNHSIZE 8192
#define SCNHREG 16
#define SCNREGMASK	0760
#define SCNREST 037777740000

#define SCN_LADDR	037777
#define SCN_HADDR	074

int	scnprobe(), scnattach(), scndgo(), scnintr();
int	scnstrategy(), scnstart();
u_int scnminp();
struct	uba_ctlr *scnminfo[NSCN];
struct	uba_device *scndinfo[NSCN];
struct	uba_ctlr scnctlr[NSCN];	/* scminfo points to this */
u_short scnstd[]	= { 0174020, 0};	
struct	uba_driver scndriver =
	{ scnprobe,0,scnattach,scndgo,scnstd,"scn",scndinfo,"scn",scnminfo };

#define ui_open	ui_type
struct	buf	scnbuf[NSCN];
struct	buf	scnutab[NSCN];




/*ARGSUSED*/
scnprobe(reg)
caddr_t reg;
{
	register int br, cvec;	/*int vecs at 310 & 314 */
	register struct scndevice *scnaddr = (struct scndevice *) reg;
	register short bucket;
#ifdef LINT
	br = 0; cvec = br; br = cvec;
#endif

	scnaddr->scn_recvst = SCN_REC_IE;
	scnaddr->scn_send = SCNRS_S;
	DELAY(10000);
	bucket = scnaddr->scn_recv;	
	scnaddr->scn_recvst = 0;
	return(1);
}

scnattach(ui)
register struct uba_device *ui;
{
	register struct uba_ctlr *um;
	register int unit;

	unit = ui->ui_unit;

	um = &scnctlr[unit];
	scnminfo[unit] = um;
	ui->ui_ctlr = unit;
	ui->ui_mi = um;
	um->um_driver = ui->ui_driver;
	um->um_ctlr = unit;
	um->um_ubanum = ui->ui_ubanum;
	um->um_alive = 1;
	um->um_intr = ui->ui_intr;
	um->um_addr = ui->ui_addr;
	um->um_hd = ui->ui_hd;
}

scnopen(dev)
dev_t dev;
{
	register int unit = minor(dev);
	register struct scnsoftc *scnp = &scnsoftc[minor(dev)];
	register struct uba_device *ui = scndinfo[unit];
	register struct scndevice *draddr = (struct scndevice *)ui->ui_addr;

	if((unit >= NSCN) || (scndinfo[unit]->ui_open)) {
		u.u_error = ENXIO;
		return;
	}
	scndinfo[unit]->ui_open++;
	draddr->scn_recvst = 0;
	scnp->sbmode = SCN_MOD_BW;
	scnp->bpmode = 0;
}

scnclose(dev)
dev_t dev;
{
	register int unit;

	scndinfo[minor(dev)]->ui_open = 0;
}

scnread(dev)
dev_t dev;
{
	register int unit = minor(dev);
	physio(scnstrategy,&scnbuf[unit],dev,B_READ,scnminp);

}

scnwrite(dev)
dev_t dev;
{
	register int unit = minor(dev);

	physio(scnstrategy,&scnbuf[unit],dev,B_WRITE,scnminp);
}
u_int
scnminp(bp)
struct buf *bp;
{
	register struct scnsoftc *scnp;
	scnp = &scnsoftc[minor(bp->b_dev)];
	scnp->sc_maxi = ((bp->b_bcount - SCNPAD)/SCNHSIZE);
}

/*
 * Due to the fact the scstrategy routine is called only by scnread
 * and scnwrite via physio, there will only be one transaction in each
 * DR11-B's queue at any time.  Therefore, one can just tack the given
 * buffer header pointer on at the end of the queue, and call scstart.
 */
scnstrategy(bp)
register struct buf *bp;
{
	register struct uba_device *ui;
	register struct uba_ctlr *um;
	register struct buf *dp;
	register int s;
	struct scndevice *draddr;
	dev_t unit;


	unit = minor(bp->b_dev);	/* chose a DR11-B */
	ui = scndinfo[unit];
	um = ui->ui_mi;		/* get ctlr ptr */
	dp = &scnutab[unit];
	s = spl5();
	dp->b_actf = bp;
	dp->b_actl = bp;
	bp->av_forw = NULL;
	um->um_tab.b_actf = dp;
	um->um_tab.b_actl = dp;
	scnstart(um);
	splx(s);	/*dennis says this should go away*/
	switch(tsleep((caddr_t)bp, PRIBIO+1, 20)) {
	case TS_OK:
		break;
	case TS_SIG:	/* not supposed to happen*/
	case TS_TIME:
		draddr = (struct scndevice *)um->um_addr;
		bp->b_flags |=  B_ERROR;
		s = spl6();	/* if other goes this can to*/
		printf("timeout calling scintr\n");
		scnintr(unit);
		splx(s);	/*likewise this*/
	}
/*	splx(s);	this is where dennis thinks it should be*/

}

scnstart(um)
register struct uba_ctlr *um;
{
	register struct buf *bp,*dp;
	register struct scndevice *draddr;
	register struct scnsoftc *scnp;
	int cmd;

	dp = um->um_tab.b_actf;
	bp = dp->b_actf;
	scnp = &scnsoftc[minor(bp->b_dev)];

	scnp->sc_intno = 0;
	um->um_tab.b_active++;
	draddr = (struct scndevice *)um->um_addr;
	draddr->scnwc = -1;
	if(bp->b_flags & B_READ)
		cmd = SCN_IE;	
	else{
		u.u_error = EFAULT;
	}
	um->um_cmd = cmd|SCN_GO;
	draddr->scndata = scnp->sbmode|scnp->bpmode|SCN_ARM;

	draddr->scncs = cmd;
	bp->b_bcount = SCNSIZE + SCNPAD;

	DELAY(10);
	if( ubago(scndinfo[minor(bp->b_dev)])== 0)
		printf("ubago returned 0\n");
}

scndgo(um)
struct uba_ctlr *um;
{
	register struct scndevice *draddr = (struct scndevice *)um->um_addr;
	register unsigned addr, temp;
	register struct scnsoftc *scnp;
	struct buf *bp, *dp;

	dp = um->um_tab.b_actf;
	bp = dp->b_actf;
	scnp = &scnsoftc[minor(bp->b_dev)];

/*	temp = bp->b_un.b_addr;*/
	addr = um->um_ubinfo;
	addr = (addr + (SCNSIZE-1)) & ~(SCNSIZE-1);
/*	temp = (temp + (SCNSIZE-1)) & ~(SCNSIZE-1);*/
	scnp->scnreg = UBAI_MR(addr);
	scnp->scn_offset = (addr - um->um_ubinfo) & (SCNSIZE-1);
					/* add half so intr can */
	scnp->scnb_addr = bp->b_un.b_addr  + SCNHSIZE + scnp->scn_offset;
							/*was temp*/
	temp = UBAI_BDP(addr);
	scnp->scn_bdp = (temp << UBAMR_DPSHIFT) | UBAMR_MRV;
	printf("scndgo uminfo %o addr %o reg %o b_addr %o\n",um->um_ubinfo,
		addr, scnp->scnreg,bp->b_un.b_addr);
	printf("ba %o cs %o scnbaddr %o offset %o\n",(addr&040000),
		(um->um_cmd|((addr>>12)&SCN_HADDR)), scnp->scnb_addr,
		scnp->scn_offset);

	draddr->scnba = 0;
	scnp->scn_sync = 0;
	draddr->scncs = um->um_cmd|((addr>>12)&SCN_HADDR);
	draddr->scn_recvst |= SCN_REC_IE;
	draddr->scn_send = SCN_SCAN;
}

scnioctl(dev, cmd, arg)
dev_t dev;
int cmd;
register caddr_t arg;
{
	register struct scnsoftc *scnp = &scnsoftc[minor(dev)];
	register struct uba_device *ui = scndinfo[minor(dev)];
	register struct scndevice *draddr = (struct scndevice *)ui->ui_addr;
	register struct uba_ctlr *um;
	u_short realcmd;
	u_short stat;
	if( (cmd != SCNRECST) && (cmd != SCNREC) && (cmd != SCNSENDST)
		& (cmd != SCNHACK)){
		if(copyin(arg, (caddr_t)&realcmd, sizeof(realcmd))){
			u.u_error = EFAULT;
			return;
		}
	}
	switch(cmd){
	case SCNSENDST:
		realcmd = draddr->scn_sendst;
		break;
	case SCNSEND:
		stat = draddr->scn_sendst;
		if(stat & SCN_SREADY)
			draddr->scn_send = realcmd;
		else u.u_error = EFAULT;
		return;
	case SCNRECST:
		realcmd = draddr->scn_recvst;
		break;
	case SCNREC:
		realcmd = draddr->scn_recv;
		break;
	case SCNHACK:
		realcmd = scnp->scn_offset;
		break;
	case SCNSBMOD:
		scnp->sbmode = realcmd & SCN_SBMASK;
		return;
	case SCNBPMOD:
		scnp->bpmode = realcmd & SCN_BPMASK;
		return;
	default:
		u.u_error = ENXIO;
		return;
	}
	if(copyout((caddr_t)&realcmd, arg, sizeof(realcmd)))
		u.u_error = EFAULT;
}
scnreset() {}

scnxintr(dr11)
register dr11;
{
	register struct scndevice *draddr;
	register struct uba_ctlr *um;
	struct buf *dp, *bp;
	register int stat;
	struct scnsoftc *scnp;

	um = scnminfo[dr11];
	draddr = (struct scndevice *)um->um_addr;

	stat = draddr->scn_recv;
	if(stat == SCN_STATE2){
		draddr->scn_send = SCN_WAIT;
		return;
	}
	if(stat == SCN_STATE3){
		scnp = &scnsoftc[minor(dr11)];
		printf("got ack state 3:intno %o max %o\n", scnp->sc_intno,scnp->sc_maxi);
		dp = um->um_tab.b_actf;
		bp= dp->b_actf;
		draddr->scndata = 0;
		draddr->scn_recvst = 0;
		draddr->scncs = 0;
		um->um_tab.b_active = 0;
		um->um_tab.b_errcnt = 0;
		um->um_tab.b_actf = dp->b_forw;
		dp->b_errcnt = 0;
		dp->b_active = 0;
		bp->b_resid = 0;
		ubadone(um);
		iodone(bp);
		return;
	}
	return;
}

scnintr(dr11)
register dr11;
{
	register struct buf *bp,*dp;
	register struct scndevice *draddr;
	register struct uba_ctlr *um;
	register unsigned stat, reg,temp;
	u_short bit;
	struct pte *io, *pte;
	struct scnsoftc *scnp;

	um = scnminfo[dr11];
	scnp = &scnsoftc[dr11];

	if(um->um_tab.b_active == 0)
		return;

	if(scndinfo[dr11]->ui_open == 0)
		return;
	dp = um->um_tab.b_actf;
	bp = dp->b_actf;
	draddr = (struct scndevice *)um->um_addr;
	stat = draddr->scncs;
	if(stat & SCN_ERROR){
		reg = draddr->scnba;
		printf("scanner error %o addr %o intno %d\n",stat,
			reg,scnp->sc_intno);
		goto scbad;
	}
	if(scnp->sc_intno >= scnp->sc_maxi){
		printf("quiting on maxi %o\n",scnp->sc_intno);
		goto scbad;
	}
	bit = draddr->scnba & 020000;
	if(scnp->scn_sync == bit)
		printf("scn out of sync %d addr=%o\n",
			scnp->sc_intno,draddr->scnba);
	scnp->scn_sync = bit;
	reg = scnp->scnreg;
	if(scnp->sc_intno++ & 01)
		reg += SCNHREG;
	scnp->scnb_addr += SCNHSIZE;

	stat = btop(scnp->scnb_addr);
	pte = vtopte(bp->b_proc, stat);
 	
	io = &um->um_hd->uh_uba->uba_map[reg];
	stat = SCNHREG;
	temp = scnp->scn_bdp;
	while(stat-- > 0){
		if(pte->pg_pfnum == 0){
			printf("about to write to 0 pte int %o stat %d\n",
				scnp->sc_intno,stat);
			goto scbad;
		}
		*(int *)io++ = pte++->pg_pfnum | temp;
	}
	return;

scbad:
	draddr->scndata = 0;	/*turn off arm bit*/
	draddr->scn_recvst = 0;	/*turn off recv intr*/
	draddr->scncs = 0;	/*turn off scn intr*/
	um->um_tab.b_active = 0;
	um->um_tab.b_errcnt = 0;
	um->um_tab.b_actf = dp->b_forw;
	dp->b_errcnt = 0;
	dp->b_active = 0;
	bp->b_resid = 0;
	ubadone(um);
	iodone(bp);

}
#endif