xref: /csrg-svn/sys/vax/uba/lpa.c (revision 8476)
1*8476Sroot /*	lpa.c	4.6	82/10/10	*/
2*8476Sroot 
36968Ssam #include "lpa.h"
46968Ssam #if NLPA > 0
56968Ssam 
66968Ssam #include "../h/param.h"
76968Ssam #include "../h/dir.h"
86968Ssam #include "../h/user.h"
96968Ssam #include "../h/buf.h"
106968Ssam #include "../h/proc.h"
116968Ssam #include "../h/ioctl.h"
127729Sroot #include "../h/uio.h"
136968Ssam 
14*8476Sroot #include "../vaxuba/ubavar.h"
15*8476Sroot 
166968Ssam /*
176968Ssam  *	LPA driver for 4.1BSD
186968Ssam  *	Asa Romberger
196968Ssam  * method of usage:
206968Ssam  *	open
216968Ssam  *	write microcode
226968Ssam  *	write dedicated mode dispatch table
236968Ssam  *	ioctl TIOCSETP to set parameters
246968Ssam  *		struct iocb {
256968Ssam  *			short *baddr;	buffer address
266968Ssam  *			short rate;	- 1,000,000 / frequency in Hz
276968Ssam  *			short wc;	15-13 = number of buffers - 1
286968Ssam  *					12-0 = buffer size in words
296968Ssam  *		} iocb;
306968Ssam  *	read - 1 character indicating buffer index
316968Ssam  *		fill or empty buffer
326968Ssam  * minor device number = DDCCCCCC where:
336968Ssam  *	DD	= 00 for analog input
346968Ssam  *		= 01 for analog output
356968Ssam  *	CCCCCC	= channel number
366968Ssam  */
376968Ssam /*
386968Ssam  *	define TRACELPA to get trace printouts on the console
396968Ssam  *	define NOMCODE to eliminate the microcode download check
406968Ssam  */
416968Ssam /*	#define	NOMCODE		*/
426968Ssam 
436968Ssam #ifdef TRACELPA
446968Ssam #	define TRACER(x)	printf(x)
456968Ssam #	define TRACERN(x, d)	printf(x, d)
466968Ssam #else
476968Ssam #	define TRACER(x)
486968Ssam #	define TRACERN(x, d)
496968Ssam #endif
506968Ssam 
516968Ssam 	/* PRIORITY AT WHICH PROGRAM SHOULD RUN */
526968Ssam 	/* THIS SHOULD EVENTUALLY  TELL UNIX THIS IS A REAL-TIME DEVICE */
536968Ssam 
546968Ssam #define NICE	0
556968Ssam 
566968Ssam 	/* WAKEUP PRIORITY */
576968Ssam 
586968Ssam #define LPAPRI	(PZERO + 0)
596968Ssam 
606968Ssam 	/* MACRO DEFINITIONS */
616968Ssam #define inc(v)	(sc->v = ((sc->v + 1) % sc->sc_nbuf))
626968Ssam #define LPAUNIT(dev)	0
636968Ssam #define LPADEVICE(dev)	(((dev) >> 6) & 03)
646968Ssam #define LPACHANNEL(dev)	((dev) & 077)
656968Ssam 
666968Ssam 	/* DEFINITIONS FOR INTERACTION WITH UNIX I/O */
676968Ssam 
686968Ssam int lpaprobe(), /*lpaslave(),*/ lpaattach() /*,lpadgo()*/;
696968Ssam int lpaiintr(), lpaointr();
706968Ssam u_short lpastd[] = {0170460, 0};
716968Ssam struct uba_device *lpadinfo[NLPA];
726968Ssam /*struct uba_ctlr *lpaminfo[Ndevice name];*/
736968Ssam struct uba_driver lpadriver =
746968Ssam 	{lpaprobe, 0/*lpaslave*/, lpaattach, 0/*lpadgo*/, lpastd,
756968Ssam 	"lpa", lpadinfo, 0/*"device name"*/, 0/*lpaminfo*/, 0/*exclusive use*/};
766968Ssam 
776968Ssam 
786968Ssam 	/* LPA SOFTWARE OPERATION FLAGS */
796968Ssam 
806968Ssam struct lpa_softc {
816968Ssam 	int	sc_flag;	/* flags, as defined below */
826968Ssam 	int	sc_device;	/* device: 0 = analog in, 1 = analog out */
836968Ssam 	int	sc_channel;	/* device channel number */
846968Ssam 	struct buf sc_ubuffer;	/* user buffer header */
856968Ssam 	int	sc_ubabuf;	/* uba allocation pointer for buffer */
866968Ssam 	int	sc_ubufn;	/* present buffer that user is accessing */
876968Ssam 	int	sc_lbufn;	/* present buffer that lpa is accessing */
886968Ssam 	int	sc_lbufnx;	/* next buffer for lpa (value in ustat) */
896968Ssam 	int	sc_nbuf;	/* number of buffers */
906968Ssam 	int	sc_count;	/* buffer size in words */
916968Ssam 	short	sc_ustat;	/* user status word */
926968Ssam 	struct buf sc_ustatbuf;	/* dummy user status word buffer for ubasetup */
936968Ssam 	int	sc_ubaustat;	/* uba allocation pointer for ustat */
946968Ssam 	struct buf *sc_buffer;	/* scratch buffer header */
956968Ssam 	int	sc_start;	/* 0 if lpa operation has been started */
966968Ssam } lpa_softc[NLPA];
976968Ssam     /* flag bits */
986968Ssam #define OPEN	01		/* device is open */
996968Ssam #define MCODE	02		/* microcode has been loaded */
1006968Ssam #define DMDT	04		/* dedicated mode dispatch table loaded */
1016968Ssam #define STTY	010		/* stty call and device initialized */
1026968Ssam #define SLEEP	020		/* sleeping */
1036968Ssam     /* ustat bits */
1046968Ssam #define DONE	0100000		/* done */
1056968Ssam #define STOP	0040000		/* stop data transfer */
1066968Ssam #define NBI	0003400		/* next buffer index */
1076968Ssam #define LBI	0000003		/* last buffer index */
1086968Ssam 
1096968Ssam 	/* DEVICE REGISTER DESCRIPTION AREA */
1106968Ssam 
1116968Ssam struct lpadevice {
1126968Ssam 	short	lcim;		/* control in and maintenance */
1136968Ssam 	short	lcos;		/* control and status out */
1146968Ssam 	short	lrda;		/* request description array address word */
1156968Ssam 	short	lms;		/* maintenance status */
1166968Ssam };
1176968Ssam     /* control in and maintenance register bits */
1186968Ssam #define	READYI	0000200		/* ready in */
1196968Ssam #define IIE	0000100		/* in interrupt enable */
1206968Ssam #define RDAEXT	0000014		/* rda address extension */
1216968Ssam #define RDAEXTOFFSET	2	/* offset of RDAEXT from right side */
1226968Ssam #define GO	0000001		/* go */
1236968Ssam #define RUN	0100000		/* run */
1246968Ssam #define RESET	0040000		/* reset */
1256968Ssam #define CWRITE	0020000		/* cram write */
1266968Ssam #define EA	0004000		/* enable arbitration */
1276968Ssam #define ROMO	0002000		/* rom O */
1286968Ssam #define ROMI	0001000		/* rom I */
1296968Ssam #define SMICRO	0000400		/* step microprocessor */
1306968Ssam     /* control and status out register bits */
1316968Ssam #define READYO	0200		/* ready out */
1326968Ssam #define OIE	0100		/* out interrupt enable */
1336968Ssam #define UINDEX	0007		/* user index */
1346968Ssam #define ERROR	0100000		/* error */
1356968Ssam #define ESTAT	0060000		/* error status */
1366968Ssam #define ESCODE	0017400		/* error sub code */
1376968Ssam #define ECODE	0077400		/* error status + error sub code */
1386968Ssam #define OVERRUN	0243		/* overrun error */
1396968Ssam 
1406968Ssam 	/* LPA COMMAND DESCRIPTION AREA */
1416968Ssam 
1426968Ssam 	/* INIT COMMAND */
1436968Ssam #define INIT	0		/* mode */
1446968Ssam #define MCVERS	4		/* microcode version */
1456968Ssam #define ACLOCKA	0170404		/* LPA bus addresses */
1466968Ssam #define ACLOCKB	0170432
1476968Ssam #define AAD1	0170400
1486968Ssam #define AAD2	1		/* 0170440 - DOES NOT EXIST */
1496968Ssam #define ADA	0170420
1506968Ssam #define ADIO1	1		/* 0167770 - DOES NOT EXIST */
1516968Ssam #define ADIO2	1		/* 0167760 - DOES NOT EXIST */
1526968Ssam #define ADIO3	1		/* 0167750 - DOES NOT EXIST */
1536968Ssam #define ADIO4	1		/* 0167740 - DOES NOT EXIST */
1546968Ssam #define ADIO5	1		/* 0167730 - DOES NOT EXIST */
1556968Ssam 	/* CLOCK START COMMAND */
1566968Ssam #define CLOCK	1		/* mode */
1576968Ssam #define CLOCKA	0<<4		/* clock A */
1586968Ssam 		/* clock status word */
1596968Ssam #define ENACTR	1		/* enable counter */
1606968Ssam #define R1M	1<<1		/* 1 MHz rate */
1616968Ssam #define R100K	2<<1		/* 100 KHz rate */
1626968Ssam #define R10K	3<<1		/* 10 KHz rate */
1636968Ssam #define R1K	4<<1		/* 1 KHz rate */
1646968Ssam #define R100	5<<1		/* 100 Hz rate */
1656968Ssam #define REXT	6<<1		/* external rate (from st1 input) */
1666968Ssam #define R60	7<<1		/* line frequency rate */
1676968Ssam #define MFIE	0100		/* mode flag interrupt enable */
1686968Ssam #define MSI	0<<8		/* single interval mode */
1696968Ssam #define MRI	1<<8		/* repeat interval mode */
1706968Ssam #define MEET	2<<8		/* external event time mode */
1716968Ssam #define MEETZ	3<<8		/* external event time mode from zero base */
1726968Ssam #define ST1EC	020000		/* st1 enable counter */
1736968Ssam #define ST1IE	040000		/* st1 interrupt enable */
1746968Ssam 	/* DATA TRANSFER START COMMAND */
1756968Ssam #define DTS	2		/* mode */
1766968Ssam #define SCHAN	1<<8		/* single channel */
1776968Ssam 
1786968Ssam 	/* THE ROUTINES THEMSELVES */
1796968Ssam 
1806968Ssam /*
1816968Ssam  *	probe lpa to get br level and interrupt vector
1826968Ssam  */
1836968Ssam lpaprobe(reg)
1846968Ssam caddr_t reg;
1856968Ssam {
1866968Ssam 	register int br, cvec;	/* value result (required for UNIX) */
1876968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) reg;
1886968Ssam 
1896968Ssam #ifdef lint
1906968Ssam 	br = 0; cvec = br; br = cvec;
1916968Ssam #endif
1926968Ssam 	/* this should force an interrupt, stall, clear the lpa */
1936968Ssam 	br = 0x15;
1946968Ssam 	cvec = 0330;
1956968Ssam TRACER("PROBE\n");
1967413Skre 	return (sizeof (struct lpadevice));
1976968Ssam }
1986968Ssam 
1996968Ssam /*
2006968Ssam  *	attach the specified controller
2016968Ssam  */
2026968Ssam lpaattach(ui)
2036968Ssam register struct upa_device *ui;
2046968Ssam {
2056968Ssam 	/* any stuff necessary for initialization can go here */
2066968Ssam }
2076968Ssam 
2086968Ssam /*
2096968Ssam  *	open the device
2106968Ssam  */
2116968Ssam lpaopen(dev, flag)
2126968Ssam dev_t dev;
2136968Ssam int flag;
2146968Ssam {
2156968Ssam 	register int unit = LPAUNIT(dev);
2166968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
2176968Ssam 	register struct uba_device *ui = lpadinfo[unit];
2186968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
2196968Ssam 
2206968Ssam TRACER("OPEN\n");
2216968Ssam 	if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 ||
2226968Ssam 	    ui->ui_alive == 0) {
2236968Ssam 		u.u_error = ENXIO;
2246968Ssam 		return;
2256968Ssam 	}
2266968Ssam 	(void) spl7();
2276968Ssam 	lpaaddr->lcim = RESET;
2286968Ssam 	lpaaddr->lcim = 0;
2296968Ssam 	(void) spl0();
2306968Ssam 	lpaaddr->lcos = 0;	/* clear the registers as a precaution */
2316968Ssam 	lpaaddr->lrda = 0;
2326968Ssam 	lpaaddr->lms = 0;
2336968Ssam 	sc->sc_flag = OPEN;
2346968Ssam 	sc->sc_device = LPADEVICE(dev);
2356968Ssam 	sc->sc_channel = LPACHANNEL(dev);
2366968Ssam 	sc->sc_buffer = geteblk();
2376968Ssam 	sc->sc_buffer->b_error = 0;
2386968Ssam 	sc->sc_buffer->b_proc = u.u_procp;
2396968Ssam 	sc->sc_ubufn = -1;
2406968Ssam 	/* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */
2416968Ssam 	u.u_procp->p_nice = NICE;
2426968Ssam }
2436968Ssam 
2446968Ssam /*
2456968Ssam  *	close the device
2466968Ssam  */
2476968Ssam lpaclose(dev, flag)
2486968Ssam dev_t dev;
2496968Ssam int flag;
2506968Ssam {
2516968Ssam 	register int unit = LPAUNIT(dev);
2526968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
2536968Ssam 	register struct uba_device *ui = lpadinfo[unit];
2546968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
2556968Ssam 
2566968Ssam 	if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) {
2576968Ssam 		if (sc->sc_start)
2586968Ssam 			lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
2596968Ssam 		sc->sc_flag |= STOP;
2606968Ssam 		(void) spl5();
2616968Ssam 		while (sc->sc_flag & STOP) {
2626968Ssam TRACER("SLEEP\n");
2636968Ssam 			sc->sc_flag |= SLEEP;
2646968Ssam 			sleep((caddr_t)sc, LPAPRI);
2656968Ssam 		}
2666968Ssam 	}
2676968Ssam 	(void) spl7();
2686968Ssam 	lpaaddr->lcim = RESET;
2696968Ssam 	lpaaddr->lcim = 0;
2706968Ssam 	(void) spl0();
2716968Ssam 	if (sc->sc_ubabuf) {
2726968Ssam 		ubarelse(ui->ui_ubanum, &sc->sc_ubabuf);
2736968Ssam 		sc->sc_ubabuf = 0;
2746968Ssam 		(void) spl6();
2756968Ssam 		vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount,
2766968Ssam 			(sc->sc_device)? B_READ : B_WRITE);
2776968Ssam 		u.u_procp->p_flag &= ~SPHYSIO;
2786968Ssam 		(void) spl0();
2796968Ssam 	}
2806968Ssam 	if (sc->sc_ubaustat) {
2816968Ssam 		ubarelse(ui->ui_ubanum, &sc->sc_ubaustat);
2826968Ssam 		sc->sc_ubaustat = 0;
2836968Ssam 	}
2846968Ssam 	if (sc->sc_buffer) {
2856968Ssam 		brelse(sc->sc_buffer);
2866968Ssam 		sc->sc_buffer = 0;
2876968Ssam 	}
2886968Ssam 	sc->sc_flag = 0;
2896968Ssam TRACER("CLOSE\n");
2906968Ssam }
2916968Ssam 
2926968Ssam /*
2936968Ssam  *	write
2946968Ssam  *		first write is the microcode
2956968Ssam  *		second write is the dispatch table
2966968Ssam  */
2977835Sroot lpawrite(dev, uio)
2987835Sroot 	dev_t dev;
2997835Sroot 	struct uio *uio;
3006968Ssam {
3016968Ssam 	register int unit = LPAUNIT(dev);
3026968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
3036968Ssam 	register struct uba_device *ui = lpadinfo[unit];
3046968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
3056968Ssam 	register int f;
3066968Ssam 
3076968Ssam TRACER("WRITE\n");
3086968Ssam 	f = sc->sc_flag;
3096968Ssam 	if ((f & OPEN) == 0) {
3106968Ssam 		u.u_error = ENXIO;
3116968Ssam 		return;
3126968Ssam 	}
3136968Ssam 	if ((f & MCODE) == 0) {
3147835Sroot 		lpamcode(lpaaddr, sc, uio);
3156968Ssam 		return;
3166968Ssam 	}
3176968Ssam 	if ((f & DMDT) == 0) {
3187835Sroot 		lpadmdt(lpaaddr, sc, ui->ui_ubanum, uio);
3196968Ssam 		return;
3206968Ssam 	}
3216968Ssam 	/* writes are only for microcode and dedicated mode dispatch table */
3226968Ssam 	u.u_error = ENXIO;
3236968Ssam }
3246968Ssam 
3257835Sroot lpamcode(lpaaddr, sc, uio)
3267835Sroot 	register struct lpadevice *lpaaddr;
3277835Sroot 	register struct lpa_softc *sc;
3287835Sroot 	struct uio *uio;
3296968Ssam {
3306968Ssam 	short v, r;
3316968Ssam 	register int mcaddr;
3326968Ssam 
3336968Ssam 	mcaddr = 0;
3347835Sroot 	while (uio->uio_resid) {
3357835Sroot 		uiomove(&v, 2, UIO_WRITE, uio);	/* get next microcode word */
3366968Ssam 		lpaaddr->lcim = 0;		/* load microcode word */
3376968Ssam 		lpaaddr->lrda = mcaddr;
3386968Ssam 		lpaaddr->lms = v;
3396968Ssam 		lpaaddr->lcim = ROMO;
3406968Ssam 		lpaaddr->lcim |= CWRITE;
3416968Ssam 		lpaaddr->lcim = 0;		/* verify microcode word */
3426968Ssam 		lpaaddr->lrda = mcaddr;
3436968Ssam 		lpaaddr->lcim = ROMO;
3446968Ssam 		if ((r = lpaaddr->lms) != v) {
3456968Ssam 			/* download failure */
3466968Ssam 			printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r);
3476968Ssam 			u.u_error = ENXIO;
3486968Ssam 			return;
3496968Ssam 		}
3506968Ssam 		mcaddr++;
3516968Ssam 	}
3526968Ssam 	lpaaddr->lcim = RUN | EA;	/* turn it on */
3536968Ssam 	sc->sc_flag |= MCODE;
3546968Ssam 	lpaaddr->lcim |= IIE;
3556968Ssam 	lpaaddr->lcos |= OIE;
3566968Ssam TRACER("MCODE\n");
3576968Ssam }
3586968Ssam 
3597835Sroot lpadmdt(lpaaddr, sc, ubanum, uio)
3607835Sroot 	register struct lpadevice *lpaaddr;
3617835Sroot 	register struct lpa_softc *sc;
3627835Sroot 	register short ubanum;
3637835Sroot 	struct uio *uio;
3646968Ssam {
3656968Ssam 	register short *p;
3666968Ssam 	register int n;
3676968Ssam 
3686968Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;		/* INIT */
3696968Ssam 	*p++ = (MCVERS << 8) | INIT;	/* mode */
3706968Ssam 	*p++ = ACLOCKA;		/* LPA bus device addresses */
3716968Ssam 	*p++ = ACLOCKB;
3726968Ssam 	*p++ = AAD1;
3736968Ssam 	*p++ = AAD2;
3746968Ssam 	*p++ = ADA;
3756968Ssam 	*p++ = ADIO1;
3766968Ssam 	*p++ = ADIO2;
3776968Ssam 	*p++ = ADIO3;
3786968Ssam 	*p++ = ADIO4;
3796968Ssam 	*p++ = ADIO5;
3807835Sroot 	n = min(uio->uio_resid, 256);	/* dedicated mode dispatch table */
3817835Sroot 	uiomove((char *)p, n, UIO_WRITE, uio);
3826968Ssam 	n >>= 1;
3836968Ssam 	p += n;
3846968Ssam 	while (n++ < 128)
3856968Ssam 		*p++ = 0;
3866968Ssam 	lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum);
3876968Ssam 	sc->sc_flag |= DMDT;
3886968Ssam TRACER("DMDT\n");
3896968Ssam }
3906968Ssam 
3917632Ssam lpaioctl(dev, cmd, data, flag)
3927632Ssam 	dev_t dev;
3937632Ssam 	caddr_t data;
3946968Ssam {
3956968Ssam 	register int unit = LPAUNIT(dev);
3966968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
3976968Ssam 	register struct uba_device *ui = lpadinfo[unit];
3986968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
3996968Ssam 	register short *p;
4006968Ssam 	register int i;
4016968Ssam 	register int v;
4026968Ssam 	struct iocb {
4036968Ssam 		short *baddr;
4046968Ssam 		short rate;
4056968Ssam 		short wc;
4067632Ssam 	} *iocb;
4076968Ssam 
4086968Ssam TRACER("IOCTL IN\n");
4096968Ssam 	if (cmd != TIOCSETP) {
4106968Ssam TRACER("NOT TIOCSETP\n");
4116968Ssam 		/* not valid */
4126968Ssam 		u.u_error = ENXIO;
4136968Ssam 		return;
4146968Ssam 	}
4156968Ssam #ifndef NOMCODE
4166968Ssam 	if ((sc->sc_flag & DMDT) == 0) {
4176968Ssam TRACER("NO DMDT\n");
4186968Ssam 		u.u_error = ENXIO;
4196968Ssam 		return;
4206968Ssam 	}
4216968Ssam #endif
4227632Ssam 	iocb = (struct iocb *)data;
4236968Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;	/* CLOCK START */
4246968Ssam 	*p++ = CLOCK | CLOCKA;			/* mode */
4256968Ssam 	*p++ = ENACTR | R1M | MFIE | MRI;	/* clock status */
4267632Ssam 	*p = iocb->rate;			/* clock preset */
4276968Ssam 	lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
4286968Ssam TRACER("CLOCK STARTED\n");
4296968Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;	/* DATA TRANSFER START*/
4306968Ssam 	*p++ = (sc->sc_device << 7) | DTS | SCHAN;	/* mode */
4317632Ssam 	sc->sc_count = iocb->wc & 017777;	/* word count per buffer */
4326968Ssam 	*p++ = sc->sc_count;
4336968Ssam 							/* user status word */
4346968Ssam 	sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat;
4356968Ssam 	sc->sc_ustatbuf.b_flags = 0;
4366968Ssam 	sc->sc_ustatbuf.b_bcount = 2;
4376968Ssam 	sc->sc_ustatbuf.b_proc = u.u_procp;
4386968Ssam 	sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0);
4396968Ssam 	v = sc->sc_ubaustat;
4406968Ssam 	*p++ = v;
4416968Ssam 	*p = (v >> 16) & 03;		/* into low portion of word */
4427632Ssam 	sc->sc_nbuf = (iocb->wc >> 13) & 07;	/* number of buffers */
4436968Ssam 	*p++ |= sc->sc_nbuf++ << 8;		/* into high portion of word */
4446968Ssam 					/* buffer addresses */
4457632Ssam 	if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr,
4466968Ssam 		    sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2,
4476968Ssam 		    (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) {
4486968Ssam TRACER("USER BUFFER FAULT\n");
4496968Ssam 			u.u_error = EFAULT;
4506968Ssam 			return;
4516968Ssam 	}
4526968Ssam 	sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i;
4536968Ssam 	sc->sc_ubuffer.b_proc = u.u_procp;
4546968Ssam 	u.u_procp->p_flag |= SPHYSIO;
4556968Ssam 	vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount);
4566968Ssam /*	sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, UBA_NEEDBDP);*/
4576968Ssam 	sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0);
4586968Ssam 	v = sc->sc_ubabuf;
4596968Ssam 	for (i = 0; i < sc->sc_nbuf; i++) {
4606968Ssam 		*p++ = v;
4616968Ssam 		*p++ = (v >> 16) & 03;
4626968Ssam 		v += sc->sc_count * 2;
4636968Ssam 	}
4646968Ssam 	for ( ; i <= 7; i++) {
4656968Ssam 		*p++ = 0;
4666968Ssam 		*p++ = 0;
4676968Ssam 	}
4686968Ssam 	*p++ = 0; *p++ = 0;		/* random channel list address */
4696968Ssam 	*p++ = 0;			/* delay */
4706968Ssam 	*p++ = sc->sc_channel;		/* start channel, channel inc */
4716968Ssam 	*p++ = 1;			/* number of samples in a sequence */
4726968Ssam 	*p++ = 0;			/* dwell */
4736968Ssam 	*p++ = 0;			/* start word no., event mark word */
4746968Ssam 	*p++ = 0;			/* start word mask */
4756968Ssam 	*p = 0;				/* event mark mask */
4766968Ssam 	sc->sc_ustat = 0;
4776968Ssam 	sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1;
4786968Ssam 	sc->sc_lbufn = 0;
4796968Ssam 	sc->sc_lbufnx = 0;
4806968Ssam 	sc->sc_flag |= STTY;
4816968Ssam TRACER("IOCTL OUT\n");
4826968Ssam }
4836968Ssam 
4846968Ssam /*
4857835Sroot  * Lparead reads 1 character only -- the next available buffer number.
4866968Ssam  */
4877729Sroot lparead(dev, uio)
4887835Sroot 	dev_t dev;
4897835Sroot 	struct uio *uio;
4906968Ssam {
4916968Ssam 	register int unit = LPAUNIT(dev);
4926968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
4936968Ssam 	register struct uba_device *ui = lpadinfo[unit];
4946968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
4956968Ssam 
4966968Ssam TRACER("READ\n");
4976968Ssam 	if ((sc->sc_flag & STTY) == 0) {
4986968Ssam 		u.u_error = ENXIO;
4996968Ssam 		return;
5006968Ssam 	}
5016968Ssam 	if (sc->sc_flag & ERROR) {
5026968Ssam 		u.u_error = ENXIO;
5036968Ssam 		return;
5046968Ssam 	}
5056968Ssam 	if (sc->sc_start)
5066968Ssam 		if (--sc->sc_start == 0) {
5076968Ssam 			lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
5086968Ssam TRACER("START\n");
5096968Ssam 		}
5106968Ssam 	inc(sc_ubufn);
5116968Ssam 	if (sc->sc_start == 0) {
5126968Ssam 		(void) spl5();
5136968Ssam 		while (sc->sc_ubufn == sc->sc_lbufn) {
5146968Ssam 			if (sc->sc_flag & ERROR) {
5156968Ssam 				u.u_error = ENXIO;
5166968Ssam 				return;
5176968Ssam 			}
5186968Ssam TRACER("SLEEP\n");
5196968Ssam 			sc->sc_flag |= SLEEP;
5206968Ssam 			sleep(sc, LPAPRI);
5216968Ssam 		}
5226968Ssam 		(void) spl0();
5236968Ssam 	}
5246968Ssam TRACERN("READ %d\n", sc->sc_ubufn);
5257835Sroot 	uiomove(&sc->sc_ubufn, 1, UIO_READ, uio);
5266968Ssam }
5276968Ssam 
5286968Ssam /*
5297835Sroot  * Execute a lpa command and wait for completion.
5306968Ssam  */
5316968Ssam lpacmd(bp, lpaaddr, sc, ubanum)
5327835Sroot 	register struct buf *bp;
5337835Sroot 	register struct lpadevice *lpaaddr;
5347835Sroot 	register struct lpa_softc *sc;
5357835Sroot 	register short ubanum;
5366968Ssam {
5376968Ssam 	int ubareg;
5386968Ssam 
5396968Ssam TRACER("CMD\n");
5406968Ssam /*	bp->b_flags |= B_BUSY|B_WRITE;		*/
5416968Ssam 	ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP);
5426968Ssam 	lpawait(lpaaddr, sc);
5436968Ssam 	lpaaddr->lrda = ubareg;
5446968Ssam 	lpaaddr->lcim &= ~RDAEXT;
5456968Ssam 	lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO;
5466968Ssam 	lpawait(lpaaddr, sc);
5476968Ssam 	ubarelse(ubanum, &ubareg);
5486968Ssam /*	bp->b_flags &= ~(B_BUSY|B_WRITE);		*/
5496968Ssam }
5506968Ssam 
5516968Ssam /*
5526968Ssam  *	wait for completion (ready input)
5536968Ssam  */
5546968Ssam lpawait(lpaaddr, sc)
5556968Ssam register struct lpadevice *lpaaddr;
5566968Ssam register struct lpa_softc *sc;
5576968Ssam {
5586968Ssam 	(void) spl5();
5596968Ssam 	while ((lpaaddr->lcim & READYI) == 0) {
5606968Ssam TRACER("SLEEP\n");
5616968Ssam 		sc->sc_flag |= SLEEP;
5626968Ssam 		sleep((caddr_t)sc, LPAPRI);
5636968Ssam 	}
5646968Ssam 	(void) spl0();
5656968Ssam }
5666968Ssam 
5676968Ssam /*
5686968Ssam  *	lpaiintr
5696968Ssam  *		in interrupt
5706968Ssam  *		LPA is now ready to accept a user request
5716968Ssam  */
5726968Ssam lpaiintr(unit)
5736968Ssam int unit;
5746968Ssam {
5756968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
5766968Ssam 
5776968Ssam TRACER("{I");
5786968Ssam 	if (sc->sc_flag & SLEEP) {
5796968Ssam TRACER("<WAKEUP>");
5806968Ssam 		wakeup((caddr_t)sc);
5816968Ssam 		sc->sc_flag &= ~SLEEP;
5826968Ssam 	}
5836968Ssam TRACER("}");
5846968Ssam }
5856968Ssam 
5866968Ssam /*
5876968Ssam  *	lpaointr
5886968Ssam  *		out interrupt
5896968Ssam  *		LPA has status information
5906968Ssam  */
5916968Ssam lpaointr(unit)
5926968Ssam int unit;
5936968Ssam {
5946968Ssam 	register int c, m;
5956968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
5966968Ssam 	register struct uba_device *ui = lpadinfo[unit];
5976968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
5986968Ssam 	int spx;
5996968Ssam 
6006968Ssam TRACER("{O");
6016968Ssam 	if (sc->sc_flag & SLEEP) {
6026968Ssam TRACER("<WAKEUP>");
6036968Ssam 		wakeup(sc);
6046968Ssam 		sc->sc_flag &= ~SLEEP;
6056968Ssam 	}
6066968Ssam 	c = lpaaddr->lcos;
6076968Ssam 	m = lpaaddr->lms;
6086968Ssam 	lpaaddr->lcos &= ~READYO;
6096968Ssam 	if (c & ERROR) {
6106968Ssam TRACER("<ERROR>");
6116968Ssam 		c = (c >> 8) & 0377;
6126968Ssam 		if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) {
6136968Ssam 			printf("LPA ERROR %o %o\n", c, m&0177777);
6146968Ssam 			sc->sc_flag |= ERROR;
6156968Ssam 		}
6166968Ssam 		sc->sc_flag &= ~STOP;
6176968Ssam TRACER("}\n");
6186968Ssam 		return;
6196968Ssam 	}
6206968Ssam TRACERN("<LPA %d>", sc->sc_lbufnx);
6216968Ssam 	sc->sc_lbufn = sc->sc_lbufnx;
6226968Ssam 	if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) {
6236968Ssam TRACER("<STOP?>");
6246968Ssam 		if (sc->sc_flag & STOP)
6256968Ssam 			return;
6266968Ssam 		printf("LPA OVERRUN\n");
6276968Ssam 		sc->sc_flag |= ERROR;
6286968Ssam 	}
6296968Ssam 	inc(sc_lbufnx);
6306968Ssam TRACERN("<USTAT %o>", sc->sc_ustat);
6316968Ssam 	spx = spl7();
6326968Ssam 	sc->sc_ustat &= ~NBI;
6336968Ssam 	sc->sc_ustat |= sc->sc_lbufnx << 8;
6346968Ssam 	sc->sc_ustat &= ~DONE;
6356968Ssam 	(void) splx(spx);
6366968Ssam TRACERN("<LPAN %d>}", sc->sc_lbufnx);
6376968Ssam }
6386968Ssam 
6396968Ssam /*
6406968Ssam  *	reset called for a unibus reset
6416968Ssam  */
6426968Ssam lpareset(uban)
6436968Ssam int uban;
6446968Ssam {
6456968Ssam 	register struct uba_device *ui;
6466968Ssam 	register struct lpadevice *lpaaddr;
6476968Ssam 	register struct lpa_softc *sc;
6486968Ssam 	register int unit;
6496968Ssam 
6506968Ssam TRACER("LPA RESET\n");
6516968Ssam 	for (unit = 0; unit < NLPA; unit++) {
6526968Ssam 		if (	(ui = lpadinfo[unit]) == 0 ||
6536968Ssam 			ui->ui_ubanum != uban ||
6546968Ssam 			ui->ui_alive == 0)
6556968Ssam 				continue;
6566968Ssam 		printf(" lpa%d", unit);
6576968Ssam 		lpaaddr = (struct lpadevice *)ui->ui_addr;
6586968Ssam 		sc = &lpa_softc[unit];
6596968Ssam 		sc->sc_flag |= ERROR;
6606968Ssam 		(void) spl7();
6616968Ssam 		lpaaddr->lcim = RESET;
6626968Ssam 		lpaaddr->lcim = 0;
6636968Ssam 		(void) spl0();
6646968Ssam 		if (sc->sc_flag & SLEEP) {
6656968Ssam 			wakeup((caddr_t)sc);
6666968Ssam 			sc->sc_flag &= ~SLEEP;
6676968Ssam 		}
6686968Ssam 	}
6696968Ssam }
6706968Ssam #endif NLPA
671