xref: /csrg-svn/sys/vax/uba/vs.c (revision 45810)
1*45810Sbostic /* @(#)vs.c	7.8 (MIT) 12/16/90 */
224495Sjg  /****************************************************************************
324495Sjg  *									    *
424495Sjg  *  Copyright (c) 1983, 1984 by						    *
524495Sjg  *  DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts.		    *
624495Sjg  *  All rights reserved.						    *
724495Sjg  * 									    *
824495Sjg  *  This software is furnished on an as-is basis and may be used and copied *
924495Sjg  *  only with inclusion of the above copyright notice. This software or any *
1024495Sjg  *  other copies thereof may be provided or otherwise made available to     *
1124495Sjg  *  others only for non-commercial purposes.  No title to or ownership of   *
1224495Sjg  *  the software is hereby transferred.					    *
1324495Sjg  * 									    *
1424495Sjg  *  The information in this software is  subject to change without notice   *
1524495Sjg  *  and  should  not  be  construed as  a commitment by DIGITAL EQUIPMENT   *
1624495Sjg  *  CORPORATION.							    *
1724495Sjg  * 									    *
1824495Sjg  *  DIGITAL assumes no responsibility for the use  or  reliability of its   *
1924495Sjg  *  software on equipment which is not supplied by DIGITAL.		    *
2024495Sjg  * 									    *
2124495Sjg  *									    *
2224495Sjg  ****************************************************************************/
2324495Sjg 
2424495Sjg #include "vs.h"
2524495Sjg #if NVS > 0
2624495Sjg 
27*45810Sbostic #include "../include/pte.h"
2824495Sjg 
29*45810Sbostic #include "sys/param.h"
30*45810Sbostic #include "sys/user.h"
31*45810Sbostic #include "sys/buf.h"
32*45810Sbostic #include "sys/systm.h"
33*45810Sbostic #include "sys/map.h"
34*45810Sbostic #include "sys/kernel.h"
35*45810Sbostic #include "sys/ioctl.h"
3624495Sjg 
3724495Sjg #include "vsio.h"
3824495Sjg 
39*45810Sbostic #include "sys/proc.h"
40*45810Sbostic #include "sys/uio.h"
41*45810Sbostic #include "sys/vmmac.h"
42*45810Sbostic #include "sys/file.h"
4324495Sjg 
4424495Sjg #include "ubareg.h"
4524495Sjg #include "ubavar.h"
4624495Sjg #include "vsreg.h"
4724495Sjg 
48*45810Sbostic #include "../include/mtpr.h"
4924495Sjg 
5024495Sjg #define	VSWAITPRI	(PZERO+1)
5124495Sjg #define	VSMAXEVQ	64	/* must be power of 2 */
5224495Sjg #define EVROUND(x)	((x) & (VSMAXEVQ - 1))
5324495Sjg 
5424495Sjg 
5524495Sjg #define VSBUFFSIZE	3072
5624495Sjg struct vsBuffArea {
5724495Sjg 	vsIoAddr vsioa;
5824495Sjg 	char	obuff[VSBUFFSIZE];
5924495Sjg 	vsEvent ibuff[VSMAXEVQ];
6024495Sjg };
6124495Sjg struct vsBuffArea vsBuff[NVS];
6224495Sjg 
6324495Sjg 
6424495Sjg int vsprobe(), vsattach();
6524495Sjg struct uba_device *vsdinfo[NVS];
6624495Sjg u_short vsstd[] = { 0 };
6724495Sjg struct uba_driver vsdriver =
6824495Sjg 	{ vsprobe, 0, vsattach, 0, vsstd, "vs", vsdinfo, 0, 0 };
6924495Sjg 
7024495Sjg #define	VSUNIT(dev)	(minor(dev))
7124495Sjg 
7224495Sjg struct vs_softc {
7324495Sjg 	unsigned inited : 1;		/* has this ever been inited? */
7424495Sjg 	unsigned open : 1;		/* only one open, please */
7524495Sjg 	unsigned linkAvail : 1;		/* link is up */
7624495Sjg 	short	pgrp;			/* process group for SIGHUP */
7724495Sjg 	int	romVersion;		/* rom version */
7824495Sjg 	struct vs_fparm	offset;		/* address base */
7924495Sjg 	struct vs_csr	csr;		/* saved csr0 */
8024495Sjg 	struct vs_intr	irr;		/* saved interrupt reason */
8124495Sjg 	struct vs_kbd	krr;		/* saved keyboard */
8224495Sjg 	struct vs_fparm	pr;		/* saved parameter regs */
8324495Sjg 	struct proc *rsel;		/* process waiting for select */
8424495Sjg 	struct vs_fparm vs_nextgo;	/* next packet to go */
8524495Sjg 	short vs_status;		/* status from previous packet */
8624495Sjg 	vsStats stats;			/* statistics */
8724495Sjg 	int vsBuff_ubinfo;		/* ubinfo for vsBuff */
8824495Sjg }vs_softc[NVS];
8924495Sjg 
9024495Sjg #define	TRUE	1
9124495Sjg #define	FALSE	0
9224495Sjg 
9324495Sjg #define	printI	if (vsIntrPrintfs)printf
9424495Sjg #define	printD	if (vsDebugPrintfs)printf
9524495Sjg #define	printM	if (vsMlpPrintfs) vsMlpPrintfs--,printf
9624495Sjg int	vsIntrPrintfs = 0;
9724495Sjg int	vsDebugPrintfs = 0;
9824495Sjg int	vsMlpPrintfs = 0;
9924495Sjg 
10024495Sjg /*
10124495Sjg  * Tell the system that it's out there, and set up the device's interrupt
10224495Sjg  * vector. Since we are supporting vs100s and vs125s,
10324495Sjg  * this is a bit kludgey. The vs100 works much
10424495Sjg  * as one expects, but the vs125 tries to set all the fiber link
10524495Sjg  * related bits when you hit VS_IE, ignoring the way the 100 works.
10624495Sjg  * Also, the vs100 will let you set the interrupt vector, but
10724495Sjg  * the vs125 ignores this and uses its hard-wired value.
10824495Sjg  * And there's no sure fire to tell which variant it is.
10924495Sjg  * Ugh. Ugh. Ugh.
11024495Sjg  */
11124495Sjg 
vsprobe(reg)11224495Sjg vsprobe(reg)
11324495Sjg caddr_t reg;
11424495Sjg {
11524495Sjg 	register int br, cvec;		/* value-result */
11624495Sjg 	register struct vsdevice *vsaddr = (struct vsdevice *)reg;
11724495Sjg 
11824495Sjg #ifdef	lint
11924495Sjg 	br = 0; cvec = br; br = cvec;
12024495Sjg 	vsintr(0);
12124495Sjg #endif
12224495Sjg 	br = 0x15;
12324495Sjg 	cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
12424495Sjg 	/*
12524495Sjg 	 * uh_lastiv is the last free interrupt vector in the
12624495Sjg 	 * unibus addapter header (uba_hd).
12724495Sjg 	 */
12824495Sjg 
12924495Sjg 	vsaddr->vs_csr0 = cvec >> 2;	/* Save the vector for use on next device */
13024495Sjg 	vsaddr->vs_irr = 0;		/* Csr will only be read if irr == 0 */
13124495Sjg 	vsaddr->vs_irr = 0;		/* Clear interrupt reason register */
13224495Sjg 	vsaddr->vs_pr1  = 0;		/* Clear function parameter */
13324495Sjg 	vsaddr->vs_pr2  = 0;		/* Clear function parameter */
13424495Sjg 	vsaddr->vs_ivr = cvec;		/* set up vector (no-op for vs125) */
13524495Sjg 
13624495Sjg 	DELAY(100000);
13724495Sjg 	if (vsaddr->vs_csr0 & VS_LNK_AVL)
13824495Sjg 		return(0);	/* light won't go off! */
13924495Sjg 	vsaddr->vs_csr0 &= ~VS_LNK_TRNS;
14024495Sjg 	vsaddr->vs_csr0 |= VS_IE;	/* enable interrupts */
14124495Sjg 	DELAY(200000);
14224495Sjg 
14324495Sjg 	return sizeof(struct vsdevice);
14424495Sjg }
14524495Sjg 
14624495Sjg vsattach(uip)
14724495Sjg struct uba_device *uip;
14824495Sjg {
14924495Sjg 	register struct vs_softc *vsp;
15024495Sjg 	register struct vsdevice *vsaddr;
15124495Sjg 
15224495Sjg 	vsp = &vs_softc[VSUNIT(uip->ui_unit)];
15324495Sjg 	vsp->inited  = FALSE;
15424495Sjg 	vsp->open = FALSE;
15524495Sjg 	vsBuff[VSUNIT(uip->ui_unit)].vsioa.mbox.bottom = 0;
15624495Sjg 	vsp->linkAvail = FALSE;
15724495Sjg 	vsp->romVersion = 0;
15824495Sjg 	vsp->vs_nextgo.fparm_all = NULL;
15924495Sjg 
16024495Sjg 	vsaddr = (struct vsdevice *) uip->ui_addr;
16124495Sjg 	vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);
16224495Sjg }
16324495Sjg 
vsopen(dev,flag)16424495Sjg vsopen(dev, flag)
16524495Sjg dev_t dev;
16624495Sjg int flag;
16724495Sjg {
16824495Sjg 	register struct vs_softc *vsp;
16924495Sjg 	register struct uba_device *uip;
17024495Sjg 	register struct vsdevice *vsaddr;
17124495Sjg 	int s;
17224495Sjg 	int ret;
17324495Sjg 	struct buf vsbuf;
17424495Sjg 	struct vsBuffArea *vsb;
17524495Sjg 	caddr_t vsBuffpage;
17624495Sjg 	int vsBuffnpages;
17724495Sjg 
17824495Sjg 	if (VSUNIT(dev) >= NVS || (vsp = &vs_softc[VSUNIT(dev)])->open ||
17924495Sjg 	    (uip = vsdinfo[VSUNIT(dev)]) == 0 || uip->ui_alive == 0)
18024495Sjg 		return (ENXIO);
18124495Sjg 
18224495Sjg 	vsaddr = (struct vsdevice *) uip->ui_addr;
18324495Sjg 	vsb = &vsBuff[VSUNIT(dev)];
18424495Sjg 	printM("vsopen csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
18524495Sjg 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
18624495Sjg 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
18724495Sjg 
18824495Sjg 	/*
18924495Sjg 	 * Finally! We can now set up the device.
19024495Sjg 	 */
19124495Sjg 
19224495Sjg 	if (!vsp->inited && !(flag & FNDELAY)) {
19340818Smarc 		ret = vsInitDev(dev, TRUE);
19440818Smarc 		if (ret)
19540818Smarc 			return (ret);
19624495Sjg 		if (ret = vsError(vsp))
19724495Sjg 			return(ret);
19824495Sjg 	}
19924495Sjg 
20024495Sjg 	vsp->open = TRUE;		/* we're open */
20124495Sjg 	vsp->pgrp = u.u_procp->p_pgrp;
20224495Sjg 
20324495Sjg 	/* reset statistics */
20424495Sjg 	bzero((caddr_t) &vsp->stats, sizeof(vsStats));
20524495Sjg 
20624495Sjg 	/* initialize user I/O addresses */
20724495Sjg 	vsb->vsioa.ioreg = (short *)vsaddr;
20824495Sjg 	vsb->vsioa.status = 0;
20924495Sjg 	vsb->vsioa.obuff = vsb->obuff;
21024495Sjg 	vsb->vsioa.obufflen = VSBUFFSIZE;
21124495Sjg 	vsb->vsioa.ibuff = vsb->ibuff;
21224495Sjg 	vsb->vsioa.ihead = 0;
21324495Sjg 	vsb->vsioa.itail = 0;
21424495Sjg 	vsb->vsioa.iqsize = VSMAXEVQ;
21524495Sjg 	/* map io regs into user address space (assume they don't cross a page) */
21624495Sjg 	maptouser(vsaddr);
21724495Sjg 	/* map vsBuff into user address space */
21824495Sjg 	vsBuffpage = (caddr_t)((int)vsb & ~PGOFSET);
21924495Sjg 	vsBuffnpages = (((int)vsb & PGOFSET) +
22024495Sjg 			 (NBPG-1) + sizeof(struct vsBuffArea)) >> PGSHIFT;
22124495Sjg 	while (vsBuffnpages>0) {
22224495Sjg 	    maptouser(vsBuffpage);
22324495Sjg 	    vsBuffpage += NBPG;
22424495Sjg 	    vsBuffnpages--;
22524495Sjg 	}
22624495Sjg 	/* lock in the buffer */
22724495Sjg 	vsbuf.b_error = 0;
22824495Sjg 	vsbuf.b_proc = u.u_procp;
22924495Sjg 	vsbuf.b_un.b_addr = vsb->obuff;
23024495Sjg 	vsbuf.b_flags = B_BUSY;
23124495Sjg 	vsbuf.b_bcount = VSBUFFSIZE;
23224495Sjg 	vsp->vsBuff_ubinfo = ubasetup(uip->ui_ubanum, &vsbuf, UBA_CANTWAIT);
23324495Sjg 
23424495Sjg 	vsb->vsioa.reloc = (int) (vsp->offset.fparm_all
23536037Skarels 			+ UBAI_ADDR(vsp->vsBuff_ubinfo));
23624495Sjg 	return(0);
23724495Sjg }
23824495Sjg 
vsclose(dev)23924495Sjg vsclose(dev)
24024495Sjg dev_t dev;
24124495Sjg {
24224495Sjg 	register struct uba_device *uip = vsdinfo[VSUNIT(dev)];
24324495Sjg 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
24424495Sjg 	int s, i;
24524495Sjg 	struct vsdevice *vsaddr;
24624495Sjg 	struct vsBuffArea *vsb;
24724495Sjg 	caddr_t vsBuffpage;
24824495Sjg 	int vsBuffnpages;
24924495Sjg 
25024495Sjg 	vsaddr = (struct vsdevice *) uip->ui_addr;
25124495Sjg 	printM("vsclose csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
25224495Sjg 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
25324495Sjg 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
25424495Sjg 		vsb = &vsBuff[VSUNIT(dev)];
25524495Sjg 	if (vsDebugPrintfs) {
25624495Sjg 		printf("vs%d: %d errors, %d unsolicited interrupts",
25724495Sjg 			VSUNIT(dev), vsp->stats.errors, vsp->stats.unsolIntr);
25824495Sjg 		printf(", %d link errors", vsp->stats.linkErrors);
25924495Sjg 		printf(", %d overruns", vsp->stats.overruns);
26024495Sjg 		printf(", csr0 %x, csr1 %x", vsaddr->vs_csr0, vsaddr->vs_csr1);
26124495Sjg 		printf("\n");
26224495Sjg 	}
26324495Sjg 
26424495Sjg 	vsp->open = FALSE;
26524495Sjg 	vsp->inited = FALSE;		/* init on every open */
26624495Sjg 	vsp->vs_nextgo.fparm_all = NULL;
26724495Sjg 	vsb->vsioa.mbox.bottom = 0;
26824495Sjg 	/* release the buffer */
26924495Sjg 	if (vsp->vsBuff_ubinfo!=0) {
27024495Sjg 		ubarelse(uip->ui_ubanum, &vsp->vsBuff_ubinfo);
27124495Sjg 	}
27224495Sjg 
27324495Sjg #ifdef notdef
27424495Sjg 	/* unmap io regs into user address space (assume they don't cross a page) */
27524495Sjg 	unmaptouser(vsaddr);
27624495Sjg 	/* unmap vsBuff into user address space */
27724495Sjg 	vsBuffpage = (caddr_t)((int)vsb & ~PGOFSET);
27824495Sjg 	vsBuffnpages = (((int)vsb&PGOFSET) +
27924495Sjg 			 (NBPG-1)+ sizeof(struct vsBuffArea)) >> PGSHIFT;
28024495Sjg 	while (vsBuffnpages>0) {
28124495Sjg 	    unmaptouser(vsBuffpage);
28224495Sjg 	    vsBuffpage += NBPG;
28324495Sjg 	    vsBuffnpages--;
28424495Sjg 	}
28524495Sjg #endif
28640818Smarc 	return (0);
28724495Sjg }
28824495Sjg 
vsread(dev,uio)28924495Sjg vsread(dev,uio)
29024495Sjg dev_t   dev;
29124495Sjg struct uio      *uio;
29224495Sjg {
29324495Sjg         return(-1);
29424495Sjg }
29524495Sjg 
vswrite(dev,uio)29624495Sjg vswrite(dev, uio)
29724495Sjg dev_t   dev;
29824495Sjg struct uio      *uio;
29924495Sjg {
30024495Sjg         return(-1);
30124495Sjg }
30224495Sjg 
30324495Sjg /*ARGSUSED*/
vsioctl(dev,cmd,addr,flag)30424495Sjg vsioctl(dev, cmd, addr, flag)
30524495Sjg dev_t dev;
30624495Sjg register caddr_t addr;
30724495Sjg {
30824495Sjg 	register struct uba_device *uip = vsdinfo[VSUNIT(dev)];
30924495Sjg 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
31024495Sjg 	register struct vsdevice *vsaddr = (struct vsdevice *) uip->ui_addr;
31124495Sjg 	register struct vsBuffArea *vsb = &vsBuff[VSUNIT(dev)];
31224495Sjg 	struct vs_fparm vsAddr;
31340818Smarc 	int s, error = 0;
31424495Sjg 	int func;
31524495Sjg 	int ret;
31624495Sjg 
31724495Sjg 	switch(cmd) {			/* things that don't need the device */
31824495Sjg 	case VSIOWAITGO:
31924495Sjg 		/* wait for user I/O operation to complete, then go */
32024495Sjg 		s = spl5();
32124495Sjg 		if ((ret = vsb->vsioa.status) == 0) {
32224495Sjg 			vsp->vs_nextgo.fparm_all = ((struct vs_fparm *) addr)->fparm_all;
32324495Sjg 			do {
32440818Smarc 				error = tsleep((caddr_t)vsp, VSWAITPRI | PCATCH,
32540818Smarc 				    devwait, 0);
32640818Smarc 			} while (vsp->vs_nextgo.fparm_all && error == 0);
32724495Sjg 			ret = vsp->vs_status;
32824495Sjg 		} else {
32924495Sjg 			vsaddr->vs_pr1 = ((struct vs_fparm *)addr)->fparm_low;
33024495Sjg 			vsaddr->vs_pr2 = ((struct vs_fparm *)addr)->fparm_high;
33124495Sjg 			vsb->vsioa.status = 0;
33224495Sjg 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
33324495Sjg 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
33424495Sjg 		}
33524495Sjg 		splx(s);
33640818Smarc 		if (error)
33740818Smarc 			return (error);
33824495Sjg 		if (ret & VS_ERROR)
33924495Sjg 			return ((ret & VS_REASON) + 128);
34024495Sjg 		return(0);
34124495Sjg 
34224495Sjg 	case VSIOUSERWAIT:
34324495Sjg 		/* wait for user I/O operation to complete */
34424495Sjg 		s = spl5();
34524495Sjg 		while (vsb->vsioa.status == 0) {
34640818Smarc 			error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH,
34740818Smarc 			    devio, 0);
34824495Sjg 		}
34924495Sjg 		splx(s);
35040818Smarc 		return (error);
35124495Sjg 
35224495Sjg 	case VSIOGETVER:		/* get ROM version */
35324495Sjg 		if (!vsp->inited)
35424495Sjg 			return(ENODEV);
35524495Sjg 		*(int *) addr = vsp->romVersion;
35624495Sjg 		return(0);
35724495Sjg 
35824495Sjg 	case VSIOGETSTATS:		/* get statistics block */
35924495Sjg 		*(vsStats *)addr = vsp->stats;
36024495Sjg 		return(0);
36124495Sjg 
36224495Sjg 	case VSIOGETIOA:		/* get io addresses */
36324495Sjg 		if (vsp->vsBuff_ubinfo==0) {
36424495Sjg 		    return(EIO);
36524495Sjg 		}
36624495Sjg 		*((vsIoAddrAddr *)addr) = &vsb->vsioa;
36724495Sjg 		return(0);
36824495Sjg 
36924495Sjg 	default:			/* a command that could block */
37024495Sjg 		if (ret = vsError(vsp))
37124495Sjg 			return(ret);
37224495Sjg 		break;
37324495Sjg 	}
37424495Sjg 
37524495Sjg 	switch(cmd) {			/* Commands that cause an interrupt */
37624495Sjg 	case VSIOINIT:			/* initialize device */
37724495Sjg 		vsInitDev(dev, FALSE);
37824495Sjg 		return(vsError(vsp));
37924495Sjg 
38024495Sjg 	case VSIOSTART:			/* start microcode */
38124495Sjg 		vsAddr.fparm_all = *(caddr_t *)addr;
38224495Sjg 		s = spl5();
38324495Sjg 		vsaddr->vs_pr1 = vsAddr.fparm_low;
38424495Sjg 		vsaddr->vs_pr2 = vsAddr.fparm_high;
38524495Sjg 		vsaddr->vs_irr = 0;
38624495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
38724495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (VS_START << VS_FCSHIFT) | VS_GO);
38840045Smarc 		/* synchronous */
38940818Smarc 		error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0);
39024495Sjg 		splx(s);
39140818Smarc 		if (error)
39240818Smarc 			return (error);
39324495Sjg 		return(vsError(vsp));
39424495Sjg 
39524495Sjg 	case VSIOABORT:			/* abort a command chain */
39624495Sjg 		s = spl5();
39724495Sjg 		vsaddr->vs_irr = 0;
39824495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
39924495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (VS_ABORT << VS_FCSHIFT) | VS_GO);
40040818Smarc 		error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0);
40124495Sjg 		splx(s);
40240818Smarc 		if (error)
40340818Smarc 			return (error);
40424495Sjg 		return(vsError(vsp));
40524495Sjg 
40624495Sjg 	case VSIOPWRUP:			/* power-up reset */
40724495Sjg 		s = spl5();
40824495Sjg 		vsaddr->vs_irr = 0;
40924495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
41024495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (VS_PWRUP << VS_FCSHIFT) | VS_GO);
41140818Smarc 		error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0);
41224495Sjg 		splx(s);
41340818Smarc 		if (error)
41440818Smarc 			return (error);
41524495Sjg 		return(vsError(vsp));
41624495Sjg 
41724495Sjg 	case VSIOBBACTL:		/* enable/disable BBA */
41824495Sjg 		s = spl5();
41924495Sjg 		vsaddr->vs_irr = 0;
42024495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
42124495Sjg 		func = *(int *)addr == VSIO_ON ? VS_ENABBA : VS_DISBBA;
42224495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (func << VS_FCSHIFT) | VS_GO);
42340818Smarc 		error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0);
42424495Sjg 		splx(s);
42540818Smarc 		if (error)
42640818Smarc 			return (error);
42724495Sjg 		return(vsError(vsp));
42824495Sjg 
42924495Sjg 	case VSIOFIBCTL:		/* turn the fiber lamp on/off */
43024495Sjg 		s = spl5();
43124495Sjg 		if (*(int *)addr == VSIO_OFF)
43224495Sjg 			vsaddr->vs_csr0 &= ~VS_XMIT_ON;
43324495Sjg 		else
43424495Sjg 			vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);
43540818Smarc 		error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0);
43624495Sjg 		splx(s);
43740818Smarc 		if (error)
43840818Smarc 			return (error);
43924495Sjg 		return(vsError(vsp));
44024495Sjg 
44124495Sjg 	case VSIOFIBRETRY:		/* set fiber retries */
44224495Sjg 		s = spl5();
44324495Sjg 		vsaddr->vs_irr = 0;
44424495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
44524495Sjg 		func = *(int *)addr == VS_FIB_FINITE ? VS_FINITE : VS_INFINITE;
44624495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (func << VS_FCSHIFT) | VS_GO);
44740818Smarc 		error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0);
44824495Sjg 		splx(s);
44940818Smarc 		if (error)
45040818Smarc 			return (error);
45124495Sjg 		return(vsError(vsp));
45224495Sjg 
45324495Sjg 	case VSIOSYNC:			/* get synchronized with device */
45424495Sjg 		break;
45524495Sjg 
45624495Sjg 	default:
45724495Sjg 		return(ENOTTY);
45824495Sjg 	}
45924495Sjg 
46024495Sjg 	return(0);
46124495Sjg }
46224495Sjg 
vsintr(dev)46324495Sjg vsintr(dev)
46424495Sjg dev_t dev;
46524495Sjg {
46624495Sjg 	register struct vsdevice *vsaddr;
46724495Sjg 	register struct vs_softc *vsp;
46824495Sjg 	register vsEvent *vep;
46924495Sjg 	struct uba_device *uip;
47024495Sjg 	register struct vsBuffArea *vsb;
47124495Sjg 	int i;
47224495Sjg 	vsCursor cur;
47324495Sjg 
47424495Sjg 	if (VSUNIT(dev) >= NVS || (uip = vsdinfo[VSUNIT(dev)]) == 0
47524495Sjg 	    || uip->ui_alive == 0) {
47624495Sjg 		printI("vs%d stray interrupt\n", VSUNIT(dev));
47724495Sjg 		return;
47824495Sjg 	}
47924495Sjg 
48024495Sjg 	vsaddr = (struct vsdevice *) uip->ui_addr;
48124495Sjg 	vsp = &vs_softc[VSUNIT(dev)];
48224495Sjg 	vsb = &vsBuff[VSUNIT(dev)];
48324495Sjg #ifdef notdef
48424495Sjg 	printM("vsintr csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
48524495Sjg 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
48624495Sjg 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
48724495Sjg 
48824495Sjg 	printI("vs%dintr ", VSUNIT(dev));
48924495Sjg #endif
49024495Sjg 
49124495Sjg 	/*
49224495Sjg 	 * get the information out of the soft registers
49324495Sjg 	 */
49424495Sjg 
49524495Sjg 	vsp->irr.intr_reg = vsaddr->vs_irr;
49624495Sjg 	vsp->krr.kbd_reg = vsaddr->vs_krr;
49724495Sjg 	vsp->pr.fparm_low = vsaddr->vs_pr1;
49824495Sjg 	vsp->pr.fparm_high = vsaddr->vs_pr2;
49924495Sjg 	cur.x = vsaddr->vs_cxr;
50024495Sjg 	cur.y = vsaddr->vs_cyr;
50124495Sjg 	vsp->csr.csr_reg = vsaddr->vs_csr0;
50224495Sjg 
50324495Sjg 	if (vsp->irr.intr_reason)
50424495Sjg 		vsaddr->vs_irr = 0;	/* clear int reason, if any */
50524495Sjg 
50624495Sjg 	vsaddr->vs_csr0 &= ~VS_OWN;	/* clear owner bit */
50724495Sjg 
50824495Sjg 	if (vsp->csr.csr_linkTran) {
50924495Sjg 		vsaddr->vs_csr0 &= ~VS_LNK_TRNS;	/* clear the bit */
51024495Sjg 		printI("link transition: ");
51124495Sjg 		if (vsp->csr.csr_linkErr)
51224495Sjg 			vsp->stats.linkErrors++;
51324495Sjg 
51424495Sjg 		if (vsp->csr.csr_linkAvail == vsp->linkAvail) {	/* flash */
51524495Sjg 			vsp->stats.flashes++;
51624495Sjg 			printI("flash\n");
51724495Sjg 		} else if (!vsp->csr.csr_linkAvail && vsp->linkAvail) { /* on -> off */
51824495Sjg 			vsp->stats.douses++;
51924495Sjg 			printI("douse\n");
52024495Sjg 			vsp->inited = FALSE;
52124495Sjg 			if (vsp->open && vsp->pgrp)
52224495Sjg 				gsignal(vsp->pgrp, SIGHUP);
52324495Sjg 			wakeup((caddr_t) vsp);
52424495Sjg 		} else {						/* off -> on */
52524495Sjg 			vsp->stats.ignites++;
52624495Sjg 			printI("ignite\n");
52724495Sjg 			wakeup((caddr_t) vsp);
52824495Sjg 		}
52924495Sjg 
53024495Sjg 		i = 200;
53124495Sjg 		while ((vsaddr->vs_csr0 & VS_LNK_TRNS) && i)
53224495Sjg 			i--;
53324495Sjg 		if (i == 0) {		/* bit stuck */
53424495Sjg 			printI("vs%d: Link Transition bit stuck\n", VSUNIT(dev));
53524495Sjg 			vsp->inited = FALSE;
53624495Sjg 			if (vsp->open && vsp->pgrp)
53724495Sjg 				gsignal(vsp->pgrp, SIGHUP);
53824495Sjg 			vsaddr->vs_csr0 &= ~VS_XMIT_ON;
53924495Sjg 			vsp->csr.csr_linkAvail = FALSE;
54024495Sjg 		}
54124495Sjg 
54224495Sjg 		vsp->linkAvail = vsp->csr.csr_linkAvail;
54324495Sjg 
54424495Sjg 		return;
54524495Sjg 	}
54624495Sjg 
54724495Sjg 	if (vsp->irr.intr_error) {
54824495Sjg 		printI("error 0x%x\n", vsp->irr.intr_reg&0xffff);
54924495Sjg 		vsp->stats.errors++;
55024495Sjg 		/* set status and wake up user if necessary */
55124495Sjg 		if (vsp->vs_nextgo.fparm_all) {
55224495Sjg 			vsp->vs_status = vsp->irr.intr_reg;
55324495Sjg 			vsaddr->vs_pr1 = vsp->vs_nextgo.fparm_low;
55424495Sjg 			vsaddr->vs_pr2 = vsp->vs_nextgo.fparm_high;
55524495Sjg 			vsp->vs_nextgo.fparm_all = NULL;
55624495Sjg 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
55724495Sjg 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
55824495Sjg 		} else
55924495Sjg 			vsb->vsioa.status = vsp->irr.intr_reg;
56024495Sjg 		wakeup((caddr_t) vsp);
56124495Sjg 		return;
56224495Sjg 	}
56324495Sjg 
56424495Sjg #ifdef notdef
56524495Sjg 	printI("reason is %b\n", vsp->irr.intr_reason, VSIRR_BITS);
56624495Sjg #endif
56724495Sjg 	switch(vsp->irr.intr_reason) {
56824495Sjg 	case VS_INT_CD:			/* command done */
56924495Sjg 		/* set status and start a new command if necessary */
57024495Sjg 		if (vsp->vs_nextgo.fparm_all) {
57124495Sjg 			vsp->vs_status = vsp->irr.intr_reg;
57224495Sjg 			vsaddr->vs_pr1 = vsp->vs_nextgo.fparm_low;
57324495Sjg 			vsaddr->vs_pr2 = vsp->vs_nextgo.fparm_high;
57424495Sjg 			vsp->vs_nextgo.fparm_all = NULL;
57524495Sjg 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
57624495Sjg 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
57724495Sjg 		} else
57824495Sjg 			vsb->vsioa.status = vsp->irr.intr_reg;
57924495Sjg 		break;
58024495Sjg 
58124495Sjg 	case VS_INT_MM:			/* mouse moved */
58224495Sjg 
58324495Sjg 		vsb->vsioa.mouse = cur;
58424495Sjg 
58524495Sjg                 if (!vsp->open)
58624495Sjg                         return;         /* ignore on closed device */
58724495Sjg 
58824495Sjg 		/* no event if inside box */
58924495Sjg 		if (cur.y < vsb->vsioa.mbox.bottom &&
59024495Sjg 		    cur.y >= vsb->vsioa.mbox.top &&
59124495Sjg 		    cur.x < vsb->vsioa.mbox.right &&
59224495Sjg 		    cur.x >= vsb->vsioa.mbox.left)
59324495Sjg 		    return;
59424495Sjg 
59524495Sjg 		/* trash box */
59624495Sjg 		vsb->vsioa.mbox.bottom = 0;
59724495Sjg 
59824495Sjg 		if (EVROUND(vsb->vsioa.itail+1) == vsb->vsioa.ihead)
59924495Sjg 		    return;
60024495Sjg 		i = EVROUND(vsb->vsioa.itail-1);
60124495Sjg 		if ((vsb->vsioa.itail != vsb->vsioa.ihead) &&
60224495Sjg 		    (i != vsb->vsioa.ihead)) {
60324495Sjg 		    vep = &vsb->ibuff[i];
60424495Sjg 		    if (vep->vse_type == VSE_MMOTION) {
60524495Sjg 			vep->vse_x = cur.x;
60624495Sjg 			vep->vse_y = cur.y;
60724495Sjg 			vep->vse_time = mfpr(TODR);
60824495Sjg 			return;
60924495Sjg 		    }
61024495Sjg 		}
61124495Sjg 		/* put event into queue and do select */
61224495Sjg 		vep = &vsb->ibuff[vsb->vsioa.itail];
61324495Sjg 		vep->vse_type = VSE_MMOTION;
61424495Sjg 		vep->vse_x = cur.x;
61524495Sjg 		vep->vse_y = cur.y;
61624495Sjg 		vep->vse_time = mfpr(TODR);
61724495Sjg 		vsb->vsioa.itail = EVROUND(vsb->vsioa.itail+1);
61824495Sjg 		if (vsp->rsel) {
61924495Sjg 			selwakeup(vsp->rsel, 0);
62024495Sjg 			vsp->rsel = 0;
62124495Sjg 		}
62224495Sjg 		break;
62324495Sjg 
62424495Sjg 	case VS_INT_BE:			/* button event */
62524495Sjg 		if (!vsp->open)
62624495Sjg 			return;		/* ignore on closed device */
62724495Sjg 
62824495Sjg 		if (vsp->krr.kbd_device == VSE_MOUSE) {
62924495Sjg 		    vsb->vsioa.mouse.x = cur.x;
63024495Sjg 		    vsb->vsioa.mouse.y = cur.y;
63124495Sjg 		}
63224495Sjg 		/* check for room in the queue */
63324495Sjg 		if ((i = EVROUND(vsb->vsioa.itail+1)) == vsb->vsioa.ihead)
63424495Sjg 		    return;
63524495Sjg 		/* put event into queue and do select */
63624495Sjg 		vep = &vsb->ibuff[vsb->vsioa.itail];
63724495Sjg 		vep->vse_type = VSE_BUTTON;
63824495Sjg 		vep->vse_key = vsp->krr.kbd_key;
63924495Sjg 		vep->vse_direction = vsp->krr.kbd_transition;
64024495Sjg 		vep->vse_device = vsp->krr.kbd_device;
64124495Sjg 	        vep->vse_time = mfpr(TODR);
64224495Sjg 		vep->vse_x = vsb->vsioa.mouse.x;
64324495Sjg 		vep->vse_y = vsb->vsioa.mouse.y;
64424495Sjg 		vsb->vsioa.itail = i;
64524495Sjg 		if (vsp->rsel) {
64624495Sjg 			selwakeup(vsp->rsel, 0);
64724495Sjg 			vsp->rsel = 0;
64824495Sjg 		}
64924495Sjg 		break;
65024495Sjg 
65124495Sjg 	case VS_INT_TM:			/* tablet moved */
65224495Sjg 		if (!vsp->open)
65324495Sjg 			return;		/* ignore on closed device */
65424495Sjg 
65524495Sjg 		if (EVROUND(vsb->vsioa.itail+1) == vsb->vsioa.ihead)
65624495Sjg 		    return;
65724495Sjg 		i = EVROUND(vsb->vsioa.itail-1);
65824495Sjg 		if ((vsb->vsioa.itail != vsb->vsioa.ihead) &&
65924495Sjg 		    (i != vsb->vsioa.ihead)) {
66024495Sjg 		    vep = &vsb->ibuff[i];
66124495Sjg 		    if (vep->vse_type == VSE_TMOTION) {
66224495Sjg 			vep->vse_x = cur.x;
66324495Sjg 			vep->vse_y = cur.y;
66424495Sjg 			vep->vse_time = mfpr(TODR);
66524495Sjg 			return;
66624495Sjg 		    }
66724495Sjg 		}
66824495Sjg 		/* put event into queue and do select */
66924495Sjg 		vep = &vsb->ibuff[vsb->vsioa.itail];
67024495Sjg 		vep->vse_type = VSE_TMOTION;
67124495Sjg 		vep->vse_x = cur.x;
67224495Sjg 		vep->vse_y = cur.y;
67324495Sjg 		vep->vse_time = mfpr(TODR);
67424495Sjg 		vsb->vsioa.itail = EVROUND(vsb->vsioa.itail+1);
67524495Sjg 		if (vsp->rsel) {
67624495Sjg 			selwakeup(vsp->rsel, 0);
67724495Sjg 			vsp->rsel = 0;
67824495Sjg 		}
67924495Sjg 		break;
68024495Sjg 
68124495Sjg 	case VS_INT_US:			/* unsolicited */
68224495Sjg 		vsp->stats.unsolIntr++;
68324495Sjg 		return;
68424495Sjg 
68524495Sjg 	case VS_INT_ID:			/* Initialization done */
68624495Sjg 					/* save offset from device */
68724495Sjg 		vsp->offset.fparm_all = vsp->pr.fparm_all;
68824495Sjg 					/* save rom version */
68924495Sjg 		vsp->romVersion = cur.x;
69024495Sjg 		vsp->inited = TRUE;
69124495Sjg 		break;
69224495Sjg 
69324495Sjg 	case VS_INT_SE:			/* ucode started */
69424495Sjg 		break;
69524495Sjg 
69624495Sjg 	case VS_INT_PWR:		/* power up complete */
69724495Sjg 					/* save rom version */
69824495Sjg 		vsp->romVersion = cur.x;
69924495Sjg 		vsp->inited = FALSE;
70024495Sjg 		if (vsp->open && vsp->pgrp)
70124495Sjg 			gsignal(vsp->pgrp, SIGHUP);
70224495Sjg 		break;
70324495Sjg 
70424495Sjg 	default:
70524495Sjg 		printI("vs%d: unknown interrupt %b\n", VSUNIT(dev),
70624495Sjg 			vsp->irr.intr_reason, VSIRR_BITS);
70724495Sjg 		return;
70824495Sjg 	}
70924495Sjg 	wakeup((caddr_t) vsp);
71024495Sjg }
71124495Sjg 
vsreset(uban)71224495Sjg vsreset(uban)
71324495Sjg int uban;
71424495Sjg {
71524495Sjg 	register int i;
71624495Sjg 	register struct uba_device *uip;
71724495Sjg 	register struct vs_softc *vsp = vs_softc;
71824495Sjg 
71924495Sjg 	for (i = 0; i < NVS; i++, vsp++) {
72024495Sjg 		if ((uip = vsdinfo[i]) == 0 || uip->ui_alive == 0 ||
72124495Sjg 		    uip->ui_ubanum != uban || vsp->open == 0)
72224495Sjg 			continue;
72324495Sjg 		printf(" vs%d", i);
72424495Sjg 		vsp->inited = FALSE;
72524495Sjg 		if (vsp->open && vsp->pgrp)
72624495Sjg 			gsignal(vsp->pgrp, SIGHUP);
72724495Sjg 	}
72824495Sjg }
72924495Sjg 
vsselect(dev,rw)73024495Sjg vsselect(dev, rw)
73124495Sjg dev_t dev;
73224495Sjg {
73324495Sjg 	register struct vsBuffArea *vsb = &vsBuff[VSUNIT(dev)];
73424495Sjg 	int s = spl5();
73524495Sjg 
73624495Sjg 	switch(rw) {
73724495Sjg 	case FREAD:
73824495Sjg 		if (vsb->vsioa.ihead != vsb->vsioa.itail) {
73924495Sjg 		    splx(s);
74024495Sjg 		    return(1);
74124495Sjg 		}
74224495Sjg 		vs_softc[VSUNIT(dev)].rsel = u.u_procp;
74324495Sjg 		splx(s);
74424495Sjg 		return(0);
74524495Sjg 
74643381Skarels 	default:
74724495Sjg 		splx(s);
74843381Skarels 		return(0);	/* can never write */
74924495Sjg 	}
75024495Sjg }
75124495Sjg 
75224495Sjg /*
75324495Sjg  * Initialize VS100 or SBO.
75424495Sjg  * Set XMITON.  VS100 will respond with link available.  SBO won't, so
75524495Sjg  * don't wait forever; assume everything is OK and warn user.
75624495Sjg  */
75724495Sjg 
vsInitFiber(dev)75824495Sjg vsInitFiber(dev)
75924495Sjg dev_t dev;
76024495Sjg {
76124495Sjg 	struct vsdevice *vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr;
76224495Sjg 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
76340818Smarc 	int s, error;
76424495Sjg 
76524495Sjg 	s = spl5();
76624495Sjg 	vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);	/* turn link on */
76740818Smarc 	error = tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_INITF, 2*hz);
76824495Sjg 	splx(s);
76940818Smarc 	if (error == EWOULDBLOCK)	/* timeout */
77040818Smarc 		error = 0;
77124495Sjg #ifdef VSSBO
77224495Sjg 	if (!vsp->linkAvail) {
77324495Sjg 		uprintf("\007This had better be a vs125!\n");
77424495Sjg 		printf("vs%d must be a vs125\n", VSUNIT(dev));
77524495Sjg 		vsp->linkAvail = TRUE;
77624495Sjg 	}
77724495Sjg #endif
77840818Smarc 	return (error);
77924495Sjg }
78024495Sjg 
vsInitDev(dev,retry)78124495Sjg vsInitDev(dev, retry)
78224495Sjg dev_t dev;
78324495Sjg int retry;
78424495Sjg {
78524495Sjg 	register struct vsdevice *vsaddr;
78624495Sjg 	register struct vs_softc *vsp;
78740818Smarc 	int s, error;
78824495Sjg 
78924495Sjg 	vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr;
79024495Sjg 	vsp = &vs_softc[VSUNIT(dev)];
79124495Sjg 
79224495Sjg 	if (!vsp->linkAvail)
79340818Smarc 		if (error = vsInitFiber(dev))
79440818Smarc 			return (error);
79524495Sjg 	while (1) {
79624495Sjg 		s = spl5();
79724495Sjg 		vsaddr->vs_irr = 0;
79824495Sjg 		vsaddr->vs_csr0 &= ~VS_FCN;
79924495Sjg 		vsaddr->vs_csr0 |= (VS_IE | (VS_INIT << VS_FCSHIFT) | VS_GO);
80040818Smarc 		error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH,
80140818Smarc 		    devwait, retry ? 10*hz : 0);
80224495Sjg 		splx(s);
80340818Smarc 		if (error == EWOULDBLOCK)
80440818Smarc 			error = 0;
80540818Smarc 		if (error)
80640818Smarc 			return (error);
80724495Sjg 		if (vsp->inited)
80824495Sjg 			break;
80924495Sjg 		printM("vs%d: VS_INIT fails\n", VSUNIT(dev));
81024495Sjg 		uprintf("vsInitDev %x %x\n",vsaddr->vs_csr0, vsaddr->vs_csr1);
81124495Sjg 	}
81240818Smarc 	return (0);
81324495Sjg }
81424495Sjg 
vsError(vsp)81524495Sjg vsError(vsp)
81624495Sjg 	register struct vs_softc *vsp;
81724495Sjg {
81824495Sjg 	if (vsp->irr.intr_error) {
81924495Sjg 		register int ret = vsp->irr.intr_reg;
82024495Sjg 
82124495Sjg 		printD("\treturning 0x%x\n", ret);
82224495Sjg 		vsp->irr.intr_reg = 0;
82324495Sjg 		return(ret+128);
82424495Sjg 	}
82524495Sjg 	return(0);
82624495Sjg }
82724495Sjg #endif
82824495Sjg 
829