xref: /original-bsd/sys/vax/uba/lpa.c (revision afb2e50a)
1ac9fa1f2Smckusick /*
20e670328Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
3ac9fa1f2Smckusick  * All rights reserved.  The Berkeley software License Agreement
4ac9fa1f2Smckusick  * specifies the terms and conditions for redistribution.
5ac9fa1f2Smckusick  *
6*afb2e50aSbostic  *	@(#)lpa.c	7.6 (Berkeley) 09/23/93
7ac9fa1f2Smckusick  */
842b8bd9bSroot 
987f7a842Ssam #include "lpa.h"
1087f7a842Ssam #if NLPA > 0
1187f7a842Ssam 
1239bdaf89Sbostic #include "sys/param.h"
1339bdaf89Sbostic #include "sys/user.h"
1439bdaf89Sbostic #include "sys/buf.h"
1539bdaf89Sbostic #include "sys/proc.h"
1639bdaf89Sbostic #include "sys/ioctl.h"
1739bdaf89Sbostic #include "sys/uio.h"
1887f7a842Ssam 
1971445730Sbloom #include "ubavar.h"
2042b8bd9bSroot 
2187f7a842Ssam /*
22d672d181Sroot  * LPA driver for -- Asa Romberger
23d672d181Sroot  *
2487f7a842Ssam  *	open
2587f7a842Ssam  *	write microcode
2687f7a842Ssam  *	write dedicated mode dispatch table
2787f7a842Ssam  *	ioctl TIOCSETP to set parameters
2887f7a842Ssam  *		struct iocb {
2987f7a842Ssam  *			short *baddr;	buffer address
3087f7a842Ssam  *			short rate;	- 1,000,000 / frequency in Hz
3187f7a842Ssam  *			short wc;	15-13 = number of buffers - 1
3287f7a842Ssam  *					12-0 = buffer size in words
3387f7a842Ssam  *		} iocb;
3487f7a842Ssam  *	read - 1 character indicating buffer index
3587f7a842Ssam  *		fill or empty buffer
3687f7a842Ssam  * minor device number = DDCCCCCC where:
3787f7a842Ssam  *	DD	= 00 for analog input
3887f7a842Ssam  *		= 01 for analog output
3987f7a842Ssam  *	CCCCCC	= channel number
4087f7a842Ssam  */
4187f7a842Ssam  *	define NOMCODE to eliminate the microcode download check
4287f7a842Ssam  */
43d672d181Sroot /* #define TRACELPA */
4487f7a842Ssam /* #define NOMCODE */
4587f7a842Ssam 
4687f7a842Ssam #ifdef TRACELPA
4787f7a842Ssam #	define TRACER(x)	printf(x)
4887f7a842Ssam #	define TRACERN(x, d)	printf(x, d)
4987f7a842Ssam #else
5087f7a842Ssam #	define TRACER(x)
5187f7a842Ssam #	define TRACERN(x, d)
5287f7a842Ssam #endif
5387f7a842Ssam 
5487f7a842Ssam 	/* PRIORITY AT WHICH PROGRAM SHOULD RUN */
5587f7a842Ssam 	/* THIS SHOULD EVENTUALLY  TELL UNIX THIS IS A REAL-TIME DEVICE */
5687f7a842Ssam 
5787f7a842Ssam #define NICE	0
5887f7a842Ssam 
59d672d181Sroot #define inc(v)		(sc->v = ((sc->v + 1) % sc->sc_nbuf))
6087f7a842Ssam 
6187f7a842Ssam #define LPAPRI		(PZERO + 0)
6287f7a842Ssam #define LPAUNIT(dev)	0
6387f7a842Ssam #define LPADEVICE(dev)	(((dev) >> 6) & 03)
6487f7a842Ssam #define LPACHANNEL(dev)	((dev) & 077)
6587f7a842Ssam 
66d672d181Sroot int	lpaprobe(), lpaattach(), lpaiintr(), lpaointr();
6787f7a842Ssam u_short	lpastd[] = {0170460, 0};
6887f7a842Ssam struct	uba_device *lpadinfo[NLPA];
6987f7a842Ssam struct uba_driver lpadriver =
70d672d181Sroot   {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 };
7187f7a842Ssam 
7287f7a842Ssam struct lpa_softc {
7387f7a842Ssam 	int	sc_flag;	/* flags, as defined below */
7487f7a842Ssam 	int	sc_device;	/* device: 0 = analog in, 1 = analog out */
7587f7a842Ssam 	int	sc_channel;	/* device channel number */
7687f7a842Ssam 	struct buf sc_ubuffer;	/* user buffer header */
7787f7a842Ssam 	int	sc_ubabuf;	/* uba allocation pointer for buffer */
7887f7a842Ssam 	int	sc_ubufn;	/* present buffer that user is accessing */
7987f7a842Ssam 	int	sc_lbufn;	/* present buffer that lpa is accessing */
8087f7a842Ssam 	int	sc_lbufnx;	/* next buffer for lpa (value in ustat) */
8187f7a842Ssam 	int	sc_nbuf;	/* number of buffers */
8287f7a842Ssam 	int	sc_count;	/* buffer size in words */
8387f7a842Ssam 	short	sc_ustat;	/* user status word */
8487f7a842Ssam 	struct buf sc_ustatbuf;	/* dummy user status word buffer for ubasetup */
8587f7a842Ssam 	int	sc_ubaustat;	/* uba allocation pointer for ustat */
8687f7a842Ssam 	struct buf *sc_buffer;	/* scratch buffer header */
8787f7a842Ssam 	int	sc_start;	/* 0 if lpa operation has been started */
8887f7a842Ssam } lpa_softc[NLPA];
89d672d181Sroot 
90d672d181Sroot /* flags for sc_flag */
9187f7a842Ssam #define OPEN	01		/* device is open */
9287f7a842Ssam #define MCODE	02		/* microcode has been loaded */
9387f7a842Ssam #define DMDT	04		/* dedicated mode dispatch table loaded */
9487f7a842Ssam #define STTY	010		/* stty call and device initialized */
9587f7a842Ssam #define SLEEP	020		/* sleeping */
96d672d181Sroot 
97d672d181Sroot /* bits for ustat */
9887f7a842Ssam #define DONE	0100000		/* done */
9987f7a842Ssam #define STOP	0040000		/* stop data transfer */
10087f7a842Ssam #define NBI	0003400		/* next buffer index */
10187f7a842Ssam #define LBI	0000003		/* last buffer index */
10287f7a842Ssam 
10387f7a842Ssam struct lpadevice {
10487f7a842Ssam 	short	lcim;		/* control in and maintenance */
10587f7a842Ssam 	short	lcos;		/* control and status out */
10687f7a842Ssam 	short	lrda;		/* request description array address word */
10787f7a842Ssam 	short	lms;		/* maintenance status */
10887f7a842Ssam };
109d672d181Sroot 
11087f7a842Ssam /* control in and maintenance register bits */
11187f7a842Ssam #define	READYI	0000200		/* ready in */
11287f7a842Ssam #define IIE	0000100		/* in interrupt enable */
11387f7a842Ssam #define RDAEXT	0000014		/* rda address extension */
11487f7a842Ssam #define RDAEXTOFFSET	2	/* offset of RDAEXT from right side */
11587f7a842Ssam #define GO	0000001		/* go */
11687f7a842Ssam #define RUN	0100000		/* run */
11787f7a842Ssam #define RESET	0040000		/* reset */
11887f7a842Ssam #define CWRITE	0020000		/* cram write */
11987f7a842Ssam #define EA	0004000		/* enable arbitration */
12087f7a842Ssam #define ROMO	0002000		/* rom O */
12187f7a842Ssam #define ROMI	0001000		/* rom I */
12287f7a842Ssam #define SMICRO	0000400		/* step microprocessor */
123d672d181Sroot 
12487f7a842Ssam /* control and status out register bits */
12587f7a842Ssam #define READYO	0200		/* ready out */
12687f7a842Ssam #define OIE	0100		/* out interrupt enable */
12787f7a842Ssam #define UINDEX	0007		/* user index */
12887f7a842Ssam #define ERROR	0100000		/* error */
12987f7a842Ssam #define ESTAT	0060000		/* error status */
13087f7a842Ssam #define ESCODE	0017400		/* error sub code */
13187f7a842Ssam #define ECODE	0077400		/* error status + error sub code */
13287f7a842Ssam #define OVERRUN	0243		/* overrun error */
13387f7a842Ssam 
13487f7a842Ssam /* LPA COMMAND DESCRIPTION AREA */
13587f7a842Ssam 
13687f7a842Ssam /* INIT COMMAND */
13787f7a842Ssam #define INIT	0		/* mode */
13887f7a842Ssam #define MCVERS	4		/* microcode version */
13987f7a842Ssam #define ACLOCKA	0170404		/* LPA bus addresses */
14087f7a842Ssam #define ACLOCKB	0170432
14187f7a842Ssam #define AAD1	0170400
14287f7a842Ssam #define AAD2	1		/* 0170440 - DOES NOT EXIST */
14387f7a842Ssam #define ADA	0170420
14487f7a842Ssam #define ADIO1	1		/* 0167770 - DOES NOT EXIST */
14587f7a842Ssam #define ADIO2	1		/* 0167760 - DOES NOT EXIST */
14687f7a842Ssam #define ADIO3	1		/* 0167750 - DOES NOT EXIST */
14787f7a842Ssam #define ADIO4	1		/* 0167740 - DOES NOT EXIST */
14887f7a842Ssam #define ADIO5	1		/* 0167730 - DOES NOT EXIST */
149d672d181Sroot 
15087f7a842Ssam /* CLOCK START COMMAND */
15187f7a842Ssam #define CLOCK	1		/* mode */
15287f7a842Ssam #define CLOCKA	0<<4		/* clock A */
15387f7a842Ssam 	/* clock status word */
15487f7a842Ssam #define ENACTR	1		/* enable counter */
15587f7a842Ssam #define R1M	1<<1		/* 1 MHz rate */
15687f7a842Ssam #define R100K	2<<1		/* 100 KHz rate */
15787f7a842Ssam #define R10K	3<<1		/* 10 KHz rate */
15887f7a842Ssam #define R1K	4<<1		/* 1 KHz rate */
15987f7a842Ssam #define R100	5<<1		/* 100 Hz rate */
16087f7a842Ssam #define REXT	6<<1		/* external rate (from st1 input) */
16187f7a842Ssam #define R60	7<<1		/* line frequency rate */
16287f7a842Ssam #define MFIE	0100		/* mode flag interrupt enable */
16387f7a842Ssam #define MSI	0<<8		/* single interval mode */
16487f7a842Ssam #define MRI	1<<8		/* repeat interval mode */
16587f7a842Ssam #define MEET	2<<8		/* external event time mode */
16687f7a842Ssam #define MEETZ	3<<8		/* external event time mode from zero base */
16787f7a842Ssam #define ST1EC	020000		/* st1 enable counter */
16887f7a842Ssam #define ST1IE	040000		/* st1 interrupt enable */
169d672d181Sroot 
17087f7a842Ssam /* DATA TRANSFER START COMMAND */
17187f7a842Ssam #define DTS	2		/* mode */
17287f7a842Ssam #define SCHAN	1<<8		/* single channel */
17387f7a842Ssam 
lpaprobe(reg)17487f7a842Ssam lpaprobe(reg)
17587f7a842Ssam 	caddr_t reg;
17687f7a842Ssam {
177d672d181Sroot 	register int br, cvec;	/* value result */
17887f7a842Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *)reg;
17987f7a842Ssam 
18087f7a842Ssam #ifdef lint
18187f7a842Ssam 	br = 0; cvec = br; br = cvec;
18287f7a842Ssam #endif
18387f7a842Ssam 	/* this should force an interrupt, stall, clear the lpa */
18487f7a842Ssam 	br = 0x15;
18587f7a842Ssam 	cvec = 0330;
18687f7a842Ssam TRACER("PROBE\n");
187d6764b59Skre 	return (sizeof (struct lpadevice));
18887f7a842Ssam }
18987f7a842Ssam 
lpaattach(ui)19087f7a842Ssam lpaattach(ui)
19187f7a842Ssam 	register struct upa_device *ui;
19287f7a842Ssam {
193d672d181Sroot 
19487f7a842Ssam }
19587f7a842Ssam 
lpaopen(dev,flag)19687f7a842Ssam lpaopen(dev, flag)
19787f7a842Ssam 	dev_t dev;
19887f7a842Ssam 	int flag;
19987f7a842Ssam {
20087f7a842Ssam 	register int unit = LPAUNIT(dev);
20187f7a842Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
20287f7a842Ssam 	register struct uba_device *ui = lpadinfo[unit];
20387f7a842Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
20487f7a842Ssam 
20587f7a842Ssam TRACER("OPEN\n");
20687f7a842Ssam 	if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 ||
207220098f8Sroot 	    ui->ui_alive == 0)
208220098f8Sroot 		return (ENXIO);
209395e3743Skarels 	(void) splhigh();
21087f7a842Ssam 	lpaaddr->lcim = RESET;
21187f7a842Ssam 	lpaaddr->lcim = 0;
21287f7a842Ssam 	(void) spl0();
21387f7a842Ssam 	lpaaddr->lcos = 0;	/* clear the registers as a precaution */
21487f7a842Ssam 	lpaaddr->lrda = 0;
21587f7a842Ssam 	lpaaddr->lms = 0;
21687f7a842Ssam 	sc->sc_flag = OPEN;
21787f7a842Ssam 	sc->sc_device = LPADEVICE(dev);
21887f7a842Ssam 	sc->sc_channel = LPACHANNEL(dev);
21987f7a842Ssam 	sc->sc_buffer = geteblk();
22087f7a842Ssam 	sc->sc_buffer->b_error = 0;
22187f7a842Ssam 	sc->sc_buffer->b_proc = u.u_procp;
22287f7a842Ssam 	sc->sc_ubufn = -1;
22387f7a842Ssam 	/* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */
22487f7a842Ssam 	u.u_procp->p_nice = NICE;
225220098f8Sroot 	return (0);
22687f7a842Ssam }
22787f7a842Ssam 
lpaclose(dev,flag)22887f7a842Ssam lpaclose(dev, flag)
22987f7a842Ssam 	dev_t dev;
23087f7a842Ssam 	int flag;
23187f7a842Ssam {
23287f7a842Ssam 	register int unit = LPAUNIT(dev);
23387f7a842Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
23487f7a842Ssam 	register struct uba_device *ui = lpadinfo[unit];
23587f7a842Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
23687f7a842Ssam 
23787f7a842Ssam 	if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) {
23887f7a842Ssam 		if (sc->sc_start)
23987f7a842Ssam 			lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
24087f7a842Ssam 		sc->sc_flag |= STOP;
24187f7a842Ssam 		(void) spl5();
24287f7a842Ssam 		while (sc->sc_flag & STOP) {
24387f7a842Ssam TRACER("SLEEP\n");
24487f7a842Ssam 			sc->sc_flag |= SLEEP;
24587f7a842Ssam 			sleep((caddr_t)sc, LPAPRI);
24687f7a842Ssam 		}
24787f7a842Ssam 	}
248395e3743Skarels 	(void) splhigh();
24987f7a842Ssam 	lpaaddr->lcim = RESET;
25087f7a842Ssam 	lpaaddr->lcim = 0;
25187f7a842Ssam 	(void) spl0();
25287f7a842Ssam 	if (sc->sc_ubabuf) {
25387f7a842Ssam 		ubarelse(ui->ui_ubanum, &sc->sc_ubabuf);
25487f7a842Ssam 		sc->sc_ubabuf = 0;
255395e3743Skarels 		(void) splclock();
25687f7a842Ssam 		vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount,
25787f7a842Ssam 			(sc->sc_device)? B_READ : B_WRITE);
258*afb2e50aSbostic 		u.u_procp->p_flag &= ~P_PHYSIO;
25987f7a842Ssam 		(void) spl0();
26087f7a842Ssam 	}
26187f7a842Ssam 	if (sc->sc_ubaustat) {
26287f7a842Ssam 		ubarelse(ui->ui_ubanum, &sc->sc_ubaustat);
26387f7a842Ssam 		sc->sc_ubaustat = 0;
26487f7a842Ssam 	}
26587f7a842Ssam 	if (sc->sc_buffer) {
26687f7a842Ssam 		brelse(sc->sc_buffer);
26787f7a842Ssam 		sc->sc_buffer = 0;
26887f7a842Ssam 	}
26987f7a842Ssam 	sc->sc_flag = 0;
27087f7a842Ssam TRACER("CLOSE\n");
2711db00297Skarels 	return (0);
27287f7a842Ssam }
27387f7a842Ssam 
lpawrite(dev,uio)27425aace65Sroot lpawrite(dev, uio)
27587f7a842Ssam 	dev_t dev;
27625aace65Sroot 	struct uio *uio;
27787f7a842Ssam {
27887f7a842Ssam 	register int unit = LPAUNIT(dev);
27987f7a842Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
28087f7a842Ssam 	register struct uba_device *ui = lpadinfo[unit];
28187f7a842Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
28287f7a842Ssam 	register int f;
28387f7a842Ssam 
28487f7a842Ssam TRACER("WRITE\n");
28587f7a842Ssam 	f = sc->sc_flag;
286d672d181Sroot 	if ((f & OPEN) == 0)
287d672d181Sroot 		return (ENXIO);
288d672d181Sroot 	if ((f & MCODE) == 0)		/* first write is the microcode */
289d672d181Sroot 		return (lpamcode(lpaaddr, sc, uio));
290d672d181Sroot 	if ((f & DMDT) == 0)		/* second write is the dispatch table */
291d672d181Sroot 		return (lpadmdt(lpaaddr, sc, ui->ui_ubanum, uio));
292d672d181Sroot 	return (ENXIO);
29387f7a842Ssam }
29487f7a842Ssam 
lpamcode(lpaaddr,sc,uio)29525aace65Sroot lpamcode(lpaaddr, sc, uio)
29687f7a842Ssam 	register struct lpadevice *lpaaddr;
29787f7a842Ssam 	register struct lpa_softc *sc;
29825aace65Sroot 	struct uio *uio;
29987f7a842Ssam {
30087f7a842Ssam 	short v, r;
30187f7a842Ssam 	register int mcaddr;
302af9f716dSroot 	int error;
30387f7a842Ssam 
30487f7a842Ssam 	mcaddr = 0;
30525aace65Sroot 	while (uio->uio_resid) {
30645f373caSmckusick 		error = uiomove(&v, 2, uio);
307af9f716dSroot 		if (error)
308af9f716dSroot 			break;
30987f7a842Ssam 		lpaaddr->lcim = 0;		/* load microcode word */
31087f7a842Ssam 		lpaaddr->lrda = mcaddr;
31187f7a842Ssam 		lpaaddr->lms = v;
31287f7a842Ssam 		lpaaddr->lcim = ROMO;
31387f7a842Ssam 		lpaaddr->lcim |= CWRITE;
31487f7a842Ssam 		lpaaddr->lcim = 0;		/* verify microcode word */
31587f7a842Ssam 		lpaaddr->lrda = mcaddr;
31687f7a842Ssam 		lpaaddr->lcim = ROMO;
31787f7a842Ssam 		if ((r = lpaaddr->lms) != v) {
31887f7a842Ssam 			/* download failure */
31987f7a842Ssam 			printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r);
320d672d181Sroot 			return (ENXIO);
32187f7a842Ssam 		}
32287f7a842Ssam 		mcaddr++;
32387f7a842Ssam 	}
32487f7a842Ssam 	lpaaddr->lcim = RUN | EA;	/* turn it on */
32587f7a842Ssam 	sc->sc_flag |= MCODE;
32687f7a842Ssam 	lpaaddr->lcim |= IIE;
32787f7a842Ssam 	lpaaddr->lcos |= OIE;
328af9f716dSroot 	return (error);
32987f7a842Ssam TRACER("MCODE\n");
33087f7a842Ssam }
33187f7a842Ssam 
lpadmdt(lpaaddr,sc,ubanum,uio)33225aace65Sroot lpadmdt(lpaaddr, sc, ubanum, uio)
33387f7a842Ssam 	register struct lpadevice *lpaaddr;
33487f7a842Ssam 	register struct lpa_softc *sc;
33587f7a842Ssam 	register short ubanum;
33625aace65Sroot 	struct uio *uio;
33787f7a842Ssam {
33887f7a842Ssam 	register short *p;
33987f7a842Ssam 	register int n;
340d672d181Sroot 	int error;
34187f7a842Ssam 
34287f7a842Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;		/* INIT */
34387f7a842Ssam 	*p++ = (MCVERS << 8) | INIT;	/* mode */
34487f7a842Ssam 	*p++ = ACLOCKA;		/* LPA bus device addresses */
34587f7a842Ssam 	*p++ = ACLOCKB;
34687f7a842Ssam 	*p++ = AAD1;
34787f7a842Ssam 	*p++ = AAD2;
34887f7a842Ssam 	*p++ = ADA;
34987f7a842Ssam 	*p++ = ADIO1;
35087f7a842Ssam 	*p++ = ADIO2;
35187f7a842Ssam 	*p++ = ADIO3;
35287f7a842Ssam 	*p++ = ADIO4;
35387f7a842Ssam 	*p++ = ADIO5;
354395e3743Skarels 	n = MIN(uio->uio_resid, 256);	/* dedicated mode dispatch table */
35545f373caSmckusick 	error = uiomove((char *)p, n, uio);
356d672d181Sroot 	if (error)
357d672d181Sroot 		return (error);
35887f7a842Ssam 	n >>= 1;
35987f7a842Ssam 	p += n;
36087f7a842Ssam 	while (n++ < 128)
36187f7a842Ssam 		*p++ = 0;
36287f7a842Ssam 	lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum);
36387f7a842Ssam 	sc->sc_flag |= DMDT;
364d672d181Sroot 	return (0);
36587f7a842Ssam TRACER("DMDT\n");
36687f7a842Ssam }
36787f7a842Ssam 
lpaioctl(dev,cmd,data,flag)368b5e757a2Ssam lpaioctl(dev, cmd, data, flag)
36987f7a842Ssam 	dev_t dev;
370b5e757a2Ssam 	caddr_t data;
37187f7a842Ssam {
37287f7a842Ssam 	register int unit = LPAUNIT(dev);
37387f7a842Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
37487f7a842Ssam 	register struct uba_device *ui = lpadinfo[unit];
37587f7a842Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
37687f7a842Ssam 	register short *p;
37787f7a842Ssam 	register int i;
37887f7a842Ssam 	register int v;
37987f7a842Ssam 	struct iocb {
38087f7a842Ssam 		short *baddr;
38187f7a842Ssam 		short rate;
38287f7a842Ssam 		short wc;
383b5e757a2Ssam 	} *iocb;
38487f7a842Ssam 
38587f7a842Ssam TRACER("IOCTL IN\n");
386220098f8Sroot 	if (cmd != TIOCSETP || (sc->sc_flag & DMDT) == 0)
387220098f8Sroot 		return (ENXIO);
388b5e757a2Ssam 	iocb = (struct iocb *)data;
38987f7a842Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;	/* CLOCK START */
39087f7a842Ssam 	*p++ = CLOCK | CLOCKA;			/* mode */
39187f7a842Ssam 	*p++ = ENACTR | R1M | MFIE | MRI;	/* clock status */
392b5e757a2Ssam 	*p = iocb->rate;			/* clock preset */
39387f7a842Ssam 	lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
39487f7a842Ssam TRACER("CLOCK STARTED\n");
39587f7a842Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;	/* DATA TRANSFER START*/
39687f7a842Ssam 	*p++ = (sc->sc_device << 7) | DTS | SCHAN;	/* mode */
397b5e757a2Ssam 	sc->sc_count = iocb->wc & 017777;	/* word count per buffer */
39887f7a842Ssam 	*p++ = sc->sc_count;
39987f7a842Ssam 							/* user status word */
40087f7a842Ssam 	sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat;
40187f7a842Ssam 	sc->sc_ustatbuf.b_flags = 0;
40287f7a842Ssam 	sc->sc_ustatbuf.b_bcount = 2;
40387f7a842Ssam 	sc->sc_ustatbuf.b_proc = u.u_procp;
40487f7a842Ssam 	sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0);
40587f7a842Ssam 	v = sc->sc_ubaustat;
40687f7a842Ssam 	*p++ = v;
40787f7a842Ssam 	*p = (v >> 16) & 03;		/* into low portion of word */
408b5e757a2Ssam 	sc->sc_nbuf = (iocb->wc >> 13) & 07;	/* number of buffers */
40987f7a842Ssam 	*p++ |= sc->sc_nbuf++ << 8;		/* into high portion of word */
41087f7a842Ssam 					/* buffer addresses */
411b5e757a2Ssam 	if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr,
41287f7a842Ssam 	    sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2,
41387f7a842Ssam 	    (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) {
41487f7a842Ssam TRACER("USER BUFFER FAULT\n");
415220098f8Sroot 		return (EFAULT);
41687f7a842Ssam 	}
41787f7a842Ssam 	sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i;
41887f7a842Ssam 	sc->sc_ubuffer.b_proc = u.u_procp;
419*afb2e50aSbostic 	u.u_procp->p_flag |= P_PHYSIO;
42087f7a842Ssam 	vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount);
42187f7a842Ssam 	sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0);
42287f7a842Ssam 	v = sc->sc_ubabuf;
42387f7a842Ssam 	for (i = 0; i < sc->sc_nbuf; i++) {
42487f7a842Ssam 		*p++ = v;
42587f7a842Ssam 		*p++ = (v >> 16) & 03;
42687f7a842Ssam 		v += sc->sc_count * 2;
42787f7a842Ssam 	}
42887f7a842Ssam 	for ( ; i <= 7; i++) {
42987f7a842Ssam 		*p++ = 0;
43087f7a842Ssam 		*p++ = 0;
43187f7a842Ssam 	}
43287f7a842Ssam 	*p++ = 0; *p++ = 0;		/* random channel list address */
43387f7a842Ssam 	*p++ = 0;			/* delay */
43487f7a842Ssam 	*p++ = sc->sc_channel;		/* start channel, channel inc */
43587f7a842Ssam 	*p++ = 1;			/* number of samples in a sequence */
43687f7a842Ssam 	*p++ = 0;			/* dwell */
43787f7a842Ssam 	*p++ = 0;			/* start word no., event mark word */
43887f7a842Ssam 	*p++ = 0;			/* start word mask */
43987f7a842Ssam 	*p = 0;				/* event mark mask */
44087f7a842Ssam 	sc->sc_ustat = 0;
44187f7a842Ssam 	sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1;
44287f7a842Ssam 	sc->sc_lbufn = 0;
44387f7a842Ssam 	sc->sc_lbufnx = 0;
44487f7a842Ssam 	sc->sc_flag |= STTY;
44587f7a842Ssam TRACER("IOCTL OUT\n");
446220098f8Sroot 	return (0);
44787f7a842Ssam }
44887f7a842Ssam 
lparead(dev,uio)4496e6bbc9cSroot lparead(dev, uio)
45087f7a842Ssam 	dev_t dev;
4516e6bbc9cSroot 	struct uio *uio;
45287f7a842Ssam {
45387f7a842Ssam 	register int unit = LPAUNIT(dev);
45487f7a842Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
45587f7a842Ssam 	register struct uba_device *ui = lpadinfo[unit];
45687f7a842Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
45787f7a842Ssam 
45887f7a842Ssam TRACER("READ\n");
459d672d181Sroot 	if ((sc->sc_flag & STTY) == 0)
460d672d181Sroot 		return (ENXIO);
461d672d181Sroot 	if (sc->sc_flag & ERROR)
462d672d181Sroot 		return (ENXIO);
46387f7a842Ssam 	if (sc->sc_start)
46487f7a842Ssam 		if (--sc->sc_start == 0) {
46587f7a842Ssam 			lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
46687f7a842Ssam TRACER("START\n");
46787f7a842Ssam 		}
46887f7a842Ssam 	inc(sc_ubufn);
46987f7a842Ssam 	if (sc->sc_start == 0) {
47087f7a842Ssam 		(void) spl5();
47187f7a842Ssam 		while (sc->sc_ubufn == sc->sc_lbufn) {
472d672d181Sroot 			if (sc->sc_flag & ERROR)
473d672d181Sroot 				return (ENXIO);
47487f7a842Ssam TRACER("SLEEP\n");
47587f7a842Ssam 			sc->sc_flag |= SLEEP;
47687f7a842Ssam 			sleep(sc, LPAPRI);
47787f7a842Ssam 		}
47887f7a842Ssam 		(void) spl0();
47987f7a842Ssam 	}
48087f7a842Ssam TRACERN("READ %d\n", sc->sc_ubufn);
48145f373caSmckusick 	return (uiomove(&sc->sc_ubufn, 1, uio));
48287f7a842Ssam }
48387f7a842Ssam 
lpacmd(bp,lpaaddr,sc,ubanum)48487f7a842Ssam lpacmd(bp, lpaaddr, sc, ubanum)
48587f7a842Ssam 	register struct buf *bp;
48687f7a842Ssam 	register struct lpadevice *lpaaddr;
48787f7a842Ssam 	register struct lpa_softc *sc;
48887f7a842Ssam 	register short ubanum;
48987f7a842Ssam {
49087f7a842Ssam 	int ubareg;
49187f7a842Ssam 
49287f7a842Ssam TRACER("CMD\n");
49387f7a842Ssam 	ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP);
49487f7a842Ssam 	lpawait(lpaaddr, sc);
49587f7a842Ssam 	lpaaddr->lrda = ubareg;
49687f7a842Ssam 	lpaaddr->lcim &= ~RDAEXT;
49787f7a842Ssam 	lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO;
49887f7a842Ssam 	lpawait(lpaaddr, sc);
49987f7a842Ssam 	ubarelse(ubanum, &ubareg);
50087f7a842Ssam }
50187f7a842Ssam 
lpawait(lpaaddr,sc)50287f7a842Ssam lpawait(lpaaddr, sc)
50387f7a842Ssam 	register struct lpadevice *lpaaddr;
50487f7a842Ssam 	register struct lpa_softc *sc;
50587f7a842Ssam {
506d672d181Sroot 
50787f7a842Ssam 	(void) spl5();
50887f7a842Ssam 	while ((lpaaddr->lcim & READYI) == 0) {
50987f7a842Ssam TRACER("SLEEP\n");
51087f7a842Ssam 		sc->sc_flag |= SLEEP;
51187f7a842Ssam 		sleep((caddr_t)sc, LPAPRI);
51287f7a842Ssam 	}
51387f7a842Ssam 	(void) spl0();
51487f7a842Ssam }
51587f7a842Ssam 
lpaiintr(unit)51687f7a842Ssam lpaiintr(unit)
51787f7a842Ssam 	int unit;
51887f7a842Ssam {
51987f7a842Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
52087f7a842Ssam 
52187f7a842Ssam TRACER("{I");
52287f7a842Ssam 	if (sc->sc_flag & SLEEP) {
52387f7a842Ssam TRACER("<WAKEUP>");
52487f7a842Ssam 		wakeup((caddr_t)sc);
52587f7a842Ssam 		sc->sc_flag &= ~SLEEP;
52687f7a842Ssam 	}
52787f7a842Ssam TRACER("}");
52887f7a842Ssam }
52987f7a842Ssam 
lpaointr(unit)53087f7a842Ssam lpaointr(unit)
53187f7a842Ssam 	int unit;
53287f7a842Ssam {
53387f7a842Ssam 	register int c, m;
53487f7a842Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
53587f7a842Ssam 	register struct uba_device *ui = lpadinfo[unit];
53687f7a842Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
53787f7a842Ssam 	int spx;
53887f7a842Ssam 
53987f7a842Ssam TRACER("{O");
54087f7a842Ssam 	if (sc->sc_flag & SLEEP) {
54187f7a842Ssam TRACER("<WAKEUP>");
54287f7a842Ssam 		wakeup(sc);
54387f7a842Ssam 		sc->sc_flag &= ~SLEEP;
54487f7a842Ssam 	}
54587f7a842Ssam 	c = lpaaddr->lcos;
54687f7a842Ssam 	m = lpaaddr->lms;
54787f7a842Ssam 	lpaaddr->lcos &= ~READYO;
54887f7a842Ssam 	if (c & ERROR) {
54987f7a842Ssam TRACER("<ERROR>");
55087f7a842Ssam 		c = (c >> 8) & 0377;
55187f7a842Ssam 		if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) {
55287f7a842Ssam 			printf("LPA ERROR %o %o\n", c, m&0177777);
55387f7a842Ssam 			sc->sc_flag |= ERROR;
55487f7a842Ssam 		}
55587f7a842Ssam 		sc->sc_flag &= ~STOP;
55687f7a842Ssam TRACER("}\n");
55787f7a842Ssam 		return;
55887f7a842Ssam 	}
55987f7a842Ssam TRACERN("<LPA %d>", sc->sc_lbufnx);
56087f7a842Ssam 	sc->sc_lbufn = sc->sc_lbufnx;
56187f7a842Ssam 	if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) {
56287f7a842Ssam TRACER("<STOP?>");
56387f7a842Ssam 		if (sc->sc_flag & STOP)
56487f7a842Ssam 			return;
56587f7a842Ssam 		printf("LPA OVERRUN\n");
56687f7a842Ssam 		sc->sc_flag |= ERROR;
56787f7a842Ssam 	}
56887f7a842Ssam 	inc(sc_lbufnx);
56987f7a842Ssam TRACERN("<USTAT %o>", sc->sc_ustat);
570395e3743Skarels 	spx = splhigh();
57187f7a842Ssam 	sc->sc_ustat &= ~NBI;
57287f7a842Ssam 	sc->sc_ustat |= sc->sc_lbufnx << 8;
57387f7a842Ssam 	sc->sc_ustat &= ~DONE;
574395e3743Skarels 	splx(spx);
57587f7a842Ssam TRACERN("<LPAN %d>}", sc->sc_lbufnx);
57687f7a842Ssam }
57787f7a842Ssam 
lpareset(uban)57887f7a842Ssam lpareset(uban)
57987f7a842Ssam 	int uban;
58087f7a842Ssam {
58187f7a842Ssam 	register struct uba_device *ui;
58287f7a842Ssam 	register struct lpadevice *lpaaddr;
58387f7a842Ssam 	register struct lpa_softc *sc;
58487f7a842Ssam 	register int unit;
58587f7a842Ssam 
58687f7a842Ssam TRACER("LPA RESET\n");
58787f7a842Ssam 	for (unit = 0; unit < NLPA; unit++) {
58887f7a842Ssam 		if ((ui = lpadinfo[unit]) == 0 ||
589d672d181Sroot 		    ui->ui_ubanum != uban || ui->ui_alive == 0)
59087f7a842Ssam 			continue;
59187f7a842Ssam 		printf(" lpa%d", unit);
59287f7a842Ssam 		lpaaddr = (struct lpadevice *)ui->ui_addr;
59387f7a842Ssam 		sc = &lpa_softc[unit];
59487f7a842Ssam 		sc->sc_flag |= ERROR;
595395e3743Skarels 		(void) splhigh();
59687f7a842Ssam 		lpaaddr->lcim = RESET;
59787f7a842Ssam 		lpaaddr->lcim = 0;
59887f7a842Ssam 		(void) spl0();
59987f7a842Ssam 		if (sc->sc_flag & SLEEP) {
60087f7a842Ssam 			wakeup((caddr_t)sc);
60187f7a842Ssam 			sc->sc_flag &= ~SLEEP;
60287f7a842Ssam 		}
60387f7a842Ssam 	}
60487f7a842Ssam }
60587f7a842Ssam #endif NLPA
606