⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dr.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
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 + -