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