xref: /csrg-svn/sys/vax/uba/vs.c (revision 24495)
1*24495Sjg /* @(#)vs.c	1.1 (MIT) 08/30/85 */
2*24495Sjg  /****************************************************************************
3*24495Sjg  *									    *
4*24495Sjg  *  Copyright (c) 1983, 1984 by						    *
5*24495Sjg  *  DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts.		    *
6*24495Sjg  *  All rights reserved.						    *
7*24495Sjg  * 									    *
8*24495Sjg  *  This software is furnished on an as-is basis and may be used and copied *
9*24495Sjg  *  only with inclusion of the above copyright notice. This software or any *
10*24495Sjg  *  other copies thereof may be provided or otherwise made available to     *
11*24495Sjg  *  others only for non-commercial purposes.  No title to or ownership of   *
12*24495Sjg  *  the software is hereby transferred.					    *
13*24495Sjg  * 									    *
14*24495Sjg  *  The information in this software is  subject to change without notice   *
15*24495Sjg  *  and  should  not  be  construed as  a commitment by DIGITAL EQUIPMENT   *
16*24495Sjg  *  CORPORATION.							    *
17*24495Sjg  * 									    *
18*24495Sjg  *  DIGITAL assumes no responsibility for the use  or  reliability of its   *
19*24495Sjg  *  software on equipment which is not supplied by DIGITAL.		    *
20*24495Sjg  * 									    *
21*24495Sjg  *									    *
22*24495Sjg  ****************************************************************************/
23*24495Sjg 
24*24495Sjg #include "vs.h"
25*24495Sjg #if NVS > 0
26*24495Sjg 
27*24495Sjg #include "../machine/pte.h"
28*24495Sjg 
29*24495Sjg #include "param.h"
30*24495Sjg #include "dir.h"
31*24495Sjg #include "user.h"
32*24495Sjg #include "buf.h"
33*24495Sjg #include "systm.h"
34*24495Sjg #include "map.h"
35*24495Sjg #include "kernel.h"
36*24495Sjg #include "ioctl.h"
37*24495Sjg 
38*24495Sjg #include "vsio.h"
39*24495Sjg 
40*24495Sjg #include "proc.h"
41*24495Sjg #include "uio.h"
42*24495Sjg #include "vmmac.h"
43*24495Sjg #include "file.h"
44*24495Sjg 
45*24495Sjg #include "ubareg.h"
46*24495Sjg #include "ubavar.h"
47*24495Sjg #include "vsreg.h"
48*24495Sjg 
49*24495Sjg #include "../vax/mtpr.h"
50*24495Sjg 
51*24495Sjg #define	VSWAITPRI	(PZERO+1)
52*24495Sjg #define	VSMAXEVQ	64	/* must be power of 2 */
53*24495Sjg #define EVROUND(x)	((x) & (VSMAXEVQ - 1))
54*24495Sjg 
55*24495Sjg 
56*24495Sjg #define VSBUFFSIZE	3072
57*24495Sjg struct vsBuffArea {
58*24495Sjg 	vsIoAddr vsioa;
59*24495Sjg 	char	obuff[VSBUFFSIZE];
60*24495Sjg 	vsEvent ibuff[VSMAXEVQ];
61*24495Sjg };
62*24495Sjg struct vsBuffArea vsBuff[NVS];
63*24495Sjg 
64*24495Sjg 
65*24495Sjg int vsprobe(), vsattach();
66*24495Sjg struct uba_device *vsdinfo[NVS];
67*24495Sjg u_short vsstd[] = { 0 };
68*24495Sjg struct uba_driver vsdriver =
69*24495Sjg 	{ vsprobe, 0, vsattach, 0, vsstd, "vs", vsdinfo, 0, 0 };
70*24495Sjg 
71*24495Sjg #define	VSUNIT(dev)	(minor(dev))
72*24495Sjg 
73*24495Sjg struct vs_softc {
74*24495Sjg 	unsigned inited : 1;		/* has this ever been inited? */
75*24495Sjg 	unsigned open : 1;		/* only one open, please */
76*24495Sjg 	unsigned linkAvail : 1;		/* link is up */
77*24495Sjg 	short	pgrp;			/* process group for SIGHUP */
78*24495Sjg 	int	romVersion;		/* rom version */
79*24495Sjg 	struct vs_fparm	offset;		/* address base */
80*24495Sjg 	struct vs_csr	csr;		/* saved csr0 */
81*24495Sjg 	struct vs_intr	irr;		/* saved interrupt reason */
82*24495Sjg 	struct vs_kbd	krr;		/* saved keyboard */
83*24495Sjg 	struct vs_fparm	pr;		/* saved parameter regs */
84*24495Sjg 	struct proc *rsel;		/* process waiting for select */
85*24495Sjg 	struct vs_fparm vs_nextgo;	/* next packet to go */
86*24495Sjg 	short vs_status;		/* status from previous packet */
87*24495Sjg 	vsStats stats;			/* statistics */
88*24495Sjg 	int vsBuff_ubinfo;		/* ubinfo for vsBuff */
89*24495Sjg }vs_softc[NVS];
90*24495Sjg 
91*24495Sjg #define	TRUE	1
92*24495Sjg #define	FALSE	0
93*24495Sjg 
94*24495Sjg #define	printI	if (vsIntrPrintfs)printf
95*24495Sjg #define	printD	if (vsDebugPrintfs)printf
96*24495Sjg #define	printM	if (vsMlpPrintfs) vsMlpPrintfs--,printf
97*24495Sjg int	vsIntrPrintfs = 0;
98*24495Sjg int	vsDebugPrintfs = 0;
99*24495Sjg int	vsMlpPrintfs = 0;
100*24495Sjg 
101*24495Sjg /*
102*24495Sjg  * Tell the system that it's out there, and set up the device's interrupt
103*24495Sjg  * vector. Since we are supporting vs100s and vs125s,
104*24495Sjg  * this is a bit kludgey. The vs100 works much
105*24495Sjg  * as one expects, but the vs125 tries to set all the fiber link
106*24495Sjg  * related bits when you hit VS_IE, ignoring the way the 100 works.
107*24495Sjg  * Also, the vs100 will let you set the interrupt vector, but
108*24495Sjg  * the vs125 ignores this and uses its hard-wired value.
109*24495Sjg  * And there's no sure fire to tell which variant it is.
110*24495Sjg  * Ugh. Ugh. Ugh.
111*24495Sjg  */
112*24495Sjg 
113*24495Sjg vsprobe(reg)
114*24495Sjg caddr_t reg;
115*24495Sjg {
116*24495Sjg 	register int br, cvec;		/* value-result */
117*24495Sjg 	register struct vsdevice *vsaddr = (struct vsdevice *)reg;
118*24495Sjg 
119*24495Sjg #ifdef	lint
120*24495Sjg 	br = 0; cvec = br; br = cvec;
121*24495Sjg 	vsintr(0);
122*24495Sjg #endif
123*24495Sjg 	br = 0x15;
124*24495Sjg 	cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
125*24495Sjg 	/*
126*24495Sjg 	 * uh_lastiv is the last free interrupt vector in the
127*24495Sjg 	 * unibus addapter header (uba_hd).
128*24495Sjg 	 */
129*24495Sjg 
130*24495Sjg 	vsaddr->vs_csr0 = cvec >> 2;	/* Save the vector for use on next device */
131*24495Sjg 	vsaddr->vs_irr = 0;		/* Csr will only be read if irr == 0 */
132*24495Sjg 	vsaddr->vs_irr = 0;		/* Clear interrupt reason register */
133*24495Sjg 	vsaddr->vs_pr1  = 0;		/* Clear function parameter */
134*24495Sjg 	vsaddr->vs_pr2  = 0;		/* Clear function parameter */
135*24495Sjg 	vsaddr->vs_ivr = cvec;		/* set up vector (no-op for vs125) */
136*24495Sjg 
137*24495Sjg 	DELAY(100000);
138*24495Sjg 	if (vsaddr->vs_csr0 & VS_LNK_AVL)
139*24495Sjg 		return(0);	/* light won't go off! */
140*24495Sjg 	vsaddr->vs_csr0 &= ~VS_LNK_TRNS;
141*24495Sjg 	vsaddr->vs_csr0 |= VS_IE;	/* enable interrupts */
142*24495Sjg 	DELAY(200000);
143*24495Sjg 
144*24495Sjg 	return sizeof(struct vsdevice);
145*24495Sjg }
146*24495Sjg 
147*24495Sjg vsattach(uip)
148*24495Sjg struct uba_device *uip;
149*24495Sjg {
150*24495Sjg 	register struct vs_softc *vsp;
151*24495Sjg 	register struct vsdevice *vsaddr;
152*24495Sjg 
153*24495Sjg 	vsp = &vs_softc[VSUNIT(uip->ui_unit)];
154*24495Sjg 	vsp->inited  = FALSE;
155*24495Sjg 	vsp->open = FALSE;
156*24495Sjg 	vsBuff[VSUNIT(uip->ui_unit)].vsioa.mbox.bottom = 0;
157*24495Sjg 	vsp->linkAvail = FALSE;
158*24495Sjg 	vsp->romVersion = 0;
159*24495Sjg 	vsp->vs_nextgo.fparm_all = NULL;
160*24495Sjg 
161*24495Sjg 	vsaddr = (struct vsdevice *) uip->ui_addr;
162*24495Sjg 	vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);
163*24495Sjg }
164*24495Sjg 
165*24495Sjg vsopen(dev, flag)
166*24495Sjg dev_t dev;
167*24495Sjg int flag;
168*24495Sjg {
169*24495Sjg 	register struct vs_softc *vsp;
170*24495Sjg 	register struct uba_device *uip;
171*24495Sjg 	register struct vsdevice *vsaddr;
172*24495Sjg 	int s;
173*24495Sjg 	int ret;
174*24495Sjg 	struct buf vsbuf;
175*24495Sjg 	struct vsBuffArea *vsb;
176*24495Sjg 	caddr_t vsBuffpage;
177*24495Sjg 	int vsBuffnpages;
178*24495Sjg 
179*24495Sjg 	if (VSUNIT(dev) >= NVS || (vsp = &vs_softc[VSUNIT(dev)])->open ||
180*24495Sjg 	    (uip = vsdinfo[VSUNIT(dev)]) == 0 || uip->ui_alive == 0)
181*24495Sjg 		return (ENXIO);
182*24495Sjg 
183*24495Sjg 	vsaddr = (struct vsdevice *) uip->ui_addr;
184*24495Sjg 	vsb = &vsBuff[VSUNIT(dev)];
185*24495Sjg 	printM("vsopen csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
186*24495Sjg 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
187*24495Sjg 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
188*24495Sjg 
189*24495Sjg 	/*
190*24495Sjg 	 * Finally! We can now set up the device.
191*24495Sjg 	 */
192*24495Sjg 
193*24495Sjg 	if (!vsp->inited && !(flag & FNDELAY)) {
194*24495Sjg 		vsInitDev(dev, TRUE);
195*24495Sjg 		if (ret = vsError(vsp))
196*24495Sjg 			return(ret);
197*24495Sjg 	}
198*24495Sjg 
199*24495Sjg 	vsp->open = TRUE;		/* we're open */
200*24495Sjg 	vsp->pgrp = u.u_procp->p_pgrp;
201*24495Sjg 
202*24495Sjg 	/* reset statistics */
203*24495Sjg 	bzero((caddr_t) &vsp->stats, sizeof(vsStats));
204*24495Sjg 
205*24495Sjg 	/* initialize user I/O addresses */
206*24495Sjg 	vsb->vsioa.ioreg = (short *)vsaddr;
207*24495Sjg 	vsb->vsioa.status = 0;
208*24495Sjg 	vsb->vsioa.obuff = vsb->obuff;
209*24495Sjg 	vsb->vsioa.obufflen = VSBUFFSIZE;
210*24495Sjg 	vsb->vsioa.ibuff = vsb->ibuff;
211*24495Sjg 	vsb->vsioa.ihead = 0;
212*24495Sjg 	vsb->vsioa.itail = 0;
213*24495Sjg 	vsb->vsioa.iqsize = VSMAXEVQ;
214*24495Sjg 	/* map io regs into user address space (assume they don't cross a page) */
215*24495Sjg 	maptouser(vsaddr);
216*24495Sjg 	/* map vsBuff into user address space */
217*24495Sjg 	vsBuffpage = (caddr_t)((int)vsb & ~PGOFSET);
218*24495Sjg 	vsBuffnpages = (((int)vsb & PGOFSET) +
219*24495Sjg 			 (NBPG-1) + sizeof(struct vsBuffArea)) >> PGSHIFT;
220*24495Sjg 	while (vsBuffnpages>0) {
221*24495Sjg 	    maptouser(vsBuffpage);
222*24495Sjg 	    vsBuffpage += NBPG;
223*24495Sjg 	    vsBuffnpages--;
224*24495Sjg 	}
225*24495Sjg 	/* lock in the buffer */
226*24495Sjg 	vsbuf.b_error = 0;
227*24495Sjg 	vsbuf.b_proc = u.u_procp;
228*24495Sjg 	vsbuf.b_un.b_addr = vsb->obuff;
229*24495Sjg 	vsbuf.b_flags = B_BUSY;
230*24495Sjg 	vsbuf.b_bcount = VSBUFFSIZE;
231*24495Sjg 	vsp->vsBuff_ubinfo = ubasetup(uip->ui_ubanum, &vsbuf, UBA_CANTWAIT);
232*24495Sjg 
233*24495Sjg 	vsb->vsioa.reloc = (int) (vsp->offset.fparm_all
234*24495Sjg 			+ (vsp->vsBuff_ubinfo & 0x3ffff));
235*24495Sjg 	return(0);
236*24495Sjg }
237*24495Sjg 
238*24495Sjg vsclose(dev)
239*24495Sjg dev_t dev;
240*24495Sjg {
241*24495Sjg 	register struct uba_device *uip = vsdinfo[VSUNIT(dev)];
242*24495Sjg 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
243*24495Sjg 	int s, i;
244*24495Sjg 	struct vsdevice *vsaddr;
245*24495Sjg 	struct vsBuffArea *vsb;
246*24495Sjg 	caddr_t vsBuffpage;
247*24495Sjg 	int vsBuffnpages;
248*24495Sjg 
249*24495Sjg 	vsaddr = (struct vsdevice *) uip->ui_addr;
250*24495Sjg 	printM("vsclose csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
251*24495Sjg 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
252*24495Sjg 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
253*24495Sjg 		vsb = &vsBuff[VSUNIT(dev)];
254*24495Sjg 	if (vsDebugPrintfs) {
255*24495Sjg 		printf("vs%d: %d errors, %d unsolicited interrupts",
256*24495Sjg 			VSUNIT(dev), vsp->stats.errors, vsp->stats.unsolIntr);
257*24495Sjg 		printf(", %d link errors", vsp->stats.linkErrors);
258*24495Sjg 		printf(", %d overruns", vsp->stats.overruns);
259*24495Sjg 		printf(", csr0 %x, csr1 %x", vsaddr->vs_csr0, vsaddr->vs_csr1);
260*24495Sjg 		printf("\n");
261*24495Sjg 	}
262*24495Sjg 
263*24495Sjg 	vsp->open = FALSE;
264*24495Sjg 	vsp->inited = FALSE;		/* init on every open */
265*24495Sjg 	vsp->vs_nextgo.fparm_all = NULL;
266*24495Sjg 	vsb->vsioa.mbox.bottom = 0;
267*24495Sjg 	/* release the buffer */
268*24495Sjg 	if (vsp->vsBuff_ubinfo!=0) {
269*24495Sjg 		ubarelse(uip->ui_ubanum, &vsp->vsBuff_ubinfo);
270*24495Sjg 	}
271*24495Sjg 
272*24495Sjg #ifdef notdef
273*24495Sjg 	/* unmap io regs into user address space (assume they don't cross a page) */
274*24495Sjg 	unmaptouser(vsaddr);
275*24495Sjg 	/* unmap vsBuff into user address space */
276*24495Sjg 	vsBuffpage = (caddr_t)((int)vsb & ~PGOFSET);
277*24495Sjg 	vsBuffnpages = (((int)vsb&PGOFSET) +
278*24495Sjg 			 (NBPG-1)+ sizeof(struct vsBuffArea)) >> PGSHIFT;
279*24495Sjg 	while (vsBuffnpages>0) {
280*24495Sjg 	    unmaptouser(vsBuffpage);
281*24495Sjg 	    vsBuffpage += NBPG;
282*24495Sjg 	    vsBuffnpages--;
283*24495Sjg 	}
284*24495Sjg #endif
285*24495Sjg }
286*24495Sjg 
287*24495Sjg vsread(dev,uio)
288*24495Sjg dev_t   dev;
289*24495Sjg struct uio      *uio;
290*24495Sjg {
291*24495Sjg         return(-1);
292*24495Sjg }
293*24495Sjg 
294*24495Sjg vswrite(dev, uio)
295*24495Sjg dev_t   dev;
296*24495Sjg struct uio      *uio;
297*24495Sjg {
298*24495Sjg         return(-1);
299*24495Sjg }
300*24495Sjg 
301*24495Sjg /*ARGSUSED*/
302*24495Sjg vsioctl(dev, cmd, addr, flag)
303*24495Sjg dev_t dev;
304*24495Sjg register caddr_t addr;
305*24495Sjg {
306*24495Sjg 	register struct uba_device *uip = vsdinfo[VSUNIT(dev)];
307*24495Sjg 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
308*24495Sjg 	register struct vsdevice *vsaddr = (struct vsdevice *) uip->ui_addr;
309*24495Sjg 	register struct vsBuffArea *vsb = &vsBuff[VSUNIT(dev)];
310*24495Sjg 	struct vs_fparm vsAddr;
311*24495Sjg 	int s;
312*24495Sjg 	int func;
313*24495Sjg 	int ret;
314*24495Sjg 
315*24495Sjg 	switch(cmd) {			/* things that don't need the device */
316*24495Sjg 	case VSIOWAITGO:
317*24495Sjg 		/* wait for user I/O operation to complete, then go */
318*24495Sjg 		s = spl5();
319*24495Sjg 		if ((ret = vsb->vsioa.status) == 0) {
320*24495Sjg 			vsp->vs_nextgo.fparm_all = ((struct vs_fparm *) addr)->fparm_all;
321*24495Sjg 			do {
322*24495Sjg 				sleep((caddr_t) vsp, VSWAITPRI);
323*24495Sjg 			} while (vsp->vs_nextgo.fparm_all);
324*24495Sjg 			ret = vsp->vs_status;
325*24495Sjg 		} else {
326*24495Sjg 			vsaddr->vs_pr1 = ((struct vs_fparm *)addr)->fparm_low;
327*24495Sjg 			vsaddr->vs_pr2 = ((struct vs_fparm *)addr)->fparm_high;
328*24495Sjg 			vsb->vsioa.status = 0;
329*24495Sjg 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
330*24495Sjg 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
331*24495Sjg 		}
332*24495Sjg 		splx(s);
333*24495Sjg 		if (ret & VS_ERROR)
334*24495Sjg 			return ((ret & VS_REASON) + 128);
335*24495Sjg 		return(0);
336*24495Sjg 
337*24495Sjg 	case VSIOUSERWAIT:
338*24495Sjg 		/* wait for user I/O operation to complete */
339*24495Sjg 		s = spl5();
340*24495Sjg 		while (vsb->vsioa.status == 0) {
341*24495Sjg 			sleep((caddr_t) vsp, VSWAITPRI);
342*24495Sjg 		}
343*24495Sjg 		splx(s);
344*24495Sjg 		return (0);
345*24495Sjg 
346*24495Sjg 	case VSIOGETVER:		/* get ROM version */
347*24495Sjg 		if (!vsp->inited)
348*24495Sjg 			return(ENODEV);
349*24495Sjg 		*(int *) addr = vsp->romVersion;
350*24495Sjg 		return(0);
351*24495Sjg 
352*24495Sjg 	case VSIOGETSTATS:		/* get statistics block */
353*24495Sjg 		*(vsStats *)addr = vsp->stats;
354*24495Sjg 		return(0);
355*24495Sjg 
356*24495Sjg 	case VSIOGETIOA:		/* get io addresses */
357*24495Sjg 		if (vsp->vsBuff_ubinfo==0) {
358*24495Sjg 		    return(EIO);
359*24495Sjg 		}
360*24495Sjg 		*((vsIoAddrAddr *)addr) = &vsb->vsioa;
361*24495Sjg 		return(0);
362*24495Sjg 
363*24495Sjg 	default:			/* a command that could block */
364*24495Sjg 		if (ret = vsError(vsp))
365*24495Sjg 			return(ret);
366*24495Sjg 		break;
367*24495Sjg 	}
368*24495Sjg 
369*24495Sjg 	switch(cmd) {			/* Commands that cause an interrupt */
370*24495Sjg 	case VSIOINIT:			/* initialize device */
371*24495Sjg 		vsInitDev(dev, FALSE);
372*24495Sjg 		return(vsError(vsp));
373*24495Sjg 
374*24495Sjg 	case VSIOSTART:			/* start microcode */
375*24495Sjg 		vsAddr.fparm_all = *(caddr_t *)addr;
376*24495Sjg 		s = spl5();
377*24495Sjg 		vsaddr->vs_pr1 = vsAddr.fparm_low;
378*24495Sjg 		vsaddr->vs_pr2 = vsAddr.fparm_high;
379*24495Sjg 		vsaddr->vs_irr = 0;
380*24495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
381*24495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (VS_START << VS_FCSHIFT) | VS_GO);
382*24495Sjg 		sleep((caddr_t) vsp, VSWAITPRI);	/* synchronous */
383*24495Sjg 		splx(s);
384*24495Sjg 		return(vsError(vsp));
385*24495Sjg 
386*24495Sjg 	case VSIOABORT:			/* abort a command chain */
387*24495Sjg 		s = spl5();
388*24495Sjg 		vsaddr->vs_irr = 0;
389*24495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
390*24495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (VS_ABORT << VS_FCSHIFT) | VS_GO);
391*24495Sjg 		sleep((caddr_t) vsp, VSWAITPRI);
392*24495Sjg 		splx(s);
393*24495Sjg 		return(vsError(vsp));
394*24495Sjg 
395*24495Sjg 	case VSIOPWRUP:			/* power-up reset */
396*24495Sjg 		s = spl5();
397*24495Sjg 		vsaddr->vs_irr = 0;
398*24495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
399*24495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (VS_PWRUP << VS_FCSHIFT) | VS_GO);
400*24495Sjg 		sleep((caddr_t) vsp, VSWAITPRI);
401*24495Sjg 		splx(s);
402*24495Sjg 		return(vsError(vsp));
403*24495Sjg 
404*24495Sjg 	case VSIOBBACTL:		/* enable/disable BBA */
405*24495Sjg 		s = spl5();
406*24495Sjg 		vsaddr->vs_irr = 0;
407*24495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
408*24495Sjg 		func = *(int *)addr == VSIO_ON ? VS_ENABBA : VS_DISBBA;
409*24495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (func << VS_FCSHIFT) | VS_GO);
410*24495Sjg 		sleep((caddr_t) vsp, VSWAITPRI);
411*24495Sjg 		splx(s);
412*24495Sjg 		return(vsError(vsp));
413*24495Sjg 
414*24495Sjg 	case VSIOFIBCTL:		/* turn the fiber lamp on/off */
415*24495Sjg 		s = spl5();
416*24495Sjg 		if (*(int *)addr == VSIO_OFF)
417*24495Sjg 			vsaddr->vs_csr0 &= ~VS_XMIT_ON;
418*24495Sjg 		else
419*24495Sjg 			vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);
420*24495Sjg 		sleep((caddr_t) vsp, VSWAITPRI);
421*24495Sjg 		splx(s);
422*24495Sjg 		return(vsError(vsp));
423*24495Sjg 
424*24495Sjg 	case VSIOFIBRETRY:		/* set fiber retries */
425*24495Sjg 		s = spl5();
426*24495Sjg 		vsaddr->vs_irr = 0;
427*24495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
428*24495Sjg 		func = *(int *)addr == VS_FIB_FINITE ? VS_FINITE : VS_INFINITE;
429*24495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (func << VS_FCSHIFT) | VS_GO);
430*24495Sjg 		sleep((caddr_t) vsp, VSWAITPRI);
431*24495Sjg 		splx(s);
432*24495Sjg 		return(vsError(vsp));
433*24495Sjg 
434*24495Sjg 	case VSIOSYNC:			/* get synchronized with device */
435*24495Sjg 		break;
436*24495Sjg 
437*24495Sjg 	default:
438*24495Sjg 		return(ENOTTY);
439*24495Sjg 	}
440*24495Sjg 
441*24495Sjg 	return(0);
442*24495Sjg }
443*24495Sjg 
444*24495Sjg vsintr(dev)
445*24495Sjg dev_t dev;
446*24495Sjg {
447*24495Sjg 	register struct vsdevice *vsaddr;
448*24495Sjg 	register struct vs_softc *vsp;
449*24495Sjg 	register vsEvent *vep;
450*24495Sjg 	struct uba_device *uip;
451*24495Sjg 	register struct vsBuffArea *vsb;
452*24495Sjg 	int i;
453*24495Sjg 	vsCursor cur;
454*24495Sjg 
455*24495Sjg 	if (VSUNIT(dev) >= NVS || (uip = vsdinfo[VSUNIT(dev)]) == 0
456*24495Sjg 	    || uip->ui_alive == 0) {
457*24495Sjg 		printI("vs%d stray interrupt\n", VSUNIT(dev));
458*24495Sjg 		return;
459*24495Sjg 	}
460*24495Sjg 
461*24495Sjg 	vsaddr = (struct vsdevice *) uip->ui_addr;
462*24495Sjg 	vsp = &vs_softc[VSUNIT(dev)];
463*24495Sjg 	vsb = &vsBuff[VSUNIT(dev)];
464*24495Sjg #ifdef notdef
465*24495Sjg 	printM("vsintr csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
466*24495Sjg 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
467*24495Sjg 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
468*24495Sjg 
469*24495Sjg 	printI("vs%dintr ", VSUNIT(dev));
470*24495Sjg #endif
471*24495Sjg 
472*24495Sjg 	/*
473*24495Sjg 	 * get the information out of the soft registers
474*24495Sjg 	 */
475*24495Sjg 
476*24495Sjg 	vsp->irr.intr_reg = vsaddr->vs_irr;
477*24495Sjg 	vsp->krr.kbd_reg = vsaddr->vs_krr;
478*24495Sjg 	vsp->pr.fparm_low = vsaddr->vs_pr1;
479*24495Sjg 	vsp->pr.fparm_high = vsaddr->vs_pr2;
480*24495Sjg 	cur.x = vsaddr->vs_cxr;
481*24495Sjg 	cur.y = vsaddr->vs_cyr;
482*24495Sjg 	vsp->csr.csr_reg = vsaddr->vs_csr0;
483*24495Sjg 
484*24495Sjg 	if (vsp->irr.intr_reason)
485*24495Sjg 		vsaddr->vs_irr = 0;	/* clear int reason, if any */
486*24495Sjg 
487*24495Sjg 	vsaddr->vs_csr0 &= ~VS_OWN;	/* clear owner bit */
488*24495Sjg 
489*24495Sjg 	if (vsp->csr.csr_linkTran) {
490*24495Sjg 		vsaddr->vs_csr0 &= ~VS_LNK_TRNS;	/* clear the bit */
491*24495Sjg 		printI("link transition: ");
492*24495Sjg 		if (vsp->csr.csr_linkErr)
493*24495Sjg 			vsp->stats.linkErrors++;
494*24495Sjg 
495*24495Sjg 		if (vsp->csr.csr_linkAvail == vsp->linkAvail) {	/* flash */
496*24495Sjg 			vsp->stats.flashes++;
497*24495Sjg 			printI("flash\n");
498*24495Sjg 		} else if (!vsp->csr.csr_linkAvail && vsp->linkAvail) { /* on -> off */
499*24495Sjg 			vsp->stats.douses++;
500*24495Sjg 			printI("douse\n");
501*24495Sjg 			vsp->inited = FALSE;
502*24495Sjg 			if (vsp->open && vsp->pgrp)
503*24495Sjg 				gsignal(vsp->pgrp, SIGHUP);
504*24495Sjg 			wakeup((caddr_t) vsp);
505*24495Sjg 		} else {						/* off -> on */
506*24495Sjg 			vsp->stats.ignites++;
507*24495Sjg 			printI("ignite\n");
508*24495Sjg 			wakeup((caddr_t) vsp);
509*24495Sjg 		}
510*24495Sjg 
511*24495Sjg 		i = 200;
512*24495Sjg 		while ((vsaddr->vs_csr0 & VS_LNK_TRNS) && i)
513*24495Sjg 			i--;
514*24495Sjg 		if (i == 0) {		/* bit stuck */
515*24495Sjg 			printI("vs%d: Link Transition bit stuck\n", VSUNIT(dev));
516*24495Sjg 			vsp->inited = FALSE;
517*24495Sjg 			if (vsp->open && vsp->pgrp)
518*24495Sjg 				gsignal(vsp->pgrp, SIGHUP);
519*24495Sjg 			vsaddr->vs_csr0 &= ~VS_XMIT_ON;
520*24495Sjg 			vsp->csr.csr_linkAvail = FALSE;
521*24495Sjg 		}
522*24495Sjg 
523*24495Sjg 		vsp->linkAvail = vsp->csr.csr_linkAvail;
524*24495Sjg 
525*24495Sjg 		return;
526*24495Sjg 	}
527*24495Sjg 
528*24495Sjg 	if (vsp->irr.intr_error) {
529*24495Sjg 		printI("error 0x%x\n", vsp->irr.intr_reg&0xffff);
530*24495Sjg 		vsp->stats.errors++;
531*24495Sjg 		/* set status and wake up user if necessary */
532*24495Sjg 		if (vsp->vs_nextgo.fparm_all) {
533*24495Sjg 			vsp->vs_status = vsp->irr.intr_reg;
534*24495Sjg 			vsaddr->vs_pr1 = vsp->vs_nextgo.fparm_low;
535*24495Sjg 			vsaddr->vs_pr2 = vsp->vs_nextgo.fparm_high;
536*24495Sjg 			vsp->vs_nextgo.fparm_all = NULL;
537*24495Sjg 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
538*24495Sjg 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
539*24495Sjg 		} else
540*24495Sjg 			vsb->vsioa.status = vsp->irr.intr_reg;
541*24495Sjg 		wakeup((caddr_t) vsp);
542*24495Sjg 		return;
543*24495Sjg 	}
544*24495Sjg 
545*24495Sjg #ifdef notdef
546*24495Sjg 	printI("reason is %b\n", vsp->irr.intr_reason, VSIRR_BITS);
547*24495Sjg #endif
548*24495Sjg 	switch(vsp->irr.intr_reason) {
549*24495Sjg 	case VS_INT_CD:			/* command done */
550*24495Sjg 		/* set status and start a new command if necessary */
551*24495Sjg 		if (vsp->vs_nextgo.fparm_all) {
552*24495Sjg 			vsp->vs_status = vsp->irr.intr_reg;
553*24495Sjg 			vsaddr->vs_pr1 = vsp->vs_nextgo.fparm_low;
554*24495Sjg 			vsaddr->vs_pr2 = vsp->vs_nextgo.fparm_high;
555*24495Sjg 			vsp->vs_nextgo.fparm_all = NULL;
556*24495Sjg 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
557*24495Sjg 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
558*24495Sjg 		} else
559*24495Sjg 			vsb->vsioa.status = vsp->irr.intr_reg;
560*24495Sjg 		break;
561*24495Sjg 
562*24495Sjg 	case VS_INT_MM:			/* mouse moved */
563*24495Sjg 
564*24495Sjg 		vsb->vsioa.mouse = cur;
565*24495Sjg 
566*24495Sjg                 if (!vsp->open)
567*24495Sjg                         return;         /* ignore on closed device */
568*24495Sjg 
569*24495Sjg 		/* no event if inside box */
570*24495Sjg 		if (cur.y < vsb->vsioa.mbox.bottom &&
571*24495Sjg 		    cur.y >= vsb->vsioa.mbox.top &&
572*24495Sjg 		    cur.x < vsb->vsioa.mbox.right &&
573*24495Sjg 		    cur.x >= vsb->vsioa.mbox.left)
574*24495Sjg 		    return;
575*24495Sjg 
576*24495Sjg 		/* trash box */
577*24495Sjg 		vsb->vsioa.mbox.bottom = 0;
578*24495Sjg 
579*24495Sjg 		if (EVROUND(vsb->vsioa.itail+1) == vsb->vsioa.ihead)
580*24495Sjg 		    return;
581*24495Sjg 		i = EVROUND(vsb->vsioa.itail-1);
582*24495Sjg 		if ((vsb->vsioa.itail != vsb->vsioa.ihead) &&
583*24495Sjg 		    (i != vsb->vsioa.ihead)) {
584*24495Sjg 		    vep = &vsb->ibuff[i];
585*24495Sjg 		    if (vep->vse_type == VSE_MMOTION) {
586*24495Sjg 			vep->vse_x = cur.x;
587*24495Sjg 			vep->vse_y = cur.y;
588*24495Sjg 			vep->vse_time = mfpr(TODR);
589*24495Sjg 			return;
590*24495Sjg 		    }
591*24495Sjg 		}
592*24495Sjg 		/* put event into queue and do select */
593*24495Sjg 		vep = &vsb->ibuff[vsb->vsioa.itail];
594*24495Sjg 		vep->vse_type = VSE_MMOTION;
595*24495Sjg 		vep->vse_x = cur.x;
596*24495Sjg 		vep->vse_y = cur.y;
597*24495Sjg 		vep->vse_time = mfpr(TODR);
598*24495Sjg 		vsb->vsioa.itail = EVROUND(vsb->vsioa.itail+1);
599*24495Sjg 		if (vsp->rsel) {
600*24495Sjg 			selwakeup(vsp->rsel, 0);
601*24495Sjg 			vsp->rsel = 0;
602*24495Sjg 		}
603*24495Sjg 		break;
604*24495Sjg 
605*24495Sjg 	case VS_INT_BE:			/* button event */
606*24495Sjg 		if (!vsp->open)
607*24495Sjg 			return;		/* ignore on closed device */
608*24495Sjg 
609*24495Sjg 		if (vsp->krr.kbd_device == VSE_MOUSE) {
610*24495Sjg 		    vsb->vsioa.mouse.x = cur.x;
611*24495Sjg 		    vsb->vsioa.mouse.y = cur.y;
612*24495Sjg 		}
613*24495Sjg 		/* check for room in the queue */
614*24495Sjg 		if ((i = EVROUND(vsb->vsioa.itail+1)) == vsb->vsioa.ihead)
615*24495Sjg 		    return;
616*24495Sjg 		/* put event into queue and do select */
617*24495Sjg 		vep = &vsb->ibuff[vsb->vsioa.itail];
618*24495Sjg 		vep->vse_type = VSE_BUTTON;
619*24495Sjg 		vep->vse_key = vsp->krr.kbd_key;
620*24495Sjg 		vep->vse_direction = vsp->krr.kbd_transition;
621*24495Sjg 		vep->vse_device = vsp->krr.kbd_device;
622*24495Sjg 	        vep->vse_time = mfpr(TODR);
623*24495Sjg 		vep->vse_x = vsb->vsioa.mouse.x;
624*24495Sjg 		vep->vse_y = vsb->vsioa.mouse.y;
625*24495Sjg 		vsb->vsioa.itail = i;
626*24495Sjg 		if (vsp->rsel) {
627*24495Sjg 			selwakeup(vsp->rsel, 0);
628*24495Sjg 			vsp->rsel = 0;
629*24495Sjg 		}
630*24495Sjg 		break;
631*24495Sjg 
632*24495Sjg 	case VS_INT_TM:			/* tablet moved */
633*24495Sjg 		if (!vsp->open)
634*24495Sjg 			return;		/* ignore on closed device */
635*24495Sjg 
636*24495Sjg 		if (EVROUND(vsb->vsioa.itail+1) == vsb->vsioa.ihead)
637*24495Sjg 		    return;
638*24495Sjg 		i = EVROUND(vsb->vsioa.itail-1);
639*24495Sjg 		if ((vsb->vsioa.itail != vsb->vsioa.ihead) &&
640*24495Sjg 		    (i != vsb->vsioa.ihead)) {
641*24495Sjg 		    vep = &vsb->ibuff[i];
642*24495Sjg 		    if (vep->vse_type == VSE_TMOTION) {
643*24495Sjg 			vep->vse_x = cur.x;
644*24495Sjg 			vep->vse_y = cur.y;
645*24495Sjg 			vep->vse_time = mfpr(TODR);
646*24495Sjg 			return;
647*24495Sjg 		    }
648*24495Sjg 		}
649*24495Sjg 		/* put event into queue and do select */
650*24495Sjg 		vep = &vsb->ibuff[vsb->vsioa.itail];
651*24495Sjg 		vep->vse_type = VSE_TMOTION;
652*24495Sjg 		vep->vse_x = cur.x;
653*24495Sjg 		vep->vse_y = cur.y;
654*24495Sjg 		vep->vse_time = mfpr(TODR);
655*24495Sjg 		vsb->vsioa.itail = EVROUND(vsb->vsioa.itail+1);
656*24495Sjg 		if (vsp->rsel) {
657*24495Sjg 			selwakeup(vsp->rsel, 0);
658*24495Sjg 			vsp->rsel = 0;
659*24495Sjg 		}
660*24495Sjg 		break;
661*24495Sjg 
662*24495Sjg 	case VS_INT_US:			/* unsolicited */
663*24495Sjg 		vsp->stats.unsolIntr++;
664*24495Sjg 		return;
665*24495Sjg 
666*24495Sjg 	case VS_INT_ID:			/* Initialization done */
667*24495Sjg 					/* save offset from device */
668*24495Sjg 		vsp->offset.fparm_all = vsp->pr.fparm_all;
669*24495Sjg 					/* save rom version */
670*24495Sjg 		vsp->romVersion = cur.x;
671*24495Sjg 		vsp->inited = TRUE;
672*24495Sjg 		break;
673*24495Sjg 
674*24495Sjg 	case VS_INT_SE:			/* ucode started */
675*24495Sjg 		break;
676*24495Sjg 
677*24495Sjg 	case VS_INT_PWR:		/* power up complete */
678*24495Sjg 					/* save rom version */
679*24495Sjg 		vsp->romVersion = cur.x;
680*24495Sjg 		vsp->inited = FALSE;
681*24495Sjg 		if (vsp->open && vsp->pgrp)
682*24495Sjg 			gsignal(vsp->pgrp, SIGHUP);
683*24495Sjg 		break;
684*24495Sjg 
685*24495Sjg 	default:
686*24495Sjg 		printI("vs%d: unknown interrupt %b\n", VSUNIT(dev),
687*24495Sjg 			vsp->irr.intr_reason, VSIRR_BITS);
688*24495Sjg 		return;
689*24495Sjg 	}
690*24495Sjg 	wakeup((caddr_t) vsp);
691*24495Sjg }
692*24495Sjg 
693*24495Sjg vsreset(uban)
694*24495Sjg int uban;
695*24495Sjg {
696*24495Sjg 	register int i;
697*24495Sjg 	register struct uba_device *uip;
698*24495Sjg 	register struct vs_softc *vsp = vs_softc;
699*24495Sjg 
700*24495Sjg 	for (i = 0; i < NVS; i++, vsp++) {
701*24495Sjg 		if ((uip = vsdinfo[i]) == 0 || uip->ui_alive == 0 ||
702*24495Sjg 		    uip->ui_ubanum != uban || vsp->open == 0)
703*24495Sjg 			continue;
704*24495Sjg 		printf(" vs%d", i);
705*24495Sjg 		vsp->inited = FALSE;
706*24495Sjg 		if (vsp->open && vsp->pgrp)
707*24495Sjg 			gsignal(vsp->pgrp, SIGHUP);
708*24495Sjg 	}
709*24495Sjg }
710*24495Sjg 
711*24495Sjg vsselect(dev, rw)
712*24495Sjg dev_t dev;
713*24495Sjg {
714*24495Sjg 	register struct vsBuffArea *vsb = &vsBuff[VSUNIT(dev)];
715*24495Sjg 	int s = spl5();
716*24495Sjg 
717*24495Sjg 	switch(rw) {
718*24495Sjg 	case FREAD:
719*24495Sjg 		if (vsb->vsioa.ihead != vsb->vsioa.itail) {
720*24495Sjg 		    splx(s);
721*24495Sjg 		    return(1);
722*24495Sjg 		}
723*24495Sjg 		vs_softc[VSUNIT(dev)].rsel = u.u_procp;
724*24495Sjg 		splx(s);
725*24495Sjg 		return(0);
726*24495Sjg 
727*24495Sjg 	case FWRITE:
728*24495Sjg 		splx(s);
729*24495Sjg 		return(EACCES);
730*24495Sjg 	}
731*24495Sjg }
732*24495Sjg 
733*24495Sjg /*
734*24495Sjg  * Initialize VS100 or SBO.
735*24495Sjg  * Set XMITON.  VS100 will respond with link available.  SBO won't, so
736*24495Sjg  * don't wait forever; assume everything is OK and warn user.
737*24495Sjg  */
738*24495Sjg 
739*24495Sjg vsInitFiber(dev)
740*24495Sjg dev_t dev;
741*24495Sjg {
742*24495Sjg 	struct vsdevice *vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr;
743*24495Sjg 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
744*24495Sjg 	int s;
745*24495Sjg #ifdef VSSBO
746*24495Sjg 	int vsFiberNudge();
747*24495Sjg 
748*24495Sjg 	timeout(vsFiberNudge, (caddr_t) dev, 2*hz);
749*24495Sjg #endif
750*24495Sjg 	s = spl5();
751*24495Sjg 	vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);	/* turn link on */
752*24495Sjg 	sleep((caddr_t) vsp, VSWAITPRI);
753*24495Sjg 	splx(s);
754*24495Sjg #ifdef VSSBO
755*24495Sjg 	if (!vsp->linkAvail) {
756*24495Sjg 		uprintf("\007This had better be a vs125!\n");
757*24495Sjg 		printf("vs%d must be a vs125\n", VSUNIT(dev));
758*24495Sjg 		vsp->linkAvail = TRUE;
759*24495Sjg 	}
760*24495Sjg #endif
761*24495Sjg }
762*24495Sjg 
763*24495Sjg #ifdef VSSBO
764*24495Sjg vsFiberNudge(dev)
765*24495Sjg dev_t dev;
766*24495Sjg {
767*24495Sjg 	struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
768*24495Sjg 
769*24495Sjg 	if (!vsp->linkAvail)
770*24495Sjg 		wakeup((caddr_t) vsp);
771*24495Sjg }
772*24495Sjg #endif VSSBO
773*24495Sjg 
774*24495Sjg vsInitDev(dev, retry)
775*24495Sjg dev_t dev;
776*24495Sjg int retry;
777*24495Sjg {
778*24495Sjg 	register struct vsdevice *vsaddr;
779*24495Sjg 	register struct vs_softc *vsp;
780*24495Sjg 	int s;
781*24495Sjg 	int vsInitNudge();
782*24495Sjg 
783*24495Sjg 	vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr;
784*24495Sjg 	vsp = &vs_softc[VSUNIT(dev)];
785*24495Sjg 
786*24495Sjg 	if (!vsp->linkAvail)
787*24495Sjg 		vsInitFiber(dev);
788*24495Sjg 	while (1) {
789*24495Sjg 		if (retry)
790*24495Sjg 			timeout(vsInitNudge, (caddr_t) dev, 10*hz);
791*24495Sjg 		s = spl5();
792*24495Sjg 		vsaddr->vs_irr = 0;
793*24495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
794*24495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (VS_INIT << VS_FCSHIFT) | VS_GO);
795*24495Sjg 		sleep((caddr_t) vsp, VSWAITPRI);
796*24495Sjg 		splx(s);
797*24495Sjg 		if (vsp->inited)
798*24495Sjg 			break;
799*24495Sjg 		printM("vs%d: VS_INIT fails\n", VSUNIT(dev));
800*24495Sjg 		uprintf("vsInitDev %x %x\n",vsaddr->vs_csr0, vsaddr->vs_csr1);
801*24495Sjg 	}
802*24495Sjg }
803*24495Sjg 
804*24495Sjg vsInitNudge(dev)
805*24495Sjg dev_t dev;
806*24495Sjg {
807*24495Sjg 	struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
808*24495Sjg 
809*24495Sjg 	if (!vsp->inited)
810*24495Sjg 		wakeup((caddr_t) vsp);
811*24495Sjg }
812*24495Sjg 
813*24495Sjg vsError(vsp)
814*24495Sjg 	register struct vs_softc *vsp;
815*24495Sjg {
816*24495Sjg 	if (vsp->irr.intr_error) {
817*24495Sjg 		register int ret = vsp->irr.intr_reg;
818*24495Sjg 
819*24495Sjg 		printD("\treturning 0x%x\n", ret);
820*24495Sjg 		vsp->irr.intr_reg = 0;
821*24495Sjg 		return(ret+128);
822*24495Sjg 	}
823*24495Sjg 	return(0);
824*24495Sjg }
825*24495Sjg #endif
826*24495Sjg 
827