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