xref: /csrg-svn/sys/vax/uba/lpa.c (revision 6968)
1*6968Ssam /*	lpa.c	4.1	82/05/27	*/
2*6968Ssam #include "lpa.h"
3*6968Ssam #if NLPA > 0
4*6968Ssam 
5*6968Ssam #include "../h/param.h"
6*6968Ssam #include "../h/dir.h"
7*6968Ssam #include "../h/user.h"
8*6968Ssam #include "../h/buf.h"
9*6968Ssam #include "../h/ubavar.h"
10*6968Ssam #include "../h/proc.h"
11*6968Ssam #include "../h/ioctl.h"
12*6968Ssam 
13*6968Ssam /*
14*6968Ssam  *	LPA driver for 4.1BSD
15*6968Ssam  *	Asa Romberger
16*6968Ssam  * method of usage:
17*6968Ssam  *	open
18*6968Ssam  *	write microcode
19*6968Ssam  *	write dedicated mode dispatch table
20*6968Ssam  *	ioctl TIOCSETP to set parameters
21*6968Ssam  *		struct iocb {
22*6968Ssam  *			short *baddr;	buffer address
23*6968Ssam  *			short rate;	- 1,000,000 / frequency in Hz
24*6968Ssam  *			short wc;	15-13 = number of buffers - 1
25*6968Ssam  *					12-0 = buffer size in words
26*6968Ssam  *		} iocb;
27*6968Ssam  *	read - 1 character indicating buffer index
28*6968Ssam  *		fill or empty buffer
29*6968Ssam  * minor device number = DDCCCCCC where:
30*6968Ssam  *	DD	= 00 for analog input
31*6968Ssam  *		= 01 for analog output
32*6968Ssam  *	CCCCCC	= channel number
33*6968Ssam  */
34*6968Ssam /*
35*6968Ssam  *	define TRACELPA to get trace printouts on the console
36*6968Ssam  *	define NOMCODE to eliminate the microcode download check
37*6968Ssam  */
38*6968Ssam /*	#define	NOMCODE		*/
39*6968Ssam 
40*6968Ssam #ifdef TRACELPA
41*6968Ssam #	define TRACER(x)	printf(x)
42*6968Ssam #	define TRACERN(x, d)	printf(x, d)
43*6968Ssam #else
44*6968Ssam #	define TRACER(x)
45*6968Ssam #	define TRACERN(x, d)
46*6968Ssam #endif
47*6968Ssam 
48*6968Ssam 	/* PRIORITY AT WHICH PROGRAM SHOULD RUN */
49*6968Ssam 	/* THIS SHOULD EVENTUALLY  TELL UNIX THIS IS A REAL-TIME DEVICE */
50*6968Ssam 
51*6968Ssam #define NICE	0
52*6968Ssam 
53*6968Ssam 	/* WAKEUP PRIORITY */
54*6968Ssam 
55*6968Ssam #define LPAPRI	(PZERO + 0)
56*6968Ssam 
57*6968Ssam 	/* MACRO DEFINITIONS */
58*6968Ssam #define inc(v)	(sc->v = ((sc->v + 1) % sc->sc_nbuf))
59*6968Ssam #define LPAUNIT(dev)	0
60*6968Ssam #define LPADEVICE(dev)	(((dev) >> 6) & 03)
61*6968Ssam #define LPACHANNEL(dev)	((dev) & 077)
62*6968Ssam 
63*6968Ssam 	/* DEFINITIONS FOR INTERACTION WITH UNIX I/O */
64*6968Ssam 
65*6968Ssam int lpaprobe(), /*lpaslave(),*/ lpaattach() /*,lpadgo()*/;
66*6968Ssam int lpaiintr(), lpaointr();
67*6968Ssam u_short lpastd[] = {0170460, 0};
68*6968Ssam struct uba_device *lpadinfo[NLPA];
69*6968Ssam /*struct uba_ctlr *lpaminfo[Ndevice name];*/
70*6968Ssam struct uba_driver lpadriver =
71*6968Ssam 	{lpaprobe, 0/*lpaslave*/, lpaattach, 0/*lpadgo*/, lpastd,
72*6968Ssam 	"lpa", lpadinfo, 0/*"device name"*/, 0/*lpaminfo*/, 0/*exclusive use*/};
73*6968Ssam 
74*6968Ssam 
75*6968Ssam 	/* LPA SOFTWARE OPERATION FLAGS */
76*6968Ssam 
77*6968Ssam struct lpa_softc {
78*6968Ssam 	int	sc_flag;	/* flags, as defined below */
79*6968Ssam 	int	sc_device;	/* device: 0 = analog in, 1 = analog out */
80*6968Ssam 	int	sc_channel;	/* device channel number */
81*6968Ssam 	struct buf sc_ubuffer;	/* user buffer header */
82*6968Ssam 	int	sc_ubabuf;	/* uba allocation pointer for buffer */
83*6968Ssam 	int	sc_ubufn;	/* present buffer that user is accessing */
84*6968Ssam 	int	sc_lbufn;	/* present buffer that lpa is accessing */
85*6968Ssam 	int	sc_lbufnx;	/* next buffer for lpa (value in ustat) */
86*6968Ssam 	int	sc_nbuf;	/* number of buffers */
87*6968Ssam 	int	sc_count;	/* buffer size in words */
88*6968Ssam 	short	sc_ustat;	/* user status word */
89*6968Ssam 	struct buf sc_ustatbuf;	/* dummy user status word buffer for ubasetup */
90*6968Ssam 	int	sc_ubaustat;	/* uba allocation pointer for ustat */
91*6968Ssam 	struct buf *sc_buffer;	/* scratch buffer header */
92*6968Ssam 	int	sc_start;	/* 0 if lpa operation has been started */
93*6968Ssam } lpa_softc[NLPA];
94*6968Ssam     /* flag bits */
95*6968Ssam #define OPEN	01		/* device is open */
96*6968Ssam #define MCODE	02		/* microcode has been loaded */
97*6968Ssam #define DMDT	04		/* dedicated mode dispatch table loaded */
98*6968Ssam #define STTY	010		/* stty call and device initialized */
99*6968Ssam #define SLEEP	020		/* sleeping */
100*6968Ssam     /* ustat bits */
101*6968Ssam #define DONE	0100000		/* done */
102*6968Ssam #define STOP	0040000		/* stop data transfer */
103*6968Ssam #define NBI	0003400		/* next buffer index */
104*6968Ssam #define LBI	0000003		/* last buffer index */
105*6968Ssam 
106*6968Ssam 	/* DEVICE REGISTER DESCRIPTION AREA */
107*6968Ssam 
108*6968Ssam struct lpadevice {
109*6968Ssam 	short	lcim;		/* control in and maintenance */
110*6968Ssam 	short	lcos;		/* control and status out */
111*6968Ssam 	short	lrda;		/* request description array address word */
112*6968Ssam 	short	lms;		/* maintenance status */
113*6968Ssam };
114*6968Ssam     /* control in and maintenance register bits */
115*6968Ssam #define	READYI	0000200		/* ready in */
116*6968Ssam #define IIE	0000100		/* in interrupt enable */
117*6968Ssam #define RDAEXT	0000014		/* rda address extension */
118*6968Ssam #define RDAEXTOFFSET	2	/* offset of RDAEXT from right side */
119*6968Ssam #define GO	0000001		/* go */
120*6968Ssam #define RUN	0100000		/* run */
121*6968Ssam #define RESET	0040000		/* reset */
122*6968Ssam #define CWRITE	0020000		/* cram write */
123*6968Ssam #define EA	0004000		/* enable arbitration */
124*6968Ssam #define ROMO	0002000		/* rom O */
125*6968Ssam #define ROMI	0001000		/* rom I */
126*6968Ssam #define SMICRO	0000400		/* step microprocessor */
127*6968Ssam     /* control and status out register bits */
128*6968Ssam #define READYO	0200		/* ready out */
129*6968Ssam #define OIE	0100		/* out interrupt enable */
130*6968Ssam #define UINDEX	0007		/* user index */
131*6968Ssam #define ERROR	0100000		/* error */
132*6968Ssam #define ESTAT	0060000		/* error status */
133*6968Ssam #define ESCODE	0017400		/* error sub code */
134*6968Ssam #define ECODE	0077400		/* error status + error sub code */
135*6968Ssam #define OVERRUN	0243		/* overrun error */
136*6968Ssam 
137*6968Ssam 	/* LPA COMMAND DESCRIPTION AREA */
138*6968Ssam 
139*6968Ssam 	/* INIT COMMAND */
140*6968Ssam #define INIT	0		/* mode */
141*6968Ssam #define MCVERS	4		/* microcode version */
142*6968Ssam #define ACLOCKA	0170404		/* LPA bus addresses */
143*6968Ssam #define ACLOCKB	0170432
144*6968Ssam #define AAD1	0170400
145*6968Ssam #define AAD2	1		/* 0170440 - DOES NOT EXIST */
146*6968Ssam #define ADA	0170420
147*6968Ssam #define ADIO1	1		/* 0167770 - DOES NOT EXIST */
148*6968Ssam #define ADIO2	1		/* 0167760 - DOES NOT EXIST */
149*6968Ssam #define ADIO3	1		/* 0167750 - DOES NOT EXIST */
150*6968Ssam #define ADIO4	1		/* 0167740 - DOES NOT EXIST */
151*6968Ssam #define ADIO5	1		/* 0167730 - DOES NOT EXIST */
152*6968Ssam 	/* CLOCK START COMMAND */
153*6968Ssam #define CLOCK	1		/* mode */
154*6968Ssam #define CLOCKA	0<<4		/* clock A */
155*6968Ssam 		/* clock status word */
156*6968Ssam #define ENACTR	1		/* enable counter */
157*6968Ssam #define R1M	1<<1		/* 1 MHz rate */
158*6968Ssam #define R100K	2<<1		/* 100 KHz rate */
159*6968Ssam #define R10K	3<<1		/* 10 KHz rate */
160*6968Ssam #define R1K	4<<1		/* 1 KHz rate */
161*6968Ssam #define R100	5<<1		/* 100 Hz rate */
162*6968Ssam #define REXT	6<<1		/* external rate (from st1 input) */
163*6968Ssam #define R60	7<<1		/* line frequency rate */
164*6968Ssam #define MFIE	0100		/* mode flag interrupt enable */
165*6968Ssam #define MSI	0<<8		/* single interval mode */
166*6968Ssam #define MRI	1<<8		/* repeat interval mode */
167*6968Ssam #define MEET	2<<8		/* external event time mode */
168*6968Ssam #define MEETZ	3<<8		/* external event time mode from zero base */
169*6968Ssam #define ST1EC	020000		/* st1 enable counter */
170*6968Ssam #define ST1IE	040000		/* st1 interrupt enable */
171*6968Ssam 	/* DATA TRANSFER START COMMAND */
172*6968Ssam #define DTS	2		/* mode */
173*6968Ssam #define SCHAN	1<<8		/* single channel */
174*6968Ssam 
175*6968Ssam 	/* THE ROUTINES THEMSELVES */
176*6968Ssam 
177*6968Ssam /*
178*6968Ssam  *	probe lpa to get br level and interrupt vector
179*6968Ssam  */
180*6968Ssam lpaprobe(reg)
181*6968Ssam caddr_t reg;
182*6968Ssam {
183*6968Ssam 	register int br, cvec;	/* value result (required for UNIX) */
184*6968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) reg;
185*6968Ssam 
186*6968Ssam #ifdef lint
187*6968Ssam 	br = 0; cvec = br; br = cvec;
188*6968Ssam #endif
189*6968Ssam 	/* this should force an interrupt, stall, clear the lpa */
190*6968Ssam 	br = 0x15;
191*6968Ssam 	cvec = 0330;
192*6968Ssam TRACER("PROBE\n");
193*6968Ssam 	return (1);
194*6968Ssam }
195*6968Ssam 
196*6968Ssam /*
197*6968Ssam  *	attach the specified controller
198*6968Ssam  */
199*6968Ssam lpaattach(ui)
200*6968Ssam register struct upa_device *ui;
201*6968Ssam {
202*6968Ssam 	/* any stuff necessary for initialization can go here */
203*6968Ssam }
204*6968Ssam 
205*6968Ssam /*
206*6968Ssam  *	open the device
207*6968Ssam  */
208*6968Ssam lpaopen(dev, flag)
209*6968Ssam dev_t dev;
210*6968Ssam int flag;
211*6968Ssam {
212*6968Ssam 	register int unit = LPAUNIT(dev);
213*6968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
214*6968Ssam 	register struct uba_device *ui = lpadinfo[unit];
215*6968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
216*6968Ssam 
217*6968Ssam TRACER("OPEN\n");
218*6968Ssam 	if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 ||
219*6968Ssam 	    ui->ui_alive == 0) {
220*6968Ssam 		u.u_error = ENXIO;
221*6968Ssam 		return;
222*6968Ssam 	}
223*6968Ssam 	(void) spl7();
224*6968Ssam 	lpaaddr->lcim = RESET;
225*6968Ssam 	lpaaddr->lcim = 0;
226*6968Ssam 	(void) spl0();
227*6968Ssam 	lpaaddr->lcos = 0;	/* clear the registers as a precaution */
228*6968Ssam 	lpaaddr->lrda = 0;
229*6968Ssam 	lpaaddr->lms = 0;
230*6968Ssam 	sc->sc_flag = OPEN;
231*6968Ssam 	sc->sc_device = LPADEVICE(dev);
232*6968Ssam 	sc->sc_channel = LPACHANNEL(dev);
233*6968Ssam 	sc->sc_buffer = geteblk();
234*6968Ssam 	sc->sc_buffer->b_error = 0;
235*6968Ssam 	sc->sc_buffer->b_proc = u.u_procp;
236*6968Ssam 	sc->sc_ubufn = -1;
237*6968Ssam 	/* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */
238*6968Ssam 	u.u_procp->p_nice = NICE;
239*6968Ssam }
240*6968Ssam 
241*6968Ssam /*
242*6968Ssam  *	close the device
243*6968Ssam  */
244*6968Ssam lpaclose(dev, flag)
245*6968Ssam dev_t dev;
246*6968Ssam int flag;
247*6968Ssam {
248*6968Ssam 	register int unit = LPAUNIT(dev);
249*6968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
250*6968Ssam 	register struct uba_device *ui = lpadinfo[unit];
251*6968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
252*6968Ssam 
253*6968Ssam 	if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) {
254*6968Ssam 		if (sc->sc_start)
255*6968Ssam 			lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
256*6968Ssam 		sc->sc_flag |= STOP;
257*6968Ssam 		(void) spl5();
258*6968Ssam 		while (sc->sc_flag & STOP) {
259*6968Ssam TRACER("SLEEP\n");
260*6968Ssam 			sc->sc_flag |= SLEEP;
261*6968Ssam 			sleep((caddr_t)sc, LPAPRI);
262*6968Ssam 		}
263*6968Ssam 	}
264*6968Ssam 	(void) spl7();
265*6968Ssam 	lpaaddr->lcim = RESET;
266*6968Ssam 	lpaaddr->lcim = 0;
267*6968Ssam 	(void) spl0();
268*6968Ssam 	if (sc->sc_ubabuf) {
269*6968Ssam 		ubarelse(ui->ui_ubanum, &sc->sc_ubabuf);
270*6968Ssam 		sc->sc_ubabuf = 0;
271*6968Ssam 		(void) spl6();
272*6968Ssam 		vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount,
273*6968Ssam 			(sc->sc_device)? B_READ : B_WRITE);
274*6968Ssam 		u.u_procp->p_flag &= ~SPHYSIO;
275*6968Ssam 		(void) spl0();
276*6968Ssam 	}
277*6968Ssam 	if (sc->sc_ubaustat) {
278*6968Ssam 		ubarelse(ui->ui_ubanum, &sc->sc_ubaustat);
279*6968Ssam 		sc->sc_ubaustat = 0;
280*6968Ssam 	}
281*6968Ssam 	if (sc->sc_buffer) {
282*6968Ssam 		brelse(sc->sc_buffer);
283*6968Ssam 		sc->sc_buffer = 0;
284*6968Ssam 	}
285*6968Ssam 	sc->sc_flag = 0;
286*6968Ssam TRACER("CLOSE\n");
287*6968Ssam }
288*6968Ssam 
289*6968Ssam /*
290*6968Ssam  *	write
291*6968Ssam  *		first write is the microcode
292*6968Ssam  *		second write is the dispatch table
293*6968Ssam  */
294*6968Ssam lpawrite(dev)
295*6968Ssam dev_t dev;
296*6968Ssam {
297*6968Ssam 	register int unit = LPAUNIT(dev);
298*6968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
299*6968Ssam 	register struct uba_device *ui = lpadinfo[unit];
300*6968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
301*6968Ssam 	register int f;
302*6968Ssam 
303*6968Ssam TRACER("WRITE\n");
304*6968Ssam 	f = sc->sc_flag;
305*6968Ssam 	if ((f & OPEN) == 0) {
306*6968Ssam 		u.u_error = ENXIO;
307*6968Ssam 		return;
308*6968Ssam 	}
309*6968Ssam 	if ((f & MCODE) == 0) {
310*6968Ssam 		lpamcode(lpaaddr, sc);
311*6968Ssam 		return;
312*6968Ssam 	}
313*6968Ssam 	if ((f & DMDT) == 0) {
314*6968Ssam 		lpadmdt(lpaaddr, sc, ui->ui_ubanum);
315*6968Ssam 		return;
316*6968Ssam 	}
317*6968Ssam 	/* writes are only for microcode and dedicated mode dispatch table */
318*6968Ssam 	u.u_error = ENXIO;
319*6968Ssam }
320*6968Ssam 
321*6968Ssam lpamcode(lpaaddr, sc)
322*6968Ssam register struct lpadevice *lpaaddr;
323*6968Ssam register struct lpa_softc *sc;
324*6968Ssam {
325*6968Ssam 	short v, r;
326*6968Ssam 	register int mcaddr;
327*6968Ssam 
328*6968Ssam 	mcaddr = 0;
329*6968Ssam 	while (u.u_count) {
330*6968Ssam 		iomove(&v, 2, B_WRITE);		/* get next microcode word */
331*6968Ssam 		lpaaddr->lcim = 0;		/* load microcode word */
332*6968Ssam 		lpaaddr->lrda = mcaddr;
333*6968Ssam 		lpaaddr->lms = v;
334*6968Ssam 		lpaaddr->lcim = ROMO;
335*6968Ssam 		lpaaddr->lcim |= CWRITE;
336*6968Ssam 		lpaaddr->lcim = 0;		/* verify microcode word */
337*6968Ssam 		lpaaddr->lrda = mcaddr;
338*6968Ssam 		lpaaddr->lcim = ROMO;
339*6968Ssam 		if ((r = lpaaddr->lms) != v) {
340*6968Ssam 			/* download failure */
341*6968Ssam 			printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r);
342*6968Ssam 			u.u_error = ENXIO;
343*6968Ssam 			return;
344*6968Ssam 		}
345*6968Ssam 		mcaddr++;
346*6968Ssam 	}
347*6968Ssam 	lpaaddr->lcim = RUN | EA;	/* turn it on */
348*6968Ssam 	sc->sc_flag |= MCODE;
349*6968Ssam 	lpaaddr->lcim |= IIE;
350*6968Ssam 	lpaaddr->lcos |= OIE;
351*6968Ssam TRACER("MCODE\n");
352*6968Ssam }
353*6968Ssam 
354*6968Ssam lpadmdt(lpaaddr, sc, ubanum)
355*6968Ssam register struct lpadevice *lpaaddr;
356*6968Ssam register struct lpa_softc *sc;
357*6968Ssam register short ubanum;
358*6968Ssam {
359*6968Ssam 	register short *p;
360*6968Ssam 	register int n;
361*6968Ssam 
362*6968Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;		/* INIT */
363*6968Ssam 	*p++ = (MCVERS << 8) | INIT;	/* mode */
364*6968Ssam 	*p++ = ACLOCKA;		/* LPA bus device addresses */
365*6968Ssam 	*p++ = ACLOCKB;
366*6968Ssam 	*p++ = AAD1;
367*6968Ssam 	*p++ = AAD2;
368*6968Ssam 	*p++ = ADA;
369*6968Ssam 	*p++ = ADIO1;
370*6968Ssam 	*p++ = ADIO2;
371*6968Ssam 	*p++ = ADIO3;
372*6968Ssam 	*p++ = ADIO4;
373*6968Ssam 	*p++ = ADIO5;
374*6968Ssam 	n = min(u.u_count, 256);	/* dedicated mode dispatch table */
375*6968Ssam 	iomove((char *) p, n, B_WRITE);
376*6968Ssam 	n >>= 1;
377*6968Ssam 	p += n;
378*6968Ssam 	while (n++ < 128)
379*6968Ssam 		*p++ = 0;
380*6968Ssam 	lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum);
381*6968Ssam 	sc->sc_flag |= DMDT;
382*6968Ssam TRACER("DMDT\n");
383*6968Ssam }
384*6968Ssam 
385*6968Ssam lpaioctl(dev, cmd, addr, flag)
386*6968Ssam dev_t dev;
387*6968Ssam caddr_t *addr;
388*6968Ssam {
389*6968Ssam 	register int unit = LPAUNIT(dev);
390*6968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
391*6968Ssam 	register struct uba_device *ui = lpadinfo[unit];
392*6968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
393*6968Ssam 	register short *p;
394*6968Ssam 	register int i;
395*6968Ssam 	register int v;
396*6968Ssam 	struct iocb {
397*6968Ssam 		short *baddr;
398*6968Ssam 		short rate;
399*6968Ssam 		short wc;
400*6968Ssam 	} iocb;
401*6968Ssam 
402*6968Ssam TRACER("IOCTL IN\n");
403*6968Ssam 	if (cmd != TIOCSETP) {
404*6968Ssam TRACER("NOT TIOCSETP\n");
405*6968Ssam 		/* not valid */
406*6968Ssam 		u.u_error = ENXIO;
407*6968Ssam 		return;
408*6968Ssam 	}
409*6968Ssam #ifndef NOMCODE
410*6968Ssam 	if ((sc->sc_flag & DMDT) == 0) {
411*6968Ssam TRACER("NO DMDT\n");
412*6968Ssam 		u.u_error = ENXIO;
413*6968Ssam 		return;
414*6968Ssam 	}
415*6968Ssam #endif
416*6968Ssam 	if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
417*6968Ssam TRACER("COPYIN FAULT\n");
418*6968Ssam 		u.u_error = EFAULT;
419*6968Ssam 		return;
420*6968Ssam 	}
421*6968Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;	/* CLOCK START */
422*6968Ssam 	*p++ = CLOCK | CLOCKA;			/* mode */
423*6968Ssam 	*p++ = ENACTR | R1M | MFIE | MRI;	/* clock status */
424*6968Ssam 	*p = iocb.rate;				/* clock preset */
425*6968Ssam 	lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
426*6968Ssam TRACER("CLOCK STARTED\n");
427*6968Ssam 	p = (short *) sc->sc_buffer->b_un.b_addr;	/* DATA TRANSFER START*/
428*6968Ssam 	*p++ = (sc->sc_device << 7) | DTS | SCHAN;	/* mode */
429*6968Ssam 	sc->sc_count = iocb.wc & 017777;	/* word count per buffer */
430*6968Ssam 	*p++ = sc->sc_count;
431*6968Ssam 							/* user status word */
432*6968Ssam 	sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat;
433*6968Ssam 	sc->sc_ustatbuf.b_flags = 0;
434*6968Ssam 	sc->sc_ustatbuf.b_bcount = 2;
435*6968Ssam 	sc->sc_ustatbuf.b_proc = u.u_procp;
436*6968Ssam 	sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0);
437*6968Ssam 	v = sc->sc_ubaustat;
438*6968Ssam 	*p++ = v;
439*6968Ssam 	*p = (v >> 16) & 03;		/* into low portion of word */
440*6968Ssam 	sc->sc_nbuf = (iocb.wc >> 13) & 07;	/* number of buffers */
441*6968Ssam 	*p++ |= sc->sc_nbuf++ << 8;		/* into high portion of word */
442*6968Ssam 					/* buffer addresses */
443*6968Ssam 	if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb.baddr,
444*6968Ssam 		    sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2,
445*6968Ssam 		    (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) {
446*6968Ssam TRACER("USER BUFFER FAULT\n");
447*6968Ssam 			u.u_error = EFAULT;
448*6968Ssam 			return;
449*6968Ssam 	}
450*6968Ssam 	sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i;
451*6968Ssam 	sc->sc_ubuffer.b_proc = u.u_procp;
452*6968Ssam 	u.u_procp->p_flag |= SPHYSIO;
453*6968Ssam 	vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount);
454*6968Ssam /*	sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, UBA_NEEDBDP);*/
455*6968Ssam 	sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0);
456*6968Ssam 	v = sc->sc_ubabuf;
457*6968Ssam 	for (i = 0; i < sc->sc_nbuf; i++) {
458*6968Ssam 		*p++ = v;
459*6968Ssam 		*p++ = (v >> 16) & 03;
460*6968Ssam 		v += sc->sc_count * 2;
461*6968Ssam 	}
462*6968Ssam 	for ( ; i <= 7; i++) {
463*6968Ssam 		*p++ = 0;
464*6968Ssam 		*p++ = 0;
465*6968Ssam 	}
466*6968Ssam 	*p++ = 0; *p++ = 0;		/* random channel list address */
467*6968Ssam 	*p++ = 0;			/* delay */
468*6968Ssam 	*p++ = sc->sc_channel;		/* start channel, channel inc */
469*6968Ssam 	*p++ = 1;			/* number of samples in a sequence */
470*6968Ssam 	*p++ = 0;			/* dwell */
471*6968Ssam 	*p++ = 0;			/* start word no., event mark word */
472*6968Ssam 	*p++ = 0;			/* start word mask */
473*6968Ssam 	*p = 0;				/* event mark mask */
474*6968Ssam 	sc->sc_ustat = 0;
475*6968Ssam 	sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1;
476*6968Ssam 	sc->sc_lbufn = 0;
477*6968Ssam 	sc->sc_lbufnx = 0;
478*6968Ssam 	sc->sc_flag |= STTY;
479*6968Ssam TRACER("IOCTL OUT\n");
480*6968Ssam }
481*6968Ssam 
482*6968Ssam /*
483*6968Ssam  *	read
484*6968Ssam  *		read 1 character only - the next available buffer number
485*6968Ssam  */
486*6968Ssam lparead(dev)
487*6968Ssam dev_t dev;
488*6968Ssam {
489*6968Ssam 	register int unit = LPAUNIT(dev);
490*6968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
491*6968Ssam 	register struct uba_device *ui = lpadinfo[unit];
492*6968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
493*6968Ssam 
494*6968Ssam TRACER("READ\n");
495*6968Ssam 	if ((sc->sc_flag & STTY) == 0) {
496*6968Ssam 		u.u_error = ENXIO;
497*6968Ssam 		return;
498*6968Ssam 	}
499*6968Ssam 	if (sc->sc_flag & ERROR) {
500*6968Ssam 		u.u_error = ENXIO;
501*6968Ssam 		return;
502*6968Ssam 	}
503*6968Ssam 	if (sc->sc_start)
504*6968Ssam 		if (--sc->sc_start == 0) {
505*6968Ssam 			lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
506*6968Ssam TRACER("START\n");
507*6968Ssam 		}
508*6968Ssam 	inc(sc_ubufn);
509*6968Ssam 	if (sc->sc_start == 0) {
510*6968Ssam 		(void) spl5();
511*6968Ssam 		while (sc->sc_ubufn == sc->sc_lbufn) {
512*6968Ssam 			if (sc->sc_flag & ERROR) {
513*6968Ssam 				u.u_error = ENXIO;
514*6968Ssam 				return;
515*6968Ssam 			}
516*6968Ssam TRACER("SLEEP\n");
517*6968Ssam 			sc->sc_flag |= SLEEP;
518*6968Ssam 			sleep(sc, LPAPRI);
519*6968Ssam 		}
520*6968Ssam 		(void) spl0();
521*6968Ssam 	}
522*6968Ssam TRACERN("READ %d\n", sc->sc_ubufn);
523*6968Ssam 	iomove(&sc->sc_ubufn, 1, B_READ);
524*6968Ssam }
525*6968Ssam 
526*6968Ssam /*
527*6968Ssam  *	execute a command and wait for completion
528*6968Ssam  */
529*6968Ssam lpacmd(bp, lpaaddr, sc, ubanum)
530*6968Ssam register struct buf *bp;
531*6968Ssam register struct lpadevice *lpaaddr;
532*6968Ssam register struct lpa_softc *sc;
533*6968Ssam register short ubanum;
534*6968Ssam {
535*6968Ssam 	int ubareg;
536*6968Ssam 
537*6968Ssam TRACER("CMD\n");
538*6968Ssam /*	bp->b_flags |= B_BUSY|B_WRITE;		*/
539*6968Ssam 	ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP);
540*6968Ssam 	lpawait(lpaaddr, sc);
541*6968Ssam 	lpaaddr->lrda = ubareg;
542*6968Ssam 	lpaaddr->lcim &= ~RDAEXT;
543*6968Ssam 	lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO;
544*6968Ssam 	lpawait(lpaaddr, sc);
545*6968Ssam 	ubarelse(ubanum, &ubareg);
546*6968Ssam /*	bp->b_flags &= ~(B_BUSY|B_WRITE);		*/
547*6968Ssam }
548*6968Ssam 
549*6968Ssam /*
550*6968Ssam  *	wait for completion (ready input)
551*6968Ssam  */
552*6968Ssam lpawait(lpaaddr, sc)
553*6968Ssam register struct lpadevice *lpaaddr;
554*6968Ssam register struct lpa_softc *sc;
555*6968Ssam {
556*6968Ssam 	(void) spl5();
557*6968Ssam 	while ((lpaaddr->lcim & READYI) == 0) {
558*6968Ssam TRACER("SLEEP\n");
559*6968Ssam 		sc->sc_flag |= SLEEP;
560*6968Ssam 		sleep((caddr_t)sc, LPAPRI);
561*6968Ssam 	}
562*6968Ssam 	(void) spl0();
563*6968Ssam }
564*6968Ssam 
565*6968Ssam /*
566*6968Ssam  *	lpaiintr
567*6968Ssam  *		in interrupt
568*6968Ssam  *		LPA is now ready to accept a user request
569*6968Ssam  */
570*6968Ssam lpaiintr(unit)
571*6968Ssam int unit;
572*6968Ssam {
573*6968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
574*6968Ssam 
575*6968Ssam TRACER("{I");
576*6968Ssam 	if (sc->sc_flag & SLEEP) {
577*6968Ssam TRACER("<WAKEUP>");
578*6968Ssam 		wakeup((caddr_t)sc);
579*6968Ssam 		sc->sc_flag &= ~SLEEP;
580*6968Ssam 	}
581*6968Ssam TRACER("}");
582*6968Ssam }
583*6968Ssam 
584*6968Ssam /*
585*6968Ssam  *	lpaointr
586*6968Ssam  *		out interrupt
587*6968Ssam  *		LPA has status information
588*6968Ssam  */
589*6968Ssam lpaointr(unit)
590*6968Ssam int unit;
591*6968Ssam {
592*6968Ssam 	register int c, m;
593*6968Ssam 	register struct lpa_softc *sc = &lpa_softc[unit];
594*6968Ssam 	register struct uba_device *ui = lpadinfo[unit];
595*6968Ssam 	register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
596*6968Ssam 	int spx;
597*6968Ssam 
598*6968Ssam TRACER("{O");
599*6968Ssam 	if (sc->sc_flag & SLEEP) {
600*6968Ssam TRACER("<WAKEUP>");
601*6968Ssam 		wakeup(sc);
602*6968Ssam 		sc->sc_flag &= ~SLEEP;
603*6968Ssam 	}
604*6968Ssam 	c = lpaaddr->lcos;
605*6968Ssam 	m = lpaaddr->lms;
606*6968Ssam 	lpaaddr->lcos &= ~READYO;
607*6968Ssam 	if (c & ERROR) {
608*6968Ssam TRACER("<ERROR>");
609*6968Ssam 		c = (c >> 8) & 0377;
610*6968Ssam 		if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) {
611*6968Ssam 			printf("LPA ERROR %o %o\n", c, m&0177777);
612*6968Ssam 			sc->sc_flag |= ERROR;
613*6968Ssam 		}
614*6968Ssam 		sc->sc_flag &= ~STOP;
615*6968Ssam TRACER("}\n");
616*6968Ssam 		return;
617*6968Ssam 	}
618*6968Ssam TRACERN("<LPA %d>", sc->sc_lbufnx);
619*6968Ssam 	sc->sc_lbufn = sc->sc_lbufnx;
620*6968Ssam 	if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) {
621*6968Ssam TRACER("<STOP?>");
622*6968Ssam 		if (sc->sc_flag & STOP)
623*6968Ssam 			return;
624*6968Ssam 		printf("LPA OVERRUN\n");
625*6968Ssam 		sc->sc_flag |= ERROR;
626*6968Ssam 	}
627*6968Ssam 	inc(sc_lbufnx);
628*6968Ssam TRACERN("<USTAT %o>", sc->sc_ustat);
629*6968Ssam 	spx = spl7();
630*6968Ssam 	sc->sc_ustat &= ~NBI;
631*6968Ssam 	sc->sc_ustat |= sc->sc_lbufnx << 8;
632*6968Ssam 	sc->sc_ustat &= ~DONE;
633*6968Ssam 	(void) splx(spx);
634*6968Ssam TRACERN("<LPAN %d>}", sc->sc_lbufnx);
635*6968Ssam }
636*6968Ssam 
637*6968Ssam /*
638*6968Ssam  *	reset called for a unibus reset
639*6968Ssam  */
640*6968Ssam lpareset(uban)
641*6968Ssam int uban;
642*6968Ssam {
643*6968Ssam 	register struct uba_device *ui;
644*6968Ssam 	register struct lpadevice *lpaaddr;
645*6968Ssam 	register struct lpa_softc *sc;
646*6968Ssam 	register int unit;
647*6968Ssam 
648*6968Ssam TRACER("LPA RESET\n");
649*6968Ssam 	for (unit = 0; unit < NLPA; unit++) {
650*6968Ssam 		if (	(ui = lpadinfo[unit]) == 0 ||
651*6968Ssam 			ui->ui_ubanum != uban ||
652*6968Ssam 			ui->ui_alive == 0)
653*6968Ssam 				continue;
654*6968Ssam 		printf(" lpa%d", unit);
655*6968Ssam 		lpaaddr = (struct lpadevice *)ui->ui_addr;
656*6968Ssam 		sc = &lpa_softc[unit];
657*6968Ssam 		sc->sc_flag |= ERROR;
658*6968Ssam 		(void) spl7();
659*6968Ssam 		lpaaddr->lcim = RESET;
660*6968Ssam 		lpaaddr->lcim = 0;
661*6968Ssam 		(void) spl0();
662*6968Ssam 		if (sc->sc_flag & SLEEP) {
663*6968Ssam 			wakeup((caddr_t)sc);
664*6968Ssam 			sc->sc_flag &= ~SLEEP;
665*6968Ssam 		}
666*6968Ssam 	}
667*6968Ssam }
668*6968Ssam #endif NLPA
669