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

📄 dr.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1988 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Computer Consoles Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)dr.c	7.9 (Berkeley) 12/16/90 */#include "dr.h"#if NDR > 0/* * DRV11-W DMA interface driver. * * UNTESTED WITH 4.3 */#include "../include/mtpr.h"#include "../include/pte.h"#include "sys/param.h"#include "sys/conf.h"#include "sys/user.h"#include "sys/proc.h"#include "sys/map.h"#include "sys/ioctl.h"#include "sys/buf.h"#include "sys/vm.h"#include "sys/kernel.h"#include "../vba/vbavar.h"#include "../vba/drreg.h"#define YES 1#define NO  0struct  vba_device  *drinfo[NDR];struct  dr_aux dr_aux[NDR];unsigned drminphys();int	 drprobe(), drintr(), drattach(), drtimo(), drrwtimo();int	 drstrategy();extern	struct  vba_device  *drinfo[];static	long drstd[] = { 0 };struct  vba_driver drdriver =    { drprobe, 0, drattach, 0, drstd, "rs", drinfo };#define RSUNIT(dev) (minor(dev) & 7)#define SPL_UP spl5/* -------- Per-unit data -------- */extern struct dr_aux dr_aux[];#ifdef DR_DEBUGlong	DR11 = 0;#endifdrprobe(reg, vi)	caddr_t reg;	struct vba_device *vi;{	register int br, cvec;		/* must be r12, r11 */	struct rsdevice *dr;#ifdef lint	br = 0; cvec = br; br = cvec;	drintr(0);#endif	if (badaddr(reg, 2))		return (0);	dr = (struct rsdevice *)reg;	dr->dr_intvect = --vi->ui_hd->vh_lastiv;#ifdef DR_DEBUG	printf("dprobe: Set interrupt vector %lx and init\n",dr->dr_intvec);#endif	/* generate interrupt here for autoconfig */	dr->dr_cstat = MCLR;		/* init board and device */#ifdef DR_DEBUG	printf("drprobe: Initial status %lx\n", dr->dr_cstat);#endif	br = 0x18, cvec = dr->dr_intvect;	/* XXX */	return (sizeof (struct rsdevice));		/* DR11 exist */}/* ARGSUSED */drattach(ui)	struct vba_device *ui;{	register struct dr_aux *rsd;	rsd = &dr_aux[ui->ui_unit];	rsd->dr_flags = DR_PRES;		/* This dr11 is present */	rsd->dr_addr = (struct rsdevice *)ui->ui_addr; /* Save addr of this dr11 */	rsd->dr_istat = 0;	rsd->dr_bycnt = 0;	rsd->dr_cmd = 0;	rsd->currenttimo = 0;}/*ARGSUSED*/dropen(dev, flag)	dev_t dev;	int flag;{	register int unit = RSUNIT(dev);	register struct rsdevice *dr;	register struct dr_aux *rsd;	if (drinfo[unit] == 0 || !drinfo[unit]->ui_alive)		return (ENXIO);	dr = RSADDR(unit);	rsd = &dr_aux[unit];	if (rsd->dr_flags & DR_OPEN) {#ifdef DR_DEBUG		printf("\ndropen: dr11 unit %ld already open",unit);#endif		return (ENXIO);	  		/* DR11 already open */	}	rsd->dr_flags |= DR_OPEN;	/* Mark it OPEN */	rsd->dr_istat = 0;		/* Clear status of previous interrupt */	rsd->rtimoticks = hz;		/* Set read no stall timout to 1 sec */	rsd->wtimoticks = hz*60;	/* Set write no stall timout to 1 min */	dr->dr_cstat = DR_ZERO;		/* Clear function & latches */	dr->dr_pulse = (RDMA | RATN);	/* clear leftover attn & e-o-r flags */	drtimo(dev);			/* start the self kicker */	return (0);}drclose (dev)	dev_t dev;{	register int unit = RSUNIT(dev);	register struct dr_aux *dra;	register struct rsdevice *rs;	register short s;	dra = &dr_aux[unit];	if ((dra->dr_flags & DR_OPEN) == 0) {#ifdef DR_DEBUG		printf("\ndrclose: DR11 device %ld not open",unit);#endif		return;	}	dra->dr_flags &= ~(DR_OPEN|DR_ACTV);	rs = dra->dr_addr;	s = SPL_UP();	rs->dr_cstat = DR_ZERO;	if (dra->dr_buf.b_flags & B_BUSY) {		dra->dr_buf.b_flags &= ~B_BUSY;		wakeup((caddr_t)&dra->dr_buf.b_flags);	}	splx(s);	return (0);}/*	drread() works exactly like drwrite() except that the	B_READ flag is used when physio() is called*/drread (dev, uio)	dev_t dev;	struct uio *uio;{	register struct dr_aux *dra;	register struct buf *bp;	register int spl, err;	register int unit = RSUNIT(dev);	if (uio->uio_iov->iov_len <= 0 ||	/* Negative count */	    uio->uio_iov->iov_len & 1 ||	/* odd count */	    (int)uio->uio_iov->iov_base & 1)	/* odd destination address */		return (EINVAL);#ifdef DR_DEBUG	if (DR11 & 8)		printf("\ndrread: (len:%ld)(base:%lx)",		    uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base); #endif	dra = &dr_aux[RSUNIT(dev)];	dra->dr_op = DR_READ;	bp =  &dra->dr_buf;	bp->b_resid = 0;	if (dra->dr_flags & DR_NORSTALL) {		/*		 * We are in no stall mode, start the timer,		 * raise IPL so nothing can stop us once the		 * timer's running		 */		spl = SPL_UP();		timeout(drrwtimo, (caddr_t)((dra->currenttimo<<8) | unit),		    (int)dra->rtimoticks);		err = physio(drstrategy, bp, dev,B_READ, drminphys, uio);		splx(spl);		if (err)			return (err);		dra->currenttimo++;	/* Update current timeout number */		/* Did we timeout */		if (dra->dr_flags & DR_TMDM)			dra->dr_flags &= ~DR_TMDM; /* Clear timeout flag */		return (err);	}	return (physio(drstrategy, bp, dev,B_READ, drminphys, uio));}drwrite(dev, uio)	dev_t dev;	struct uio *uio;{	register struct dr_aux *dra;	register struct buf *bp;	register int unit = RSUNIT(dev);	int spl, err;	if (uio->uio_iov->iov_len <= 0 || uio->uio_iov->iov_len & 1 ||	    (int)uio->uio_iov->iov_base & 1)		return (EINVAL);#ifdef DR_DEBUG	if (DR11 & 4)		printf("\ndrwrite: (len:%ld)(base:%lx)",		    uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base); #endif	dra = &dr_aux[RSUNIT(dev)];	dra->dr_op = DR_WRITE;	bp =  &dra->dr_buf;	bp->b_resid = 0;	if (dra->dr_flags & DR_NOWSTALL) {		/*		 * We are in no stall mode, start the timer,		 * raise IPL so nothing can stop us once the		 * timer's running		 */		spl = SPL_UP();		timeout(drrwtimo,(caddr_t)((dra->currenttimo<<8) | unit),		    (int)dra->wtimoticks);		err = physio (drstrategy, bp, dev,B_WRITE, drminphys, uio);		splx(spl);		if (err)			return (err);		dra->currenttimo++;	/* Update current timeout number */		/* Did we timeout */		if (dra->dr_flags & DR_TMDM)			dra->dr_flags &= ~DR_TMDM;	/* Clear timeout flag */		return (err);	}	return (physio(drstrategy, bp, dev,B_WRITE, drminphys, uio));}/* * Routine used by calling program to issue commands to dr11 driver and  * through it to the device. * It is also used to read status from the device and driver and to wait  * for attention interrupts. * Status is returned in an 8 elements unsigned short integer array, the  * first two elements of the array are also used to pass arguments to  * drioctl() if required. * The function bits to be written to the dr11 are included in the cmd * argument. Even if they are not being written to the dr11 in a particular * drioctl() call, they will update the copy of cmd that is stored in the * driver. When drstrategy() is called, this updated copy is used if a  * deferred function bit write has been specified. The "side effect" of * calls to the drioctl() requires that the last call prior to a read or * write has an appropriate copy of the function bits in cmd if they are * to be used in drstrategy(). * When used as command value, the contents of data[0] is the command * parameter. */drioctl(dev, cmd, data)	dev_t dev;	int cmd;	long *data;{	register int unit = RSUNIT(dev);	register struct dr_aux *dra;	register struct rsdevice *rsaddr = RSADDR(unit);	int s, error = 0;	u_short status;	long temp;#ifdef DR_DEBUG	if (DR11 & 0x10)		printf("\ndrioctl: (dev:%lx)(cmd:%lx)(data:%lx)(data[0]:%lx)",		    dev,cmd,data,data[0]);#endif	dra = &dr_aux[unit];	dra->dr_cmd = 0;	/* Fresh copy; clear all previous flags */	switch (cmd) {	case DRWAIT:		/* Wait for attention interrupt */#ifdef DR_DEBUG		printf("\ndrioctl: wait for attention interrupt");#endif		s = SPL_UP();		/* 		 * If the attention flag in dr_flags is set, it probably		 * means that an attention has arrived by the time a		 * previous DMA end-of-range interrupt was serviced. If		 * ATRX is set, we will return with out sleeping, since		 * we have received an attention since the last call to		 * wait on attention.  This may not be appropriate for		 * some applications.		 */		if ((dra->dr_flags & DR_ATRX) == 0) {			dra->dr_flags |= DR_ATWT;	/* Set waiting flag */			/*			 * Enable interrupt; use pulse reg.			 * so function bits are not changed			 */			rsaddr->dr_pulse = IENB;			error = tsleep((caddr_t)&dra->dr_cmd, DRPRI | PCATCH,			    devio, 0);		}		splx(s);		break;	case DRPIOW:			/* Write to p-i/o register */		rsaddr->dr_data = data[0];		break;	case DRPACL:			/* Send pulse to device */		rsaddr->dr_pulse = FCN2;		break;	case DRDACL:			/* Defer alco pulse until go */		dra->dr_cmd |= DR_DACL;		break;	case DRPCYL:			/* Set cycle with next go */		dra->dr_cmd |= DR_PCYL;		break;	case DRDFCN:			/* Update function with next go */		dra->dr_cmd |= DR_DFCN;		break;	case DRRATN:			/* Reset attention flag */		rsaddr->dr_pulse = RATN;		break;	case DRRDMA:			/* Reset DMA e-o-r flag */		rsaddr->dr_pulse = RDMA;		break;	case DRSFCN:			/* Set function bits */		temp = data[0] & DR_FMSK;		/*		 * This has a very important side effect -- It clears		 * the interrupt enable flag. That is fine for this driver,		 * but if it is desired to leave interrupt enable at all		 * times, it will be necessary to read the status register		 * first to get IENB, or carry a software flag that indicates		 * whether interrupts are set, and or this into the control		 * register value being written.		 */		rsaddr->dr_cstat = temp;		break;	case DRRPER:			/* Clear parity flag */		rsaddr->dr_pulse = RPER;		break;	case DRSETRSTALL:		/* Set read stall mode. */		dra->dr_flags &= (~DR_NORSTALL);		break;	case DRSETNORSTALL:		/* Set no stall read  mode. */		dra->dr_flags |= DR_NORSTALL;		break;	case DRGETRSTALL:		/* Returns true if in read stall mode */		data[0]  = (dra->dr_flags & DR_NORSTALL)? 0 : 1;		break;	case DRSETRTIMEOUT:		/* Set read stall timeout (1/10 secs) */		if (data[0] < 1)			error = EINVAL;		dra->rtimoticks = (data[0] * hz )/10;		break;	case DRGETRTIMEOUT:		/* Return read stall timeout */		data[0] = ((dra->rtimoticks)*10)/hz;		break;	case DRSETWSTALL:		/* Set write stall mode. */		dra->dr_flags &= (~DR_NOWSTALL);		break;	case DRSETNOWSTALL:		/* Set write stall mode. */		dra->dr_flags |= DR_NOWSTALL;		break;	case DRGETWSTALL:		/* Return true if in write stall mode */		data[0] = (dra->dr_flags & DR_NOWSTALL)? 0 : 1;		break;	case DRSETWTIMEOUT:		/* Set write stall timeout (1/10's) */		if (data[0] < 1)			error = EINVAL;		dra->wtimoticks = (data[0] * hz )/10;		break;	case DRGETWTIMEOUT:		/* Return write stall timeout */		data[0] = ((dra->wtimoticks)*10)/hz;		break;	case DRWRITEREADY:		/* Return true if can write data */		data[0] = (rsaddr->dr_cstat & STTA)? 1 : 0;		break;	case DRREADREADY:		/* Return true if data to be read */		data[0] = (rsaddr->dr_cstat & STTB)? 1 : 0;		break;	case DRBUSY:			/* Return true if device busy */		/*		 * Internally this is the DR11-W		 * STAT C bit, but there is a bug in the Omega 500/FIFO		 * interface board that it cannot drive this signal low		 * for certain DR11-W ctlr such as the Ikon. We use the		 * REDY signal of the CSR on the Ikon DR11-W instead. 		 */#ifdef notdef		data[0] = (rsaddr->dr_cstat & STTC)? 1 : 0;#else		data[0] = ((rsaddr->dr_cstat & REDY)? 0 : 1);#endif		break;	case DRRESET:			/* Reset device */		/* Reset DMA ATN RPER flag */		rsaddr->dr_pulse = (MCLR|RDMA|RATN|RPER);		DELAY(0x1f000);		while ((rsaddr->dr_cstat & REDY) == 0 && error == 0)			/* Wakeup by drtimo() */			error = tsleep((caddr_t)dra, DRPRI | PCATCH, devio, 0);			dra->dr_istat = 0;		dra->dr_cmd = 0;		dra->currenttimo = 0;		break;	case DR11STAT: {		/* Copy back dr11 status to user */		register struct dr11io *dr = (struct dr11io *)data;		dr->arg[0] = dra->dr_flags;		dr->arg[1] = rsaddr->dr_cstat;		dr->arg[2] = dra->dr_istat;	/* Status at last interrupt */		dr->arg[3] = rsaddr->dr_data;	/* P-i/o input data */		status = (u_short)((rsaddr->dr_addmod << 8) & 0xff00);		dr->arg[4] = status | (u_short)(rsaddr->dr_intvect & 0xff);		dr->arg[5] = rsaddr->dr_range;		dr->arg[6] = rsaddr->dr_rahi;		dr->arg[7] = rsaddr->dr_ralo;		break;	}	case DR11LOOP:			/* Perform loopback test */		/*		 * NB: MUST HAVE LOOPBACK CABLE ATTACHED --		 * Test results are printed on system console		 */		if (error = suser(u.u_cred, &u.u_acflag))			break;		dr11loop(rsaddr, dra, unit);		break;	default:		return (EINVAL);	}#ifdef DR_DEBUG	if (DR11 & 0x10)		printf("**** (data[0]:%lx)",data[0]);#endif	return (error);}#define NPAT	2#define DMATBL	20u_short	tstpat[DMATBL] = { 0xAAAA, 0x5555};long	DMAin = 0;/* * Perform loopback test -- MUST HAVE LOOPBACK CABLE ATTACHED * Test results are printed on system console */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -