1*40818Smarc /* @(#)vs.c 7.6 (MIT) 04/05/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 2737511Smckusick #include "machine/pte.h" 2824495Sjg 2924495Sjg #include "param.h" 3024495Sjg #include "user.h" 3124495Sjg #include "buf.h" 3224495Sjg #include "systm.h" 3324495Sjg #include "map.h" 3424495Sjg #include "kernel.h" 3524495Sjg #include "ioctl.h" 3624495Sjg 3724495Sjg #include "vsio.h" 3824495Sjg 3924495Sjg #include "proc.h" 4024495Sjg #include "uio.h" 4124495Sjg #include "vmmac.h" 4224495Sjg #include "file.h" 4324495Sjg 4424495Sjg #include "ubareg.h" 4524495Sjg #include "ubavar.h" 4624495Sjg #include "vsreg.h" 4724495Sjg 4824495Sjg #include "../vax/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 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 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)) { 193*40818Smarc ret = vsInitDev(dev, TRUE); 194*40818Smarc if (ret) 195*40818Smarc 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 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 286*40818Smarc return (0); 28724495Sjg } 28824495Sjg 28924495Sjg vsread(dev,uio) 29024495Sjg dev_t dev; 29124495Sjg struct uio *uio; 29224495Sjg { 29324495Sjg return(-1); 29424495Sjg } 29524495Sjg 29624495Sjg vswrite(dev, uio) 29724495Sjg dev_t dev; 29824495Sjg struct uio *uio; 29924495Sjg { 30024495Sjg return(-1); 30124495Sjg } 30224495Sjg 30324495Sjg /*ARGSUSED*/ 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; 313*40818Smarc 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 { 324*40818Smarc error = tsleep((caddr_t)vsp, VSWAITPRI | PCATCH, 325*40818Smarc devwait, 0); 326*40818Smarc } 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); 336*40818Smarc if (error) 337*40818Smarc 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) { 346*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, 347*40818Smarc devio, 0); 34824495Sjg } 34924495Sjg splx(s); 350*40818Smarc 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 */ 389*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0); 39024495Sjg splx(s); 391*40818Smarc if (error) 392*40818Smarc 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); 400*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0); 40124495Sjg splx(s); 402*40818Smarc if (error) 403*40818Smarc 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); 411*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0); 41224495Sjg splx(s); 413*40818Smarc if (error) 414*40818Smarc 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); 423*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0); 42424495Sjg splx(s); 425*40818Smarc if (error) 426*40818Smarc 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); 435*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0); 43624495Sjg splx(s); 437*40818Smarc if (error) 438*40818Smarc 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); 447*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, devwait, 0); 44824495Sjg splx(s); 449*40818Smarc if (error) 450*40818Smarc 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 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 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 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 74624495Sjg case FWRITE: 74724495Sjg splx(s); 74824495Sjg return(EACCES); 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 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)]; 763*40818Smarc int s, error; 76424495Sjg 76524495Sjg s = spl5(); 76624495Sjg vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON); /* turn link on */ 767*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_INITF, 2*hz); 76824495Sjg splx(s); 769*40818Smarc if (error == EWOULDBLOCK) /* timeout */ 770*40818Smarc 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 778*40818Smarc return (error); 77924495Sjg } 78024495Sjg 78124495Sjg vsInitDev(dev, retry) 78224495Sjg dev_t dev; 78324495Sjg int retry; 78424495Sjg { 78524495Sjg register struct vsdevice *vsaddr; 78624495Sjg register struct vs_softc *vsp; 787*40818Smarc int s, error; 78824495Sjg 78924495Sjg vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr; 79024495Sjg vsp = &vs_softc[VSUNIT(dev)]; 79124495Sjg 79224495Sjg if (!vsp->linkAvail) 793*40818Smarc if (error = vsInitFiber(dev)) 794*40818Smarc 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); 800*40818Smarc error = tsleep((caddr_t) vsp, VSWAITPRI | PCATCH, 801*40818Smarc devwait, retry ? 10*hz : 0); 80224495Sjg splx(s); 803*40818Smarc if (error == EWOULDBLOCK) 804*40818Smarc error = 0; 805*40818Smarc if (error) 806*40818Smarc 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 } 812*40818Smarc return (0); 81324495Sjg } 81424495Sjg 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