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