📄 dr.c
字号:
dr11loop(dr, dra, unit) struct rsdevice *dr; struct dr_aux *dra; int unit;{ register long result, ix; long addr, wait; dr->dr_cstat = MCLR; /* Clear board & device, disable intr */ printf("\n\t ----- DR11 unit %ld loopback test -----", unit); printf("\n\t Program I/O ..."); for (ix=0;ix<NPAT;ix++) { dr->dr_data = tstpat[ix]; /* Write to Data out register */ result = dr->dr_data & 0xFFFF; /* Read it back */ if (result != tstpat[ix]) { printf("Failed, expected : %lx --- actual : %lx", tstpat[ix], result); return; } } printf("OK\n\t Functions & Status Bits ..."); dr->dr_cstat = (FCN1 | FCN3); result = dr->dr_cstat & 0xffff; /* Read them back */ if ((result & (STTC | STTA)) != (STTC |STTA)) { printf("Failed, expected : %lx --- actual : %lx, ISR:%lx", (STTA|STTC), (result & (STTA|STTC)), result); return; } dr->dr_cstat = FCN2; result = dr->dr_cstat & 0xffff; /* Read them back */ if ((result & STTB) != STTB) { printf("Failed, expected : %lx --- actual : %lx, ISR:%lx", STTB, (result & STTB), result); return; } printf("OK\n\t DMA output ..."); if (DMAin) goto dmain; /* Initialize DMA data buffer */ for (ix=0; ix<DMATBL; ix++) tstpat[ix] = 0xCCCC + ix; tstpat[DMATBL-1] = 0xCCCC; /* Last word output */ /* Setup normal DMA */ addr = (long)vtoph((struct proc *)0, (unsigned)tstpat); dr->dr_walo = (addr >> 1) & 0xffff; dr->dr_wahi = (addr >> 17) & 0x7fff; /* Set DMA range count: (number of words - 1) */ dr->dr_range = DMATBL - 1; /* Set address modifier code to be used for DMA access to memory */ dr->dr_addmod = DRADDMOD; /* * Clear dmaf and attf to assure a clean dma start, also disable * attention interrupt */ dr->dr_pulse = RDMA|RATN|RMSK; /* Use pulse register */ dr->dr_cstat = GO|CYCL; /* GO...... */ /* Wait for DMA complete; REDY and DMAF are true in ISR */ wait = 0; while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) { printf("\n\tWait for DMA complete...ISR : %lx", result); if (++wait > 5) { printf("\n\t DMA output fails...timeout!!, ISR:%lx", result); return; } } result = dr->dr_data & 0xffff; /* Read last word output */ if (result != 0xCCCC) { printf("\n\t Fails, expected : %lx --- actual : %lx", 0xCCCC, result); return; } printf("OK\n\t DMA input ...");dmain: dr->dr_data = 0x1111; /* DMA input data */ /* Setup normal DMA */ addr = (long)vtoph((struct proc *)0, (unsigned)tstpat); dr->dr_walo = (addr >> 1) & 0xffff; dr->dr_wahi = (addr >> 17) & 0x7fff; dr->dr_range = DMATBL - 1; dr->dr_addmod = (char)DRADDMOD; dr->dr_cstat = FCN1; /* Set FCN1 in ICR to DMA in*/ if ((dra->dr_flags & DR_LOOPTST) == 0) { /* Use pulse reg */ dr->dr_pulse = RDMA|RATN|RMSK|CYCL|GO; /* Wait for DMA complete; REDY and DMAF are true in ISR */ wait = 0; while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) { printf("\n\tWait for DMA to complete...ISR:%lx",result); if (++wait > 5) { printf("\n\t DMA input timeout!!, ISR:%lx", result); return; } } } else { /* Enable DMA e-o-r interrupt */ dr->dr_pulse = IENB|RDMA|RATN|CYCL|GO; /* Wait for DMA complete; DR_LOOPTST is false in dra->dr_flags*/ wait = 0; while (dra->dr_flags & DR_LOOPTST) { result = dr->dr_cstat & 0xffff; printf("\n\tWait for DMA e-o-r intr...ISR:%lx", result); if (++wait > 7) { printf("\n\t DMA e-o-r timeout!!, ISR:%lx", result); dra->dr_flags &= ~DR_LOOPTST; return; } } dra->dr_flags |= DR_LOOPTST; } mtpr(P1DC, tstpat); /* Purge cache */ mtpr(P1DC, 0x3ff+tstpat); for (ix=0; ix<DMATBL; ix++) { if (tstpat[ix] != 0x1111) { printf("\n\t Fails, ix:%d, expected:%x --- actual:%x", ix, 0x1111, tstpat[ix]); return; } } if ((dra->dr_flags & DR_LOOPTST) == 0) { dra->dr_flags |= DR_LOOPTST; printf(" OK..\n\tDMA end of range interrupt..."); goto dmain; } printf(" OK..\n\tAttention interrupt...."); dr->dr_pulse = IENB|RDMA; dr->dr_pulse = FCN2; /* Wait for ATTN interrupt; DR_LOOPTST is false in dra->dr_flags*/ wait = 0; while (dra->dr_flags & DR_LOOPTST) { result = dr->dr_cstat & 0xffff; printf("\n\tWait for Attention intr...ISR:%lx",result); if (++wait > 7) { printf("\n\t Attention interrupt timeout!!, ISR:%lx", result); dra->dr_flags &= ~DR_LOOPTST; return; } } dra->dr_flags &= ~DR_LOOPTST; printf(" OK..\n\tDone...");}/* Reset state on Unibus reset *//*ARGSUSED*/drreset(uban) int uban;{}/* * An interrupt is caused either by an error, * base address overflow, or transfer complete */drintr(dr11) int dr11;{ register struct dr_aux *dra = &dr_aux[dr11]; register struct rsdevice *rsaddr = RSADDR(dr11); register struct buf *bp; register short status; status = rsaddr->dr_cstat & 0xffff; /* get board status register */ dra->dr_istat = status;#ifdef DR_DEBUG if (DR11 & 2) printf("\ndrintr: dr11 status : %lx",status & 0xffff);#endif if (dra->dr_flags & DR_LOOPTST) { /* doing loopback test */ dra->dr_flags &= ~DR_LOOPTST; return; } /* * Make sure this is not a stray interrupt; at least one of dmaf or attf * must be set. Note that if the dr11 interrupt enable latch is reset * during a hardware interrupt ack sequence, and by the we get to this * point in the interrupt code it will be 0. This is done to give the * programmer some control over how the two more-or-less independent * interrupt sources on the board are handled. * If the attention flag is set when drstrategy() is called to start a * dma read or write an interrupt will be generated as soon as the * strategy routine enables interrupts for dma end-of-range. This will * cause execution of the interrupt routine (not necessarily bad) and * will cause the interrupt enable mask to be reset (very bad since the * dma end-of-range condition will not be able to generate an interrupt * when it occurs) causing the dma operation to time-out (even though * the dma transfer will be done successfully) or hang the process if a * software time-out capability is not implemented. One way to avoid * this situation is to check for a pending attention interrupt (attf * set) by calling drioctl() before doing a read or a write. For the * time being this driver will solve the problem by clearing the attf * flag in the status register before enabling interrupts in * drstrategy(). * * **** The IKON 10084 for which this driver is written will set both * attf and dmaf if dma is terminated by an attention pulse. This will * cause a wakeup(&dr_aux), which will be ignored since it is not being * waited on, and an iodone(bp) which is the desired action. Some other * dr11 emulators, in particular the IKON 10077 for the Multibus, donot * dmaf in this case. This may require some addtional code in the inter- * rupt routine to ensure that en iodone(bp) is issued when dma is term- * inated by attention. */ bp = dra->dr_actf; if ((status & (ATTF | DMAF)) == 0) { printf("dr%d: stray interrupt, status=%x", dr11, status); return; } if (status & DMAF) { /* End-of-range interrupt */ dra->dr_flags |= DR_DMAX;#ifdef DR_DEBUG if (DR11 & 2) printf("\ndrintr: e-o-r interrupt,cstat:%lx,dr_flags:%lx", status&0xffff, dra->dr_flags & DR_ACTV);#endif if ((dra->dr_flags & DR_ACTV) == 0) { /* We are not doing DMA !! */ bp->b_flags |= B_ERROR; } else { if (dra->dr_op == DR_READ) mtpr(P1DC, bp->b_un.b_addr); dra->dr_bycnt -= bp->b_bcount; if (dra->dr_bycnt >0) { bp->b_un.b_addr += bp->b_bcount; bp->b_bcount = (dra->dr_bycnt > NBPG) ? NBPG: dra->dr_bycnt; drstart(rsaddr, dra, bp); return; } } dra->dr_flags &= ~DR_ACTV; wakeup((caddr_t)dra); /* Wakeup waiting in drwait() */ rsaddr->dr_pulse = (RPER|RDMA|RATN); /* reset dma e-o-r flag */ } /* * Now test for attention interrupt -- It may be set in addition to * the dma e-o-r interrupt. If we get one we will issue a wakeup to * the drioctl() routine which is presumable waiting for one. * The program may have to monitor the attention interrupt received * flag in addition to doing waits for the interrupt. Futhermore, * interrupts are not enabled unless dma is in progress or drioctl() * has been called to wait for attention -- this may produce some * strange results if attf is set on the dr11 when a read or a write * is initiated, since that will enables interrupts. * **** The appropriate code for this interrupt routine will probably * be rather application dependent. */ if (status & ATTF) { dra->dr_flags |= DR_ATRX; dra->dr_flags &= ~DR_ATWT; rsaddr->dr_cstat = RATN; /* reset attention flag */ /* * Some applications which use attention to terminate * dma may also want to issue an iodone() here to * wakeup physio(). */ wakeup((caddr_t)&dra->dr_cmd); }}unsigneddrminphys(bp) struct buf *bp;{ if (bp->b_bcount > 65536) bp->b_bcount = 65536;}/* * This routine performs the device unique operations on the DR11W * it is passed as an argument to and invoked by physio */drstrategy (bp) register struct buf *bp;{ register int s; int unit = RSUNIT(bp->b_dev); register struct rsdevice *rsaddr = RSADDR(unit); register struct dr_aux *dra = &dr_aux[unit]; register int ok;#ifdef DR_DEBUG register char *caddr; long drva();#endif if ((dra->dr_flags & DR_OPEN) == 0) { /* Device not open */ bp->b_error = ENXIO; bp->b_flags |= B_ERROR; iodone (bp); return; } while (dra->dr_flags & DR_ACTV) /* Device is active; should never be in here... */ (void) tsleep((caddr_t)&dra->dr_flags, DRPRI, devio, 0); dra->dr_actf = bp;#ifdef DR_DEBUG drva(dra, bp->b_proc, bp->b_un.b_addr, bp->b_bcount);#endif dra->dr_oba = bp->b_un.b_addr; /* Save original addr, count */ dra->dr_obc = bp->b_bcount; dra->dr_bycnt = bp->b_bcount; /* Save xfer count used by drintr() */ if ((((long)bp->b_un.b_addr & 0x3fffffff) >> PGSHIFT) != ((((long)bp->b_un.b_addr & 0x3fffffff) + bp->b_bcount) >> PGSHIFT)) bp->b_bcount = NBPG - (((long)bp->b_un.b_addr) & PGOFSET); dra->dr_flags |= DR_ACTV; /* Mark active (use in intr handler) */ s = SPL_UP(); drstart(rsaddr,dra,bp); splx(s); ok = drwait(rsaddr,dra);#ifdef DR_DEBUG if (DR11 & 0x40) { caddr = (char *)dra->dr_oba; if (dra->dr_op == DR_READ) printf("\nAfter read: (%lx)(%lx)", caddr[0]&0xff, caddr[1]&0xff); }#endif dra->dr_flags &= ~DR_ACTV; /* Clear active flag */ bp->b_un.b_addr = dra->dr_oba; /* Restore original addr, count */ bp->b_bcount = dra->dr_obc; if (!ok) bp->b_flags |= B_ERROR; /* Mark buffer B_DONE,so physstrat() in ml/machdep.c won't sleep */ iodone(bp); wakeup((caddr_t)&dra->dr_flags); /* * Return to the calling program (physio()). Physio() will sleep * until awaken by a call to iodone() in the interupt handler -- * which will be called by the dispatcher when it receives dma * end-of-range interrupt. */}drwait(rs, dr) register struct rsdevice *rs; register struct dr_aux *dr;{ int s; s = SPL_UP(); while (dr->dr_flags & DR_ACTV) (void) tsleep((caddr_t)dr, DRPRI, devio, 0); splx(s); if (dr->dr_flags & DR_TMDM) { /* DMA timed out */ dr->dr_flags &= ~DR_TMDM; return (0); } if (rs->dr_cstat & (PERR|BERR|TERR)) { dr->dr_actf->b_flags |= B_ERROR; return (0); } dr->dr_flags &= ~DR_DMAX; return (1);}/* * * The lower 8-bit of tinfo is the minor device number, the * remaining higher 8-bit is the current timout number */drrwtimo(tinfo) register u_long tinfo;{ register long unit = tinfo & 0xff; register struct dr_aux *dr = &dr_aux[unit]; register struct rsdevice *rs = dr->dr_addr; /* * If this is not the timeout that drwrite/drread is waiting * for then we should just go away */ if ((tinfo &~ 0xff) != (dr->currenttimo << 8)) return; /* Mark the device timed out */ dr->dr_flags |= DR_TMDM; dr->dr_flags &= ~DR_ACTV; rs->dr_pulse = RMSK; /* Inihibit interrupt */ rs->dr_pulse = (RPER|RDMA|RATN|IENB); /* Clear DMA logic */ /* * Some applications will not issue a master after dma timeout, * since doing so sends an INIT H pulse to the external device, * which may produce undesirable side-effects. */ /* Wake up process waiting in drwait() and flag the error */ dr->dr_actf->b_flags |= B_ERROR; wakeup((caddr_t)dr->dr_cmd);}/* * Kick the driver every second */drtimo(dev) dev_t dev;{ register int unit = RSUNIT(dev); register struct dr_aux *dr; dr = &dr_aux[unit]; if (dr->dr_flags & DR_OPEN) timeout(drtimo, (caddr_t)dev, hz); wakeup((caddr_t)dr); /* Wakeup any process waiting for interrupt */}#ifdef DR_DEBUGdrva(dra, p, va, bcnt) struct dr_aux *dra; struct proc *p; char *va; long bcnt;{ register long first, last , np; if (DR11 & 0x20) { first = ((long)(vtoph(p, (unsigned)va))) >> 10; last = ((long)(vtoph(p, (unsigned)va+bcnt))) >> 10; np = bcnt / 0x3ff; printf("\ndrva: (op:%ld)(first:%ld)(last:%ld)(np:%ld)(cnt:%ld)", dra->dr_op,first,last,np,bcnt); }}#endifdrstart(rsaddr, dra, bp) register struct rsdevice *rsaddr; register struct dr_aux *dra; register struct buf *bp;{ register long addr; u_short go;#ifdef DR_DEBUG if (dra->dr_op == DR_READ && (DR11 & 8)) { char *caddr = (char *)bp->b_un.b_addr; printf("\ndrstart: READ, bcnt:%ld",bp->b_bcount); printf(",(%lx)(%lx)",caddr[0]&0xff,caddr[1]&0xff); }#endif /* we are doing raw IO, bp->b_un.b_addr is user's address */ addr = (long)vtoph(bp->b_proc, (unsigned)bp->b_un.b_addr); /* * Set DMA address into DR11 interace registers: DR11 requires that * the address be right shifted 1 bit position before it is written * to the board (The board will left shift it one bit position before * it places the address on the bus */ rsaddr->dr_walo = (addr >> 1) & 0xffff; rsaddr->dr_wahi = (addr >> 17) & 0x7fff; /* Set DMA range count: (number of words - 1) */ rsaddr->dr_range = (bp->b_bcount >> 1) - 1; /* Set address modifier code to be used for DMA access to memory */ rsaddr->dr_addmod = DRADDMOD; /* * Now determine whether this is a read or a write. ***** This is * probably only usefull for link mode operation, since dr11 doesnot * controll the direction of data transfer. The C1 control input * controls whether the hardware is doing a read or a write. In link * mode this is controlled by function 1 latch (looped back by the * cable) and could be set the program. In the general case, the dr11 * doesnot know in advance what the direction of transfer is - although * the program and protocol logic probably is */#ifdef DR_DEBUG if (DR11 & 1) printf("\ndrstrat: about to GO..,dr_cmd:%lx,drstat:%lx,drcnt:%ld,cdata:%lx,OP:%ld", dra->dr_cmd, rsaddr->dr_cstat, rsaddr->dr_range, rsaddr->dr_data, dra->dr_op);#endif /* * Update function latches may have been done already by drioctl() if * request from drioctl() */ if (dra->dr_cmd & DR_DFCN) { /* deferred function write */ dra->dr_cmd &= ~DR_DFCN; /* Clear request */ go = dra->dr_cmd & DR_FMSK; /* mask out fcn bits */ rsaddr->dr_cstat = go; /* Write it to the board */ } /* Clear dmaf and attf to assure a clean dma start */ rsaddr->dr_pulse = RATN|RDMA|RPER; rsaddr->dr_cstat = IENB|GO|CYCL|dra->dr_op; /* GO...... */ /* * Now check for software cycle request -- usually * by transmitter in link mode. */ if (dra->dr_cmd & DR_PCYL) { dra->dr_cmd &= ~DR_PCYL; /* Clear request */ rsaddr->dr_pulse = CYCL; /* Use pulse register again */ } /* * Now check for deferred ACLO FCNT2 pulse request -- usually to tell * the transmitter (via its attention) that we have enabled dma. */ if (dra->dr_cmd & DR_DACL) { dra->dr_cmd &= ~DR_DACL; /* Clear request */ rsaddr->dr_pulse = FCN2; /* Use pulse register again */ }}#endif NDR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -