/* ps.c 4.9 82/12/17 */ /* * Evans and Sutherland Picture System 2 driver */ /* * Still to be done: * WAIT_HIT */ #include "ps.h" #if NPS > 0 #define EXTERNAL_SYNC #include "../machine/pte.h" #include "../h/param.h" #include "../h/systm.h" #include "../h/ioctl.h" #include "../h/map.h" #include "../h/buf.h" #include "../h/conf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/uio.h" #include "../vaxuba/ubareg.h" #include "../vaxuba/ubavar.h" #include "../vaxuba/psreg.h" int psprobe(), psattach(), psintr(); struct uba_device *psdinfo[NPS]; u_short psstd[] = { 0 }; struct uba_driver psdriver = { psprobe, 0, psattach, 0, psstd, "ps", psdinfo }; #define PSUNIT(dev) (minor(dev)) #define MAXAUTOREFRESH (4) #define MAXAUTOMAP (4) #define MAXDBSIZE (0177777/2) #define PSPRI (PZERO+1) #define PSWAIT() {register short int i, j; i=20000; while((i-- != 0)\ && (((j=psaddr->ps_iostat)&DIOREADY)==0));} struct ps { char ps_open; short int ps_uid; struct { enum { SINGLE_STEP_RF, AUTO_RF } state; enum { RUNNING_RF, SYNCING_RF, WAITING_MAP } mode; unsigned short int sraddrs[MAXAUTOREFRESH]; short int nsraddrs; short int srcntr; char waiting; char stop; int icnt; } ps_refresh; struct { enum { ON_DB, OFF_DB } state; unsigned short int dbaddrs[2]; unsigned short int dbsize; short int rbuffer; } ps_dbuffer; struct { enum { SINGLE_STEP_MAP, AUTO_MAP } state; enum { RUNNING_MAP, WAITING_RF, WAITING_START } mode; unsigned short int maddrs[MAXAUTOMAP]; short int nmaddrs; short int mcntr; short int outputstart; char waiting; char stop; int icnt; } ps_map; struct { short int ticked; short int missed; int icnt; } ps_clock; struct { int icnt; } ps_hit; int ps_strayintr; int last_request; int strayrequest; } ps[NPS]; psprobe(reg) caddr_t reg; { register int br, cvec; register struct psdevice *psaddr = (struct psdevice *) reg; psaddr->ps_iostat = PSRESET; DELAY(200); psaddr->ps_addr = RTCIE; PSWAIT(); psaddr->ps_data = 01; psaddr->ps_iostat = PSIE; psaddr->ps_addr = RTCSR; PSWAIT(); psaddr->ps_data = (SYNC|RUN); DELAY(200000); psaddr->ps_addr = RTCREQ; PSWAIT(); psaddr->ps_data = 01; psaddr->ps_iostat = 0; psaddr->ps_iostat = PSRESET; return (sizeof (struct psdevice)); } /*ARGSUSED*/ psattach(ui) register struct uba_device *ui; { } psopen(dev) dev_t dev; { register struct ps *psp; register struct uba_device *ui; register int unit = PSUNIT(dev); if (unit >= NPS || (psp = &ps[minor(dev)])->ps_open || (ui = psdinfo[unit]) == 0 || ui->ui_alive == 0) return (ENXIO); psp->ps_open = 1; psp->ps_uid = u.u_uid; psp->ps_strayintr = 0; psp->ps_refresh.state = SINGLE_STEP_RF; psp->ps_refresh.waiting = 0; psp->ps_refresh.stop = 0; psp->ps_dbuffer.state = OFF_DB; psp->ps_map.state = SINGLE_STEP_MAP; psp->ps_map.waiting = 0; psp->ps_map.stop = 0; psp->ps_clock.ticked = 0; psp->ps_refresh.icnt = psp->ps_map.icnt = psp->ps_clock.icnt = 0; maptouser(ui->ui_addr); return (0); } psclose(dev) dev_t dev; { register struct psdevice *psaddr = (struct psdevice *) psdinfo[PSUNIT(dev)]->ui_addr; ps[PSUNIT(dev)].ps_open = 0; psaddr->ps_iostat = 0; /* clear IENABLE */ PSWAIT(); psaddr->ps_addr = RFSR; /* set in auto refresh mode */ PSWAIT(); psaddr->ps_data = AUTOREF; unmaptouser(psaddr); } /*ARGSUSED*/ psread(dev, uio) dev_t dev; struct uio *uio; { } /*ARGSUSED*/ pswrite(dev, uio) dev_t dev; struct uio *uio; { } /*ARGSUSED*/ psioctl(dev, cmd, data, flag) register caddr_t data; { register struct uba_device *ui = psdinfo[PSUNIT(dev)]; register struct ps *psp = &ps[PSUNIT(dev)]; int *waddr = *(int **)data; int n, arg, i; switch (cmd) { case PSIOGETADDR: *(caddr_t *)data = ui->ui_addr; break; case PSIOAUTOREFRESH: n = fuword(waddr++); if (n == -1) return (EFAULT); if (n < 0 || n > MAXAUTOREFRESH) return (EINVAL); for (i = 0; i < n; i++) { if ((arg = fuword(waddr++)) == -1) return (EFAULT); psp->ps_refresh.sraddrs[i] = arg; } psp->ps_refresh.state = AUTO_RF; psp->ps_refresh.nsraddrs = n; psp->ps_refresh.srcntr = 0; psp->ps_refresh.mode = WAITING_MAP; break; case PSIOAUTOMAP: n = fuword(waddr++); if (n == -1) return (EFAULT); if (n < 0 || n > MAXAUTOMAP) return (EINVAL); for (i = 0; i < n; i++) { if ((arg = fuword(waddr++)) == -1) return (EFAULT); psp->ps_map.maddrs[i] = arg; } if ((arg = fuword(waddr++)) == -1) return (EFAULT); psp->ps_map.outputstart = arg; psp->ps_map.state = AUTO_MAP; psp->ps_map.nmaddrs = n; psp->ps_map.mcntr = 0; psp->ps_map.mode = WAITING_START; break; case PSIOSINGLEREFRESH: psp->ps_refresh.state = SINGLE_STEP_RF; break; case PSIOSINGLEMAP: psp->ps_map.state = SINGLE_STEP_MAP; break; case PSIODOUBLEBUFFER: if ((arg = fuword(waddr++)) == -1) return (EFAULT); psp->ps_dbuffer.dbaddrs[0] = arg; if ((arg = fuword(waddr++)) == -1) return (EFAULT); if (arg <= 0 || arg > MAXDBSIZE) return (EINVAL); psp->ps_dbuffer.dbsize = arg; psp->ps_dbuffer.dbaddrs[1] = psp->ps_dbuffer.dbaddrs[0]+arg; psp->ps_dbuffer.state = ON_DB; psp->ps_dbuffer.rbuffer = 0; } break; case PSIOSINGLEBUFFER: psp->ps_dbuffer.state = OFF_DB; break; case PSIOWAITREFRESH: if (psp->ps_refresh.mode != RUNNING_RF) /* not running */ return (0); /* dont wait */ /* fall into ... */ case PSSIOTOPREFRESH: if (cmd == PSSTOPREFRESH) psp->ps_refresh.stop = 1; spl5(); psp->ps_refresh.waiting = 1; while (psp->ps_refresh.waiting) sleep(&psp->ps_refresh.waiting, PSPRI); spl0(); break; case PSIOWAITMAP: if (psp->ps_map.mode != RUNNING_MAP) /* not running */ return (0); /* dont wait */ /* fall into ... */ case PSIOSTOPMAP: if (cmd == PSSTOPMAP) psp->ps_map.stop = 1; spl5(); psp->ps_map.waiting = 1; while (psp->ps_map.waiting) sleep(&psp->ps_map.waiting, PSPRI); spl0(); break; default: return (ENOTTY); break; } return (0); } #define SAVEPSADDR() {register short int i, x;x=spl6();i=psaddr->ps_addr;\ while(((i=psaddr->ps_iostat)&DIOREADY)==0);\ savepsaddr=psaddr->ps_data;splx(x);} #define RESTORPSADDR() {register int x,i;x=spl6();\ while(((i=psaddr->ps_iostat)&DIOREADY)==0);\ psaddr->ps_addr=savepsaddr;splx(x);} psclockintr(dev) dev_t dev; { register struct psdevice *psaddr = (struct psdevice *) psdinfo[PSUNIT(dev)]->ui_addr; register struct ps *psp = &ps[PSUNIT(dev)]; int savepsaddr; if (!psp->ps_open) return; psp->ps_clock.icnt++; SAVEPSADDR(); #ifndef EXTERNAL_SYNC if (psp->ps_refresh.state == AUTO_RF) { if (psp->ps_refresh.mode == SYNCING_RF) { psrfnext(psp, psaddr); } else { psp->ps_clock.ticked++; psp->ps_clock.missed++; } } #endif PSWAIT(); psaddr->ps_addr = RTCREQ; PSWAIT(); psaddr->ps_data = 01; /* clear the request bits */ RESTORPSADDR(); } /*ARGSUSED*/ pssystemintr(dev) dev_t dev; { register struct psdevice *psaddr = (struct psdevice *) psdinfo[PSUNIT(dev)]->ui_addr; register struct ps *psp = &ps[PSUNIT(dev)]; short int request; register int savepsaddr, x; if (!psp->ps_open) return; SAVEPSADDR(); PSWAIT(); psaddr->ps_addr = SYSREQ; PSWAIT(); request = psaddr->ps_data; psp->last_request = request; PSWAIT(); psaddr->ps_addr = SYSREQ; PSWAIT(); psaddr->ps_data = request&(~(HALT_REQ|MOSTOP_REQ)); /* acknowledge */ if (request & (MOSTOP_REQ|HALT_REQ)) { /* Map stopped */ psp->ps_map.icnt++; psmapstop(psaddr); /* kill it dead */ if (psp->ps_map.waiting) { psp->ps_map.waiting = 0; wakeup(&psp->ps_map.waiting); if (psp->ps_map.stop) { psp->ps_map.stop = 0; goto tryrf; } } if (psp->ps_map.state == AUTO_MAP) if (!psmapnext(psp, psaddr)) { psp->ps_map.mcntr = 0; /* prepare for next round */ pssetmapbounds(psp, psaddr); if (psp->ps_refresh.mode == WAITING_MAP) { if (psp->ps_dbuffer.state == ON_DB) /* fill other db */ psdbswitch(psp, psaddr); else psp->ps_map.mode = WAITING_RF; psrfnext(psp, psaddr); /* start rf */ } else psp->ps_map.mode = WAITING_RF; } } tryrf: if (request & RFSTOP_REQ) { /* Refresh stopped */ psp->ps_refresh.icnt++; psrfstop(psaddr, psp); if (psp->ps_refresh.waiting) { psp->ps_refresh.waiting = 0; wakeup(&psp->ps_refresh.waiting); if (psp->ps_refresh.stop) { psp->ps_refresh.stop = 0; goto tryhit; } } if (psp->ps_refresh.state == AUTO_RF) if (!psrfnext(psp, psaddr)) { /* at end of refresh cycle */ if (psp->ps_map.state == AUTO_MAP && psp->ps_map.mode==WAITING_RF) { if (psp->ps_dbuffer.state == ON_DB) psdbswitch(psp, psaddr); else psmapnext(psp, psaddr); } psp->ps_refresh.srcntr = 0; #ifdef EXTERNAL_SYNC x = spl6(); #endif if (!psp->ps_clock.ticked || !psrfnext(psp, psaddr)) { psp->ps_refresh.mode = SYNCING_RF; } psp->ps_clock.ticked = 0; psp->ps_refresh.mode = SYNCING_RF; #ifdef EXTERNAL_SYNC splx(x); #endif } } tryhit: if (request & HIT_REQ) { /* Hit request */ psp->ps_hit.icnt++; } if (request == 0) psp->ps_strayintr++; RESTORPSADDR(); } psrfnext(psp, psaddr) register struct ps *psp; register struct psdevice *psaddr; { if (psp->ps_refresh.srcntr < psp->ps_refresh.nsraddrs) psrfstart(psp->ps_refresh.sraddrs[psp->ps_refresh.srcntr++], psp, psaddr); else if (psp->ps_refresh.srcntr == psp->ps_refresh.nsraddrs && psp->ps_dbuffer.state == ON_DB) { psrfstart(psp->ps_dbuffer.dbaddrs[psp->ps_dbuffer.rbuffer], psp, psaddr); psp->ps_refresh.srcntr++; /* flag for after dbuffer */ } else return(0); return(1); } psrfstart(dfaddr, psp, psaddr) short int dfaddr; register struct ps *psp; register struct psdevice *psaddr; { int dummy; PSWAIT(); psaddr->ps_addr = RFASA; PSWAIT(); psaddr->ps_data = dfaddr; PSWAIT(); dummy = psaddr->ps_data; /* just access to get to status reg */ PSWAIT(); psaddr->ps_data = RFSTART; /* may want to | this value in */ psp->ps_refresh.mode = RUNNING_RF; } psrfstop(psaddr, psp) register struct psdevice *psaddr; register struct ps *psp; { PSWAIT(); psaddr->ps_addr = RFSR; PSWAIT(); psaddr->ps_data = 0; } psdbswitch(psp, psaddr) register struct ps *psp; register struct psdevice *psaddr; { psp->ps_dbuffer.rbuffer = !psp->ps_dbuffer.rbuffer; pssetmapbounds(psp, psaddr); psmapnext(psp, psaddr); } psmapnext(psp, psaddr) register struct ps *psp; register struct psdevice *psaddr; { if (psp->ps_map.mcntr < psp->ps_map.nmaddrs) psmapstart(psp->ps_map.maddrs[psp->ps_map.mcntr++], psp, psaddr); else return(0); return(1); } pssetmapbounds(psp, psaddr) register struct ps *psp; register struct psdevice *psaddr; { unsigned short int start; PSWAIT(); psaddr->ps_addr = MAOL; PSWAIT(); if (psp->ps_dbuffer.state == ON_DB) { psaddr->ps_data = (start = psp->ps_dbuffer.dbaddrs[!psp->ps_dbuffer.rbuffer]) +psp->ps_dbuffer.dbsize-2; /* 2 for a refresh halt command */ PSWAIT(); psaddr->ps_data = start; } else { start = psaddr->ps_data; /* dummy: don't update limit */ PSWAIT(); psaddr->ps_data = psp->ps_map.outputstart; } } psmapstart(dfaddr, psp, psaddr) int dfaddr; register struct ps *psp; register struct psdevice *psaddr; { int data; PSWAIT(); psaddr->ps_addr = MAIA; PSWAIT(); psaddr->ps_data = dfaddr; PSWAIT(); psaddr->ps_data = MAO|MAI; /* may want more here */ psp->ps_map.mode = RUNNING_MAP; } psmapstop(psaddr) register struct psdevice *psaddr; { PSWAIT(); psaddr->ps_addr = MASR; PSWAIT(); psaddr->ps_data = 0; /* zero MAI bit */ PSWAIT(); psaddr->ps_addr = MAIA; PSWAIT(); psaddr->ps_data = 0; /* zero input address register */ PSWAIT(); psaddr->ps_addr = SYSREQ; PSWAIT(); psaddr->ps_data = HALT_REQ|MOSTOP_REQ; /* overkill?? */ } /*ARGSUSED*/ psdeviceintr(dev) dev_t dev; { printf("ps device intr\n"); } /*ARGSUSED*/ psdmaintr(dev) dev_t dev; { printf("ps dma intr\n"); } psreset(uban) int uban; { } psextsync(PC, PS) { register int n; register struct psdevice *psaddr; register struct ps *psp; register int savepsaddr; #ifdef EXTERNAL_SYNC for (psp = ps, n = 0; n < NPS; psp++, n++) { if (!psp->ps_open) continue; if (psp->ps_refresh.mode == SYNCING_RF) { psaddr = (struct psdevice *) psdinfo[n]->ui_addr; SAVEPSADDR(); psrfnext(psp, psaddr); RESTORPSADDR(); } else { psp->ps_clock.ticked++; psp->ps_clock.missed++; } } #endif } #endif