1*24495Sjg /* @(#)vs.c 1.1 (MIT) 08/30/85 */ 2*24495Sjg /**************************************************************************** 3*24495Sjg * * 4*24495Sjg * Copyright (c) 1983, 1984 by * 5*24495Sjg * DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts. * 6*24495Sjg * All rights reserved. * 7*24495Sjg * * 8*24495Sjg * This software is furnished on an as-is basis and may be used and copied * 9*24495Sjg * only with inclusion of the above copyright notice. This software or any * 10*24495Sjg * other copies thereof may be provided or otherwise made available to * 11*24495Sjg * others only for non-commercial purposes. No title to or ownership of * 12*24495Sjg * the software is hereby transferred. * 13*24495Sjg * * 14*24495Sjg * The information in this software is subject to change without notice * 15*24495Sjg * and should not be construed as a commitment by DIGITAL EQUIPMENT * 16*24495Sjg * CORPORATION. * 17*24495Sjg * * 18*24495Sjg * DIGITAL assumes no responsibility for the use or reliability of its * 19*24495Sjg * software on equipment which is not supplied by DIGITAL. * 20*24495Sjg * * 21*24495Sjg * * 22*24495Sjg ****************************************************************************/ 23*24495Sjg 24*24495Sjg #include "vs.h" 25*24495Sjg #if NVS > 0 26*24495Sjg 27*24495Sjg #include "../machine/pte.h" 28*24495Sjg 29*24495Sjg #include "param.h" 30*24495Sjg #include "dir.h" 31*24495Sjg #include "user.h" 32*24495Sjg #include "buf.h" 33*24495Sjg #include "systm.h" 34*24495Sjg #include "map.h" 35*24495Sjg #include "kernel.h" 36*24495Sjg #include "ioctl.h" 37*24495Sjg 38*24495Sjg #include "vsio.h" 39*24495Sjg 40*24495Sjg #include "proc.h" 41*24495Sjg #include "uio.h" 42*24495Sjg #include "vmmac.h" 43*24495Sjg #include "file.h" 44*24495Sjg 45*24495Sjg #include "ubareg.h" 46*24495Sjg #include "ubavar.h" 47*24495Sjg #include "vsreg.h" 48*24495Sjg 49*24495Sjg #include "../vax/mtpr.h" 50*24495Sjg 51*24495Sjg #define VSWAITPRI (PZERO+1) 52*24495Sjg #define VSMAXEVQ 64 /* must be power of 2 */ 53*24495Sjg #define EVROUND(x) ((x) & (VSMAXEVQ - 1)) 54*24495Sjg 55*24495Sjg 56*24495Sjg #define VSBUFFSIZE 3072 57*24495Sjg struct vsBuffArea { 58*24495Sjg vsIoAddr vsioa; 59*24495Sjg char obuff[VSBUFFSIZE]; 60*24495Sjg vsEvent ibuff[VSMAXEVQ]; 61*24495Sjg }; 62*24495Sjg struct vsBuffArea vsBuff[NVS]; 63*24495Sjg 64*24495Sjg 65*24495Sjg int vsprobe(), vsattach(); 66*24495Sjg struct uba_device *vsdinfo[NVS]; 67*24495Sjg u_short vsstd[] = { 0 }; 68*24495Sjg struct uba_driver vsdriver = 69*24495Sjg { vsprobe, 0, vsattach, 0, vsstd, "vs", vsdinfo, 0, 0 }; 70*24495Sjg 71*24495Sjg #define VSUNIT(dev) (minor(dev)) 72*24495Sjg 73*24495Sjg struct vs_softc { 74*24495Sjg unsigned inited : 1; /* has this ever been inited? */ 75*24495Sjg unsigned open : 1; /* only one open, please */ 76*24495Sjg unsigned linkAvail : 1; /* link is up */ 77*24495Sjg short pgrp; /* process group for SIGHUP */ 78*24495Sjg int romVersion; /* rom version */ 79*24495Sjg struct vs_fparm offset; /* address base */ 80*24495Sjg struct vs_csr csr; /* saved csr0 */ 81*24495Sjg struct vs_intr irr; /* saved interrupt reason */ 82*24495Sjg struct vs_kbd krr; /* saved keyboard */ 83*24495Sjg struct vs_fparm pr; /* saved parameter regs */ 84*24495Sjg struct proc *rsel; /* process waiting for select */ 85*24495Sjg struct vs_fparm vs_nextgo; /* next packet to go */ 86*24495Sjg short vs_status; /* status from previous packet */ 87*24495Sjg vsStats stats; /* statistics */ 88*24495Sjg int vsBuff_ubinfo; /* ubinfo for vsBuff */ 89*24495Sjg }vs_softc[NVS]; 90*24495Sjg 91*24495Sjg #define TRUE 1 92*24495Sjg #define FALSE 0 93*24495Sjg 94*24495Sjg #define printI if (vsIntrPrintfs)printf 95*24495Sjg #define printD if (vsDebugPrintfs)printf 96*24495Sjg #define printM if (vsMlpPrintfs) vsMlpPrintfs--,printf 97*24495Sjg int vsIntrPrintfs = 0; 98*24495Sjg int vsDebugPrintfs = 0; 99*24495Sjg int vsMlpPrintfs = 0; 100*24495Sjg 101*24495Sjg /* 102*24495Sjg * Tell the system that it's out there, and set up the device's interrupt 103*24495Sjg * vector. Since we are supporting vs100s and vs125s, 104*24495Sjg * this is a bit kludgey. The vs100 works much 105*24495Sjg * as one expects, but the vs125 tries to set all the fiber link 106*24495Sjg * related bits when you hit VS_IE, ignoring the way the 100 works. 107*24495Sjg * Also, the vs100 will let you set the interrupt vector, but 108*24495Sjg * the vs125 ignores this and uses its hard-wired value. 109*24495Sjg * And there's no sure fire to tell which variant it is. 110*24495Sjg * Ugh. Ugh. Ugh. 111*24495Sjg */ 112*24495Sjg 113*24495Sjg vsprobe(reg) 114*24495Sjg caddr_t reg; 115*24495Sjg { 116*24495Sjg register int br, cvec; /* value-result */ 117*24495Sjg register struct vsdevice *vsaddr = (struct vsdevice *)reg; 118*24495Sjg 119*24495Sjg #ifdef lint 120*24495Sjg br = 0; cvec = br; br = cvec; 121*24495Sjg vsintr(0); 122*24495Sjg #endif 123*24495Sjg br = 0x15; 124*24495Sjg cvec = (uba_hd[numuba].uh_lastiv -= 4*8); 125*24495Sjg /* 126*24495Sjg * uh_lastiv is the last free interrupt vector in the 127*24495Sjg * unibus addapter header (uba_hd). 128*24495Sjg */ 129*24495Sjg 130*24495Sjg vsaddr->vs_csr0 = cvec >> 2; /* Save the vector for use on next device */ 131*24495Sjg vsaddr->vs_irr = 0; /* Csr will only be read if irr == 0 */ 132*24495Sjg vsaddr->vs_irr = 0; /* Clear interrupt reason register */ 133*24495Sjg vsaddr->vs_pr1 = 0; /* Clear function parameter */ 134*24495Sjg vsaddr->vs_pr2 = 0; /* Clear function parameter */ 135*24495Sjg vsaddr->vs_ivr = cvec; /* set up vector (no-op for vs125) */ 136*24495Sjg 137*24495Sjg DELAY(100000); 138*24495Sjg if (vsaddr->vs_csr0 & VS_LNK_AVL) 139*24495Sjg return(0); /* light won't go off! */ 140*24495Sjg vsaddr->vs_csr0 &= ~VS_LNK_TRNS; 141*24495Sjg vsaddr->vs_csr0 |= VS_IE; /* enable interrupts */ 142*24495Sjg DELAY(200000); 143*24495Sjg 144*24495Sjg return sizeof(struct vsdevice); 145*24495Sjg } 146*24495Sjg 147*24495Sjg vsattach(uip) 148*24495Sjg struct uba_device *uip; 149*24495Sjg { 150*24495Sjg register struct vs_softc *vsp; 151*24495Sjg register struct vsdevice *vsaddr; 152*24495Sjg 153*24495Sjg vsp = &vs_softc[VSUNIT(uip->ui_unit)]; 154*24495Sjg vsp->inited = FALSE; 155*24495Sjg vsp->open = FALSE; 156*24495Sjg vsBuff[VSUNIT(uip->ui_unit)].vsioa.mbox.bottom = 0; 157*24495Sjg vsp->linkAvail = FALSE; 158*24495Sjg vsp->romVersion = 0; 159*24495Sjg vsp->vs_nextgo.fparm_all = NULL; 160*24495Sjg 161*24495Sjg vsaddr = (struct vsdevice *) uip->ui_addr; 162*24495Sjg vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON); 163*24495Sjg } 164*24495Sjg 165*24495Sjg vsopen(dev, flag) 166*24495Sjg dev_t dev; 167*24495Sjg int flag; 168*24495Sjg { 169*24495Sjg register struct vs_softc *vsp; 170*24495Sjg register struct uba_device *uip; 171*24495Sjg register struct vsdevice *vsaddr; 172*24495Sjg int s; 173*24495Sjg int ret; 174*24495Sjg struct buf vsbuf; 175*24495Sjg struct vsBuffArea *vsb; 176*24495Sjg caddr_t vsBuffpage; 177*24495Sjg int vsBuffnpages; 178*24495Sjg 179*24495Sjg if (VSUNIT(dev) >= NVS || (vsp = &vs_softc[VSUNIT(dev)])->open || 180*24495Sjg (uip = vsdinfo[VSUNIT(dev)]) == 0 || uip->ui_alive == 0) 181*24495Sjg return (ENXIO); 182*24495Sjg 183*24495Sjg vsaddr = (struct vsdevice *) uip->ui_addr; 184*24495Sjg vsb = &vsBuff[VSUNIT(dev)]; 185*24495Sjg printM("vsopen csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n", 186*24495Sjg vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3, 187*24495Sjg vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7); 188*24495Sjg 189*24495Sjg /* 190*24495Sjg * Finally! We can now set up the device. 191*24495Sjg */ 192*24495Sjg 193*24495Sjg if (!vsp->inited && !(flag & FNDELAY)) { 194*24495Sjg vsInitDev(dev, TRUE); 195*24495Sjg if (ret = vsError(vsp)) 196*24495Sjg return(ret); 197*24495Sjg } 198*24495Sjg 199*24495Sjg vsp->open = TRUE; /* we're open */ 200*24495Sjg vsp->pgrp = u.u_procp->p_pgrp; 201*24495Sjg 202*24495Sjg /* reset statistics */ 203*24495Sjg bzero((caddr_t) &vsp->stats, sizeof(vsStats)); 204*24495Sjg 205*24495Sjg /* initialize user I/O addresses */ 206*24495Sjg vsb->vsioa.ioreg = (short *)vsaddr; 207*24495Sjg vsb->vsioa.status = 0; 208*24495Sjg vsb->vsioa.obuff = vsb->obuff; 209*24495Sjg vsb->vsioa.obufflen = VSBUFFSIZE; 210*24495Sjg vsb->vsioa.ibuff = vsb->ibuff; 211*24495Sjg vsb->vsioa.ihead = 0; 212*24495Sjg vsb->vsioa.itail = 0; 213*24495Sjg vsb->vsioa.iqsize = VSMAXEVQ; 214*24495Sjg /* map io regs into user address space (assume they don't cross a page) */ 215*24495Sjg maptouser(vsaddr); 216*24495Sjg /* map vsBuff into user address space */ 217*24495Sjg vsBuffpage = (caddr_t)((int)vsb & ~PGOFSET); 218*24495Sjg vsBuffnpages = (((int)vsb & PGOFSET) + 219*24495Sjg (NBPG-1) + sizeof(struct vsBuffArea)) >> PGSHIFT; 220*24495Sjg while (vsBuffnpages>0) { 221*24495Sjg maptouser(vsBuffpage); 222*24495Sjg vsBuffpage += NBPG; 223*24495Sjg vsBuffnpages--; 224*24495Sjg } 225*24495Sjg /* lock in the buffer */ 226*24495Sjg vsbuf.b_error = 0; 227*24495Sjg vsbuf.b_proc = u.u_procp; 228*24495Sjg vsbuf.b_un.b_addr = vsb->obuff; 229*24495Sjg vsbuf.b_flags = B_BUSY; 230*24495Sjg vsbuf.b_bcount = VSBUFFSIZE; 231*24495Sjg vsp->vsBuff_ubinfo = ubasetup(uip->ui_ubanum, &vsbuf, UBA_CANTWAIT); 232*24495Sjg 233*24495Sjg vsb->vsioa.reloc = (int) (vsp->offset.fparm_all 234*24495Sjg + (vsp->vsBuff_ubinfo & 0x3ffff)); 235*24495Sjg return(0); 236*24495Sjg } 237*24495Sjg 238*24495Sjg vsclose(dev) 239*24495Sjg dev_t dev; 240*24495Sjg { 241*24495Sjg register struct uba_device *uip = vsdinfo[VSUNIT(dev)]; 242*24495Sjg register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)]; 243*24495Sjg int s, i; 244*24495Sjg struct vsdevice *vsaddr; 245*24495Sjg struct vsBuffArea *vsb; 246*24495Sjg caddr_t vsBuffpage; 247*24495Sjg int vsBuffnpages; 248*24495Sjg 249*24495Sjg vsaddr = (struct vsdevice *) uip->ui_addr; 250*24495Sjg printM("vsclose csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n", 251*24495Sjg vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3, 252*24495Sjg vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7); 253*24495Sjg vsb = &vsBuff[VSUNIT(dev)]; 254*24495Sjg if (vsDebugPrintfs) { 255*24495Sjg printf("vs%d: %d errors, %d unsolicited interrupts", 256*24495Sjg VSUNIT(dev), vsp->stats.errors, vsp->stats.unsolIntr); 257*24495Sjg printf(", %d link errors", vsp->stats.linkErrors); 258*24495Sjg printf(", %d overruns", vsp->stats.overruns); 259*24495Sjg printf(", csr0 %x, csr1 %x", vsaddr->vs_csr0, vsaddr->vs_csr1); 260*24495Sjg printf("\n"); 261*24495Sjg } 262*24495Sjg 263*24495Sjg vsp->open = FALSE; 264*24495Sjg vsp->inited = FALSE; /* init on every open */ 265*24495Sjg vsp->vs_nextgo.fparm_all = NULL; 266*24495Sjg vsb->vsioa.mbox.bottom = 0; 267*24495Sjg /* release the buffer */ 268*24495Sjg if (vsp->vsBuff_ubinfo!=0) { 269*24495Sjg ubarelse(uip->ui_ubanum, &vsp->vsBuff_ubinfo); 270*24495Sjg } 271*24495Sjg 272*24495Sjg #ifdef notdef 273*24495Sjg /* unmap io regs into user address space (assume they don't cross a page) */ 274*24495Sjg unmaptouser(vsaddr); 275*24495Sjg /* unmap vsBuff into user address space */ 276*24495Sjg vsBuffpage = (caddr_t)((int)vsb & ~PGOFSET); 277*24495Sjg vsBuffnpages = (((int)vsb&PGOFSET) + 278*24495Sjg (NBPG-1)+ sizeof(struct vsBuffArea)) >> PGSHIFT; 279*24495Sjg while (vsBuffnpages>0) { 280*24495Sjg unmaptouser(vsBuffpage); 281*24495Sjg vsBuffpage += NBPG; 282*24495Sjg vsBuffnpages--; 283*24495Sjg } 284*24495Sjg #endif 285*24495Sjg } 286*24495Sjg 287*24495Sjg vsread(dev,uio) 288*24495Sjg dev_t dev; 289*24495Sjg struct uio *uio; 290*24495Sjg { 291*24495Sjg return(-1); 292*24495Sjg } 293*24495Sjg 294*24495Sjg vswrite(dev, uio) 295*24495Sjg dev_t dev; 296*24495Sjg struct uio *uio; 297*24495Sjg { 298*24495Sjg return(-1); 299*24495Sjg } 300*24495Sjg 301*24495Sjg /*ARGSUSED*/ 302*24495Sjg vsioctl(dev, cmd, addr, flag) 303*24495Sjg dev_t dev; 304*24495Sjg register caddr_t addr; 305*24495Sjg { 306*24495Sjg register struct uba_device *uip = vsdinfo[VSUNIT(dev)]; 307*24495Sjg register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)]; 308*24495Sjg register struct vsdevice *vsaddr = (struct vsdevice *) uip->ui_addr; 309*24495Sjg register struct vsBuffArea *vsb = &vsBuff[VSUNIT(dev)]; 310*24495Sjg struct vs_fparm vsAddr; 311*24495Sjg int s; 312*24495Sjg int func; 313*24495Sjg int ret; 314*24495Sjg 315*24495Sjg switch(cmd) { /* things that don't need the device */ 316*24495Sjg case VSIOWAITGO: 317*24495Sjg /* wait for user I/O operation to complete, then go */ 318*24495Sjg s = spl5(); 319*24495Sjg if ((ret = vsb->vsioa.status) == 0) { 320*24495Sjg vsp->vs_nextgo.fparm_all = ((struct vs_fparm *) addr)->fparm_all; 321*24495Sjg do { 322*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 323*24495Sjg } while (vsp->vs_nextgo.fparm_all); 324*24495Sjg ret = vsp->vs_status; 325*24495Sjg } else { 326*24495Sjg vsaddr->vs_pr1 = ((struct vs_fparm *)addr)->fparm_low; 327*24495Sjg vsaddr->vs_pr2 = ((struct vs_fparm *)addr)->fparm_high; 328*24495Sjg vsb->vsioa.status = 0; 329*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; /* clear bits */ 330*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO); 331*24495Sjg } 332*24495Sjg splx(s); 333*24495Sjg if (ret & VS_ERROR) 334*24495Sjg return ((ret & VS_REASON) + 128); 335*24495Sjg return(0); 336*24495Sjg 337*24495Sjg case VSIOUSERWAIT: 338*24495Sjg /* wait for user I/O operation to complete */ 339*24495Sjg s = spl5(); 340*24495Sjg while (vsb->vsioa.status == 0) { 341*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 342*24495Sjg } 343*24495Sjg splx(s); 344*24495Sjg return (0); 345*24495Sjg 346*24495Sjg case VSIOGETVER: /* get ROM version */ 347*24495Sjg if (!vsp->inited) 348*24495Sjg return(ENODEV); 349*24495Sjg *(int *) addr = vsp->romVersion; 350*24495Sjg return(0); 351*24495Sjg 352*24495Sjg case VSIOGETSTATS: /* get statistics block */ 353*24495Sjg *(vsStats *)addr = vsp->stats; 354*24495Sjg return(0); 355*24495Sjg 356*24495Sjg case VSIOGETIOA: /* get io addresses */ 357*24495Sjg if (vsp->vsBuff_ubinfo==0) { 358*24495Sjg return(EIO); 359*24495Sjg } 360*24495Sjg *((vsIoAddrAddr *)addr) = &vsb->vsioa; 361*24495Sjg return(0); 362*24495Sjg 363*24495Sjg default: /* a command that could block */ 364*24495Sjg if (ret = vsError(vsp)) 365*24495Sjg return(ret); 366*24495Sjg break; 367*24495Sjg } 368*24495Sjg 369*24495Sjg switch(cmd) { /* Commands that cause an interrupt */ 370*24495Sjg case VSIOINIT: /* initialize device */ 371*24495Sjg vsInitDev(dev, FALSE); 372*24495Sjg return(vsError(vsp)); 373*24495Sjg 374*24495Sjg case VSIOSTART: /* start microcode */ 375*24495Sjg vsAddr.fparm_all = *(caddr_t *)addr; 376*24495Sjg s = spl5(); 377*24495Sjg vsaddr->vs_pr1 = vsAddr.fparm_low; 378*24495Sjg vsaddr->vs_pr2 = vsAddr.fparm_high; 379*24495Sjg vsaddr->vs_irr = 0; 380*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; /* clear bits */ 381*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (VS_START << VS_FCSHIFT) | VS_GO); 382*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); /* synchronous */ 383*24495Sjg splx(s); 384*24495Sjg return(vsError(vsp)); 385*24495Sjg 386*24495Sjg case VSIOABORT: /* abort a command chain */ 387*24495Sjg s = spl5(); 388*24495Sjg vsaddr->vs_irr = 0; 389*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; 390*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (VS_ABORT << VS_FCSHIFT) | VS_GO); 391*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 392*24495Sjg splx(s); 393*24495Sjg return(vsError(vsp)); 394*24495Sjg 395*24495Sjg case VSIOPWRUP: /* power-up reset */ 396*24495Sjg s = spl5(); 397*24495Sjg vsaddr->vs_irr = 0; 398*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; 399*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (VS_PWRUP << VS_FCSHIFT) | VS_GO); 400*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 401*24495Sjg splx(s); 402*24495Sjg return(vsError(vsp)); 403*24495Sjg 404*24495Sjg case VSIOBBACTL: /* enable/disable BBA */ 405*24495Sjg s = spl5(); 406*24495Sjg vsaddr->vs_irr = 0; 407*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; 408*24495Sjg func = *(int *)addr == VSIO_ON ? VS_ENABBA : VS_DISBBA; 409*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (func << VS_FCSHIFT) | VS_GO); 410*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 411*24495Sjg splx(s); 412*24495Sjg return(vsError(vsp)); 413*24495Sjg 414*24495Sjg case VSIOFIBCTL: /* turn the fiber lamp on/off */ 415*24495Sjg s = spl5(); 416*24495Sjg if (*(int *)addr == VSIO_OFF) 417*24495Sjg vsaddr->vs_csr0 &= ~VS_XMIT_ON; 418*24495Sjg else 419*24495Sjg vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON); 420*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 421*24495Sjg splx(s); 422*24495Sjg return(vsError(vsp)); 423*24495Sjg 424*24495Sjg case VSIOFIBRETRY: /* set fiber retries */ 425*24495Sjg s = spl5(); 426*24495Sjg vsaddr->vs_irr = 0; 427*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; 428*24495Sjg func = *(int *)addr == VS_FIB_FINITE ? VS_FINITE : VS_INFINITE; 429*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (func << VS_FCSHIFT) | VS_GO); 430*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 431*24495Sjg splx(s); 432*24495Sjg return(vsError(vsp)); 433*24495Sjg 434*24495Sjg case VSIOSYNC: /* get synchronized with device */ 435*24495Sjg break; 436*24495Sjg 437*24495Sjg default: 438*24495Sjg return(ENOTTY); 439*24495Sjg } 440*24495Sjg 441*24495Sjg return(0); 442*24495Sjg } 443*24495Sjg 444*24495Sjg vsintr(dev) 445*24495Sjg dev_t dev; 446*24495Sjg { 447*24495Sjg register struct vsdevice *vsaddr; 448*24495Sjg register struct vs_softc *vsp; 449*24495Sjg register vsEvent *vep; 450*24495Sjg struct uba_device *uip; 451*24495Sjg register struct vsBuffArea *vsb; 452*24495Sjg int i; 453*24495Sjg vsCursor cur; 454*24495Sjg 455*24495Sjg if (VSUNIT(dev) >= NVS || (uip = vsdinfo[VSUNIT(dev)]) == 0 456*24495Sjg || uip->ui_alive == 0) { 457*24495Sjg printI("vs%d stray interrupt\n", VSUNIT(dev)); 458*24495Sjg return; 459*24495Sjg } 460*24495Sjg 461*24495Sjg vsaddr = (struct vsdevice *) uip->ui_addr; 462*24495Sjg vsp = &vs_softc[VSUNIT(dev)]; 463*24495Sjg vsb = &vsBuff[VSUNIT(dev)]; 464*24495Sjg #ifdef notdef 465*24495Sjg printM("vsintr csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n", 466*24495Sjg vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3, 467*24495Sjg vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7); 468*24495Sjg 469*24495Sjg printI("vs%dintr ", VSUNIT(dev)); 470*24495Sjg #endif 471*24495Sjg 472*24495Sjg /* 473*24495Sjg * get the information out of the soft registers 474*24495Sjg */ 475*24495Sjg 476*24495Sjg vsp->irr.intr_reg = vsaddr->vs_irr; 477*24495Sjg vsp->krr.kbd_reg = vsaddr->vs_krr; 478*24495Sjg vsp->pr.fparm_low = vsaddr->vs_pr1; 479*24495Sjg vsp->pr.fparm_high = vsaddr->vs_pr2; 480*24495Sjg cur.x = vsaddr->vs_cxr; 481*24495Sjg cur.y = vsaddr->vs_cyr; 482*24495Sjg vsp->csr.csr_reg = vsaddr->vs_csr0; 483*24495Sjg 484*24495Sjg if (vsp->irr.intr_reason) 485*24495Sjg vsaddr->vs_irr = 0; /* clear int reason, if any */ 486*24495Sjg 487*24495Sjg vsaddr->vs_csr0 &= ~VS_OWN; /* clear owner bit */ 488*24495Sjg 489*24495Sjg if (vsp->csr.csr_linkTran) { 490*24495Sjg vsaddr->vs_csr0 &= ~VS_LNK_TRNS; /* clear the bit */ 491*24495Sjg printI("link transition: "); 492*24495Sjg if (vsp->csr.csr_linkErr) 493*24495Sjg vsp->stats.linkErrors++; 494*24495Sjg 495*24495Sjg if (vsp->csr.csr_linkAvail == vsp->linkAvail) { /* flash */ 496*24495Sjg vsp->stats.flashes++; 497*24495Sjg printI("flash\n"); 498*24495Sjg } else if (!vsp->csr.csr_linkAvail && vsp->linkAvail) { /* on -> off */ 499*24495Sjg vsp->stats.douses++; 500*24495Sjg printI("douse\n"); 501*24495Sjg vsp->inited = FALSE; 502*24495Sjg if (vsp->open && vsp->pgrp) 503*24495Sjg gsignal(vsp->pgrp, SIGHUP); 504*24495Sjg wakeup((caddr_t) vsp); 505*24495Sjg } else { /* off -> on */ 506*24495Sjg vsp->stats.ignites++; 507*24495Sjg printI("ignite\n"); 508*24495Sjg wakeup((caddr_t) vsp); 509*24495Sjg } 510*24495Sjg 511*24495Sjg i = 200; 512*24495Sjg while ((vsaddr->vs_csr0 & VS_LNK_TRNS) && i) 513*24495Sjg i--; 514*24495Sjg if (i == 0) { /* bit stuck */ 515*24495Sjg printI("vs%d: Link Transition bit stuck\n", VSUNIT(dev)); 516*24495Sjg vsp->inited = FALSE; 517*24495Sjg if (vsp->open && vsp->pgrp) 518*24495Sjg gsignal(vsp->pgrp, SIGHUP); 519*24495Sjg vsaddr->vs_csr0 &= ~VS_XMIT_ON; 520*24495Sjg vsp->csr.csr_linkAvail = FALSE; 521*24495Sjg } 522*24495Sjg 523*24495Sjg vsp->linkAvail = vsp->csr.csr_linkAvail; 524*24495Sjg 525*24495Sjg return; 526*24495Sjg } 527*24495Sjg 528*24495Sjg if (vsp->irr.intr_error) { 529*24495Sjg printI("error 0x%x\n", vsp->irr.intr_reg&0xffff); 530*24495Sjg vsp->stats.errors++; 531*24495Sjg /* set status and wake up user if necessary */ 532*24495Sjg if (vsp->vs_nextgo.fparm_all) { 533*24495Sjg vsp->vs_status = vsp->irr.intr_reg; 534*24495Sjg vsaddr->vs_pr1 = vsp->vs_nextgo.fparm_low; 535*24495Sjg vsaddr->vs_pr2 = vsp->vs_nextgo.fparm_high; 536*24495Sjg vsp->vs_nextgo.fparm_all = NULL; 537*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; /* clear bits */ 538*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO); 539*24495Sjg } else 540*24495Sjg vsb->vsioa.status = vsp->irr.intr_reg; 541*24495Sjg wakeup((caddr_t) vsp); 542*24495Sjg return; 543*24495Sjg } 544*24495Sjg 545*24495Sjg #ifdef notdef 546*24495Sjg printI("reason is %b\n", vsp->irr.intr_reason, VSIRR_BITS); 547*24495Sjg #endif 548*24495Sjg switch(vsp->irr.intr_reason) { 549*24495Sjg case VS_INT_CD: /* command done */ 550*24495Sjg /* set status and start a new command if necessary */ 551*24495Sjg if (vsp->vs_nextgo.fparm_all) { 552*24495Sjg vsp->vs_status = vsp->irr.intr_reg; 553*24495Sjg vsaddr->vs_pr1 = vsp->vs_nextgo.fparm_low; 554*24495Sjg vsaddr->vs_pr2 = vsp->vs_nextgo.fparm_high; 555*24495Sjg vsp->vs_nextgo.fparm_all = NULL; 556*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; /* clear bits */ 557*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO); 558*24495Sjg } else 559*24495Sjg vsb->vsioa.status = vsp->irr.intr_reg; 560*24495Sjg break; 561*24495Sjg 562*24495Sjg case VS_INT_MM: /* mouse moved */ 563*24495Sjg 564*24495Sjg vsb->vsioa.mouse = cur; 565*24495Sjg 566*24495Sjg if (!vsp->open) 567*24495Sjg return; /* ignore on closed device */ 568*24495Sjg 569*24495Sjg /* no event if inside box */ 570*24495Sjg if (cur.y < vsb->vsioa.mbox.bottom && 571*24495Sjg cur.y >= vsb->vsioa.mbox.top && 572*24495Sjg cur.x < vsb->vsioa.mbox.right && 573*24495Sjg cur.x >= vsb->vsioa.mbox.left) 574*24495Sjg return; 575*24495Sjg 576*24495Sjg /* trash box */ 577*24495Sjg vsb->vsioa.mbox.bottom = 0; 578*24495Sjg 579*24495Sjg if (EVROUND(vsb->vsioa.itail+1) == vsb->vsioa.ihead) 580*24495Sjg return; 581*24495Sjg i = EVROUND(vsb->vsioa.itail-1); 582*24495Sjg if ((vsb->vsioa.itail != vsb->vsioa.ihead) && 583*24495Sjg (i != vsb->vsioa.ihead)) { 584*24495Sjg vep = &vsb->ibuff[i]; 585*24495Sjg if (vep->vse_type == VSE_MMOTION) { 586*24495Sjg vep->vse_x = cur.x; 587*24495Sjg vep->vse_y = cur.y; 588*24495Sjg vep->vse_time = mfpr(TODR); 589*24495Sjg return; 590*24495Sjg } 591*24495Sjg } 592*24495Sjg /* put event into queue and do select */ 593*24495Sjg vep = &vsb->ibuff[vsb->vsioa.itail]; 594*24495Sjg vep->vse_type = VSE_MMOTION; 595*24495Sjg vep->vse_x = cur.x; 596*24495Sjg vep->vse_y = cur.y; 597*24495Sjg vep->vse_time = mfpr(TODR); 598*24495Sjg vsb->vsioa.itail = EVROUND(vsb->vsioa.itail+1); 599*24495Sjg if (vsp->rsel) { 600*24495Sjg selwakeup(vsp->rsel, 0); 601*24495Sjg vsp->rsel = 0; 602*24495Sjg } 603*24495Sjg break; 604*24495Sjg 605*24495Sjg case VS_INT_BE: /* button event */ 606*24495Sjg if (!vsp->open) 607*24495Sjg return; /* ignore on closed device */ 608*24495Sjg 609*24495Sjg if (vsp->krr.kbd_device == VSE_MOUSE) { 610*24495Sjg vsb->vsioa.mouse.x = cur.x; 611*24495Sjg vsb->vsioa.mouse.y = cur.y; 612*24495Sjg } 613*24495Sjg /* check for room in the queue */ 614*24495Sjg if ((i = EVROUND(vsb->vsioa.itail+1)) == vsb->vsioa.ihead) 615*24495Sjg return; 616*24495Sjg /* put event into queue and do select */ 617*24495Sjg vep = &vsb->ibuff[vsb->vsioa.itail]; 618*24495Sjg vep->vse_type = VSE_BUTTON; 619*24495Sjg vep->vse_key = vsp->krr.kbd_key; 620*24495Sjg vep->vse_direction = vsp->krr.kbd_transition; 621*24495Sjg vep->vse_device = vsp->krr.kbd_device; 622*24495Sjg vep->vse_time = mfpr(TODR); 623*24495Sjg vep->vse_x = vsb->vsioa.mouse.x; 624*24495Sjg vep->vse_y = vsb->vsioa.mouse.y; 625*24495Sjg vsb->vsioa.itail = i; 626*24495Sjg if (vsp->rsel) { 627*24495Sjg selwakeup(vsp->rsel, 0); 628*24495Sjg vsp->rsel = 0; 629*24495Sjg } 630*24495Sjg break; 631*24495Sjg 632*24495Sjg case VS_INT_TM: /* tablet moved */ 633*24495Sjg if (!vsp->open) 634*24495Sjg return; /* ignore on closed device */ 635*24495Sjg 636*24495Sjg if (EVROUND(vsb->vsioa.itail+1) == vsb->vsioa.ihead) 637*24495Sjg return; 638*24495Sjg i = EVROUND(vsb->vsioa.itail-1); 639*24495Sjg if ((vsb->vsioa.itail != vsb->vsioa.ihead) && 640*24495Sjg (i != vsb->vsioa.ihead)) { 641*24495Sjg vep = &vsb->ibuff[i]; 642*24495Sjg if (vep->vse_type == VSE_TMOTION) { 643*24495Sjg vep->vse_x = cur.x; 644*24495Sjg vep->vse_y = cur.y; 645*24495Sjg vep->vse_time = mfpr(TODR); 646*24495Sjg return; 647*24495Sjg } 648*24495Sjg } 649*24495Sjg /* put event into queue and do select */ 650*24495Sjg vep = &vsb->ibuff[vsb->vsioa.itail]; 651*24495Sjg vep->vse_type = VSE_TMOTION; 652*24495Sjg vep->vse_x = cur.x; 653*24495Sjg vep->vse_y = cur.y; 654*24495Sjg vep->vse_time = mfpr(TODR); 655*24495Sjg vsb->vsioa.itail = EVROUND(vsb->vsioa.itail+1); 656*24495Sjg if (vsp->rsel) { 657*24495Sjg selwakeup(vsp->rsel, 0); 658*24495Sjg vsp->rsel = 0; 659*24495Sjg } 660*24495Sjg break; 661*24495Sjg 662*24495Sjg case VS_INT_US: /* unsolicited */ 663*24495Sjg vsp->stats.unsolIntr++; 664*24495Sjg return; 665*24495Sjg 666*24495Sjg case VS_INT_ID: /* Initialization done */ 667*24495Sjg /* save offset from device */ 668*24495Sjg vsp->offset.fparm_all = vsp->pr.fparm_all; 669*24495Sjg /* save rom version */ 670*24495Sjg vsp->romVersion = cur.x; 671*24495Sjg vsp->inited = TRUE; 672*24495Sjg break; 673*24495Sjg 674*24495Sjg case VS_INT_SE: /* ucode started */ 675*24495Sjg break; 676*24495Sjg 677*24495Sjg case VS_INT_PWR: /* power up complete */ 678*24495Sjg /* save rom version */ 679*24495Sjg vsp->romVersion = cur.x; 680*24495Sjg vsp->inited = FALSE; 681*24495Sjg if (vsp->open && vsp->pgrp) 682*24495Sjg gsignal(vsp->pgrp, SIGHUP); 683*24495Sjg break; 684*24495Sjg 685*24495Sjg default: 686*24495Sjg printI("vs%d: unknown interrupt %b\n", VSUNIT(dev), 687*24495Sjg vsp->irr.intr_reason, VSIRR_BITS); 688*24495Sjg return; 689*24495Sjg } 690*24495Sjg wakeup((caddr_t) vsp); 691*24495Sjg } 692*24495Sjg 693*24495Sjg vsreset(uban) 694*24495Sjg int uban; 695*24495Sjg { 696*24495Sjg register int i; 697*24495Sjg register struct uba_device *uip; 698*24495Sjg register struct vs_softc *vsp = vs_softc; 699*24495Sjg 700*24495Sjg for (i = 0; i < NVS; i++, vsp++) { 701*24495Sjg if ((uip = vsdinfo[i]) == 0 || uip->ui_alive == 0 || 702*24495Sjg uip->ui_ubanum != uban || vsp->open == 0) 703*24495Sjg continue; 704*24495Sjg printf(" vs%d", i); 705*24495Sjg vsp->inited = FALSE; 706*24495Sjg if (vsp->open && vsp->pgrp) 707*24495Sjg gsignal(vsp->pgrp, SIGHUP); 708*24495Sjg } 709*24495Sjg } 710*24495Sjg 711*24495Sjg vsselect(dev, rw) 712*24495Sjg dev_t dev; 713*24495Sjg { 714*24495Sjg register struct vsBuffArea *vsb = &vsBuff[VSUNIT(dev)]; 715*24495Sjg int s = spl5(); 716*24495Sjg 717*24495Sjg switch(rw) { 718*24495Sjg case FREAD: 719*24495Sjg if (vsb->vsioa.ihead != vsb->vsioa.itail) { 720*24495Sjg splx(s); 721*24495Sjg return(1); 722*24495Sjg } 723*24495Sjg vs_softc[VSUNIT(dev)].rsel = u.u_procp; 724*24495Sjg splx(s); 725*24495Sjg return(0); 726*24495Sjg 727*24495Sjg case FWRITE: 728*24495Sjg splx(s); 729*24495Sjg return(EACCES); 730*24495Sjg } 731*24495Sjg } 732*24495Sjg 733*24495Sjg /* 734*24495Sjg * Initialize VS100 or SBO. 735*24495Sjg * Set XMITON. VS100 will respond with link available. SBO won't, so 736*24495Sjg * don't wait forever; assume everything is OK and warn user. 737*24495Sjg */ 738*24495Sjg 739*24495Sjg vsInitFiber(dev) 740*24495Sjg dev_t dev; 741*24495Sjg { 742*24495Sjg struct vsdevice *vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr; 743*24495Sjg register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)]; 744*24495Sjg int s; 745*24495Sjg #ifdef VSSBO 746*24495Sjg int vsFiberNudge(); 747*24495Sjg 748*24495Sjg timeout(vsFiberNudge, (caddr_t) dev, 2*hz); 749*24495Sjg #endif 750*24495Sjg s = spl5(); 751*24495Sjg vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON); /* turn link on */ 752*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 753*24495Sjg splx(s); 754*24495Sjg #ifdef VSSBO 755*24495Sjg if (!vsp->linkAvail) { 756*24495Sjg uprintf("\007This had better be a vs125!\n"); 757*24495Sjg printf("vs%d must be a vs125\n", VSUNIT(dev)); 758*24495Sjg vsp->linkAvail = TRUE; 759*24495Sjg } 760*24495Sjg #endif 761*24495Sjg } 762*24495Sjg 763*24495Sjg #ifdef VSSBO 764*24495Sjg vsFiberNudge(dev) 765*24495Sjg dev_t dev; 766*24495Sjg { 767*24495Sjg struct vs_softc *vsp = &vs_softc[VSUNIT(dev)]; 768*24495Sjg 769*24495Sjg if (!vsp->linkAvail) 770*24495Sjg wakeup((caddr_t) vsp); 771*24495Sjg } 772*24495Sjg #endif VSSBO 773*24495Sjg 774*24495Sjg vsInitDev(dev, retry) 775*24495Sjg dev_t dev; 776*24495Sjg int retry; 777*24495Sjg { 778*24495Sjg register struct vsdevice *vsaddr; 779*24495Sjg register struct vs_softc *vsp; 780*24495Sjg int s; 781*24495Sjg int vsInitNudge(); 782*24495Sjg 783*24495Sjg vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr; 784*24495Sjg vsp = &vs_softc[VSUNIT(dev)]; 785*24495Sjg 786*24495Sjg if (!vsp->linkAvail) 787*24495Sjg vsInitFiber(dev); 788*24495Sjg while (1) { 789*24495Sjg if (retry) 790*24495Sjg timeout(vsInitNudge, (caddr_t) dev, 10*hz); 791*24495Sjg s = spl5(); 792*24495Sjg vsaddr->vs_irr = 0; 793*24495Sjg vsaddr->vs_csr0 &= ~VS_FCN; 794*24495Sjg vsaddr->vs_csr0 |= (VS_IE | (VS_INIT << VS_FCSHIFT) | VS_GO); 795*24495Sjg sleep((caddr_t) vsp, VSWAITPRI); 796*24495Sjg splx(s); 797*24495Sjg if (vsp->inited) 798*24495Sjg break; 799*24495Sjg printM("vs%d: VS_INIT fails\n", VSUNIT(dev)); 800*24495Sjg uprintf("vsInitDev %x %x\n",vsaddr->vs_csr0, vsaddr->vs_csr1); 801*24495Sjg } 802*24495Sjg } 803*24495Sjg 804*24495Sjg vsInitNudge(dev) 805*24495Sjg dev_t dev; 806*24495Sjg { 807*24495Sjg struct vs_softc *vsp = &vs_softc[VSUNIT(dev)]; 808*24495Sjg 809*24495Sjg if (!vsp->inited) 810*24495Sjg wakeup((caddr_t) vsp); 811*24495Sjg } 812*24495Sjg 813*24495Sjg vsError(vsp) 814*24495Sjg register struct vs_softc *vsp; 815*24495Sjg { 816*24495Sjg if (vsp->irr.intr_error) { 817*24495Sjg register int ret = vsp->irr.intr_reg; 818*24495Sjg 819*24495Sjg printD("\treturning 0x%x\n", ret); 820*24495Sjg vsp->irr.intr_reg = 0; 821*24495Sjg return(ret+128); 822*24495Sjg } 823*24495Sjg return(0); 824*24495Sjg } 825*24495Sjg #endif 826*24495Sjg 827