File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / vba / nvcx.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:30:11 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

#include "vx.h"
#if NVX > 0
/*
 *	VIOC-X driver
 */

#include "../h/param.h"
#include "../h/ioctl.h"
#include "../h/tty.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/map.h"
#include "../machine/pte.h"
#include "../h/buf.h"
#include "../vba/vbavar.h"
#include "../h/conf.h"
#include "../h/file.h"
#include "../h/uio.h"
#include "../vba/vioc.h"
#ifdef VXPERF
#include "../vba/scope.h"
#endif VXPERF

#include "vbsc.h"
#if NVBSC > 0
#include "../bsc/bscio.h"
#include "../bsc/bsc.h"
char bscport[NVXPORTS];
long bscno = 0;
extern struct bsc bsc[];
#endif

#define RSPquals	1

struct vcx		vcx[NVIOCX];
struct tty		vx_tty[NVXPORTS];
extern struct vcmds	v_cmds[];
struct vba_device	*vxinfo[NVIOCX];

int	vxstart();
int	ttrstrt();
caddr_t vtoph();
struct	vxcmd	*vobtain();

/*
 * Driver information for auto-configuration stuff.
 * (not tested and probably should be changed)
 */
int	vxprobe(), vxattach(), vxrint();
long	vxstd[] = { 0 };
struct	vba_driver vxdriver =
	{ vxprobe, 0, vxattach, 0, vxstd, "VIOC ", vxinfo };

char vxtype[NVIOCX];	/* 0: viox-x/vioc-b; 1: vioc-bop */
char vxbopno[NVIOCX];	/* BOP board no. if indicated by vxtype[] */
char vxbbno = -1;
short vbtbl = -1;
int vx_cnt = NVXPORTS;	/* needed by vmstat/iostat */
extern vbrall();

vxprobe(reg)
caddr_t reg;
{
	register int br, cvec;
	register struct vblok *vp = (struct vblok *)reg;

#ifdef lint
	br = 0; cvec = br; br = cvec;
#endif

	if (badaddr(vp, 1))
		return(0);
	vp->v_fault = 0;
	vp->v_vioc = V_BSY;
	vp->v_hdwre = V_RESET;		/* reset interrupt */

	DELAY(4000000);
	if (vp->v_fault != VREADY)
		return(0);
	return(1);
}

vxattach(ui)
register struct vba_device *ui;
{
	VIOCBAS[ui->ui_unit] = ui->ui_addr;
	vxinit(ui->ui_unit, 1);
}

/*
 * Open a VX line.
 */
vxopen(dev, flag)
{
	register struct tty *tp;	/* pointer to tty struct for port */
	register struct vcx *xp;	/* pointer to VIOC-X info/cmd buffer */
	register int d;			/* minor device number */
	register int error;

	d = minor(dev);			/* get minor device number */
	if (d >= NVXPORTS)		/* validate minor device number */
		return(ENXIO);		/* set errno to indicate bad port # */
	tp = &vx_tty[d];		/* index the tty structure for port */

	xp = &vcx[d>>4];		/* index VIOC-X info/cmd area */
	d &= 017;

	/*
	 * If we are resetting the VIOC, wait until the LIDENT has
	 * completed.
	 */
	while (xp->v_state&V_RESETTING)
		sleep((caddr_t)&xp->v_state);

	if (xp->v_hiport == xp->v_loport ||	/* no ports on this board */
	   d < xp->v_loport || d > xp->v_hiport)/* not in the range of ports */
		return(ENXIO);		/* bad minor device number */

	if (isprinter(xp, d))
		/*
		 * Printers have different semantics than tty ports.
		 * They have a fixed output transliteration, no read,
		 * only one process may open them at a time, they always
		 * have carrier and processes cannot be attached to them.
		 */
		if (tp->t_state&TS_ISOPEN)
			return(EBUSY);

	if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0){/* is device already open? */
		ttychars(tp);		/* set default control chars */
		tp->t_addr = (caddr_t)xp;/* store addr of VIOC-X info */
		tp->t_oproc = vxstart;	/* store address of startup routine */
		tp->t_dev = dev;	/* store major/minor device numbers */
		if (tp->t_ispeed == 0) {/* if no default speeds set them */
			tp->t_ispeed = SSPEED;/* default input baud */
			tp->t_ospeed = SSPEED;/* default output baud */
			tp->t_flags |= (ODDP|EVENP|ECHO); /* default modes */
		}
		vxparam(dev);		/* set parameters for this port */
	}
	/*
	 * If already open for exclusive use open fails unless caller is root.
	 */
	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
		return(EBUSY);		/* device is busy, sorry */

	d = spl8();
	tp->t_state |= TS_WOPEN;	/* mark device as waiting for open */
	/*
	 * Check for carrier
	 */
	if (vcmodem(dev, VMOD_ON))
		tp->t_state |= TS_CARR_ON;
	else
		tp->t_state &= ~TS_CARR_ON;
	while ((tp->t_state&TS_CARR_ON) == 0) {
		tp->t_state |= TS_WOPEN;
		sleep(&tp->t_canq, TTIPRI);
	}
	error = (*linesw[tp->t_line].l_open)(dev, tp);/*let tty.c finish open */
	splx(d);
	return(error);
}

/*
 * Close a VX line.
 */
vxclose(dev, flag)
dev_t dev;
int  flag;
{
	register int d = minor(dev);
	register struct tty *tp = &vx_tty[d];
	register int s = spl8();
	register int error;

	error = (*linesw[tp->t_line].l_close)(tp);
	if ((tp->t_state&TS_ISOPEN) && (tp->t_state&TS_HUPCLS)) {
		register int	flags = tp->t_flags;

		/*
		**  Turn off echo to prevent infinite flushing 
		**  Flush output queue then turn off clear to send.
		**  Always restore flags so line disipline will not change.
		*/
		tp->t_flags &= ~ECHO;
		ttywait(tp);
		tp->t_flags = flags;
		vcmodem(dev, VMOD_OFF);
	}
	while ((tp->t_state&TS_FLUSH) && (tp->t_state&TS_BUSY))
		sleep((caddr_t)&tp->t_state, TTOPRI);
	ttyclose(tp);	/* let tty.c finish the close */
	splx(s);
	return(error);
}

/*
 * Read from a VX line.
 */
vxread(dev, uio)
dev_t dev;
struct uio *uio;
{
	register int d = minor(dev);
	register struct tty *tp = &vx_tty[d];
	register struct vcx *xp = &vcx[d>>4];

	d &= 0xf;
	if (isprinter(xp, d))
		return(ENODEV);
	return(*linesw[tp->t_line].l_read)(tp, uio);
}

/*
 * Write on a VX line.
 */
vxwrite(dev, uio)
dev_t dev;
struct uio *uio;
{
	register int d = minor(dev);
	register struct tty *tp = &vx_tty[d];

	return(*linesw[tp->t_line].l_write)(tp, uio);
}

/*
 * VIOCX unsolicited interrupt.
 */
vxrint(n)
int n;				/* mux number */
{
	register struct tty *tp;
	register struct vcx *xp;
	register short *sp;
	register int i;
	register unsigned int c;
	register int port;
	struct tty *tp0;
	struct vblok *kp;
	short *savsilo;
	struct silo {
		char data;
		unsigned char port;
	};

	kp = VBAS(n);
	xp = &vcx[n];
#if VX_TESTING
	c = kp->v_uqual&037;
	if (vx_test&VX_PROC_ERR_DEBUG)
		c = 2;
	else if (vx_test&VX_UQUAL_ERR_DEBUG)
		c = 5;
	switch (c) {
#else
	switch (kp->v_uqual&037) {
#endif
	case 0:
		break;
	case 2:
		printf(" ERR NBR %x\n", kp->v_ustat);
		if (kp->v_ustat == 0x40) {
			printf("VIOC %x lost some read data\n", n);
			return(0);
		}
		vpanic("vc: VC PROC ERR");
		vxstreset(n);
		return(0);
	case 3:
		vcmintr(n);
		return(1);
	case 4:
		return(1);
	default:
		printf(" ERR NBR %x\n", kp->v_uqual);
		vpanic("vc: VC UQUAL ERR");
		vxstreset(n);
		return(0);
	}

	/*
	 * Get the address of the silo in VIOC common memory.
	 */
	sp = (short *)((char *)kp + *(short *)kp->v_usdata);

nextsilo:

	/*
	 * See if the number of characters is reasonable.
	 */
	i = *(savsilo = sp);
	if (i > xp->v_silosiz) {
		printf("vx: %d exceeds silo size\n", i);
		i = xp->v_silosiz;
	}

	/*
	 * Drain the silo.
	 */
	tp0 = &vx_tty[n<<4];
	for (sp++; i > 0; i--, sp++) {
		port = ((struct silo *)sp)->port&017;
		if (port < xp->v_loport || port > xp->v_hiport)
			/*
			 * Not a valid port.
			 */
			continue;

		tp = tp0 + port;
		if ((tp->t_state&TS_ISOPEN) == 0)
			/*
			 * Nobody is listening.
			 */
			continue;

		/*
		 * Fetch the character from vioc memory.
		 */
		c = ((struct silo *)sp)->data;

		switch (((struct silo *)sp)->port&(PERROR|FERROR)) {
		case PERROR:
		case PERROR|FERROR:
			if ((tp->t_flags&(EVENP|ODDP)) == EVENP ||
			    (tp->t_flags&(EVENP|ODDP)) == ODDP)
				continue;
			if (!(((struct silo *)sp)->port&FERROR))
				break;

		case FERROR:
			if (tp->t_flags&RAW)
				c = 0;
			else
				c = tp->t_intrc;
		}
		(*linesw[tp->t_line].l_rint)(c, tp);
	}
	*savsilo = 0;
	return(1);
}

/*
 * stty/gtty for VX.
 */
vxioctl(dev, cmd, data, flag)
int dev;			/* major, minor device numbers */
int cmd;			/* command */
caddr_t	data;
int flag;
{
	register int d = minor(dev);
	register struct tty *tp = &vx_tty[d];
	register int error;

	switch (cmd) {
	case VCMANUAL:
	case VCGRS232:
	case VCSRS232:
		/*
		 * Intercept device specific commands.
		 */
		return(vcumodem(dev, cmd, data, flag));
	default:
		break;
	}

	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
	if (error == 0)
		return(error);
	if ((error = ttioctl(tp, cmd, data, flag)) >= 0)
	{
		if (cmd==TIOCSETP||cmd==TIOCSETN)
			vxparam(dev);
		return(error);
	} else
		return(ENOTTY);
}

vxparam(dev)
dev_t dev;
{
	vxcparam(dev, 1);
}

/*
 * Set parameters from open or stty into the VX hardware
 * registers.
 */
vxcparam(dev, wait)
dev_t dev;			/* major, minor device numbers */
int wait;			/* nonzero if we should wait for finish */
{
	register struct tty *tp;
	register struct vcx *xp;
	register struct vxcmd *cp;
	register int s = spl8();

	tp = &vx_tty[minor(dev)];	/* pointer to tty structure for port */
	xp = (struct vcx *)tp->t_addr;	/* pointer to VIOCX info/cmd buffer */

	cp = vobtain(xp);
	cp->cmd = LPARAX;		/* set command to "load parameters" */
	cp->par[1] = minor(dev)&017;	/* port number */

	/*
	 * Check for XON/XOFF flow control.
	 */
	cp->par[2] = (tp->t_flags&RAW)? 0 : tp->t_startc;	/* XON char */
	cp->par[3] = (tp->t_flags&RAW)? 0 : tp->t_stopc;	/* XOFF char */

	if (tp->t_flags&(RAW|LITOUT) ||
	  (tp->t_flags&(EVENP|ODDP)) == (EVENP|ODDP)) {
		cp->par[4] = 0xc0;	/* 8 bits of data */
		cp->par[7] = 0;		/* no parity */
	} else {
		cp->par[4] = 0x40;	/* 7 bits of data */
		if ((tp->t_flags&(EVENP|ODDP)) == ODDP)
			cp->par[7] = 1;		/* odd parity */
		else if ((tp->t_flags&(EVENP|ODDP)) == EVENP)
			cp->par[7] = 3;		/* even parity */
		else
			cp->par[7] = 0;		/* no parity */
	}
 	cp->par[5] = (tp->t_stopbits == 0) ? 4 : tp->t_stopbits;
	if (tp->t_ospeed == EXTA || tp->t_ospeed == EXTB)
		cp->par[6] = 19;		/* 19200 BAUD */
	else
		cp->par[6] = tp->t_ospeed;

	if (vcmd(xp->v_nbr, &cp->cmd) && wait)
		sleep(cp, TTIPRI);
	splx(s);
}

/*
 * VIOCX command response interrupt.
 * For transmission, restart output to any active port.
 * For all other commands, just clean up.
 * This routine is called with spl8 from vcmdrsp().
 */
vxxint(n, cp)
register int n;			/* VIOC number */
register struct vxcmd *cp;	/* command structure */
{
	register struct vxmit *vp, *pvp;
	register struct tty *tp;
	register struct vcx *xp;
	register struct tty *hp;
	register int port;

	xp = &vcx[n];
	cp = (struct vxcmd *)((long *)cp-1);
#if NVBSC > 0
	switch (cp->cmd) {
	case MDMCTL1: case HUNTMD1: case LPARAX1:
		vrelease(xp, cp);
		wakeup(cp);
		return;
	}
#endif
	switch (cp->cmd&0xff00) {
	case LIDENT:	/* initialization complete */
		if (xp->v_state&V_RESETTING)
			vxfnreset(n, cp);
		cp->cmd++;
		return;
	case XMITDTA: case XMITIMM:
		break;
	case LPARAX:
		wakeup(cp);
	case FDTATOX:
	default:	/* MDMCTL or FDTATOX */
		vrelease(xp, cp);
		return;
	}
	for (vp = (struct vxmit *)(cp->par + (cp->cmd&07)*sizvxmit);
	    vp >= (struct vxmit *)cp->par;
	    vp = (struct vxmit *) ((char *)vp - sizvxmit)) {
		tp = &vx_tty[(vp->line&017)+(n<<4)];

#if NVBSC > 0
		port = vp->line;
		if (tp->t_line == LDISP) {
			vrelease(xp, cp);
			/*
			 * Call bsctxd with logical bscport no; 0,1..4,5.
			 * v_xmtcnt was set to BISYNC ctlr no in vxinit().
			 */
			bsctxd((xp->v_xmtcnt*NBSC)+port);
			return;
		}
		if (bscport[(n<<4)+port] == BISYNC) {
			printf("\nvxxint: int. after line closed. (cmd:%lx)",
				cp->cmd&0xff);
			vrelease(xp, cp);
			return;
		}
#endif
		pvp = vp;
		tp->t_state &= ~TS_BUSY;
		if (tp->t_state&TS_FLUSH) {
			tp->t_state &= ~TS_FLUSH;
			wakeup((caddr_t)&tp->t_state);
		}
		else
		 	ndflush(&tp->t_outq, vp->bcount+1);
	}
	xp->v_xmtcnt--;
	vrelease(xp, cp);
	vp = pvp;
	vxstart(tp);
	return;
}

/*
 * Start (restart) transmission on the given VX line.
 */
vxstart(tp)
register struct tty *tp;
{
	register short nch;
	register struct vcx *xp;
	register char *outb;
	register full = 0;
	int s, port;

	s = spl8();
	port = minor(tp->t_dev)&017;
	xp = (struct vcx *)tp->t_addr;
	if (!(tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
		if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
			if (tp->t_state&TS_ASLEEP) {
				tp->t_state &= ~TS_ASLEEP;
				wakeup((caddr_t)&tp->t_outq);
			}
			if (tp->t_wsel) {
				selwakeup(tp->t_wsel, tp->t_state&TS_WCOLL);
				tp->t_wsel = 0;
				tp->t_state &= ~TS_WCOLL;
			}
		}
		if (tp->t_outq.c_cc == 0) {
			splx(s);
			return(0);
		}
#ifdef VXPERF
		scope_out(3);
#endif VXPERF
		if (!(tp->t_flags&(RAW|LITOUT)))  
			full = 0200;
		if ((nch = ndqb(&tp->t_outq, full)) == 0)   {
			if (full) {
				nch = getc(&tp->t_outq);
				timeout(ttrstrt, (caddr_t)tp, (nch&0177) +6);
				tp->t_state |= TS_TIMEOUT;
				full = 0;
			}
		} else {
			outb = (char *)tp->t_outq.c_cf;
			tp->t_state |= TS_BUSY;
			vsend(xp, port, outb, nch);
		}
	}
	splx(s);
	return;
}

/*
 * Stop output on a line.
 */
vxstop(tp)
register struct tty *tp;
{
	register int s;

	s = spl8();
	if (tp->t_state&TS_BUSY) {
		if ((tp->t_state&TS_TTSTOP)==0) {
			tp->t_state |= TS_FLUSH;
		}
	}
	splx(s);
}

/*
 * VIOCX Initialization.  Makes free lists of command buffers.
 * Resets all viocx's.  Issues a LIDENT command to each
 * viocx which establishes interrupt vectors and logical
 * port numbers.
 */
vxinit(i, wait)
register int i;
int wait;
{
	register struct vcx *xp;	/* ptr to VIOC-X info/cmd buffer */
	register struct vblok *kp;	/* pointer to VIOC-X control block */
	register struct vxcmd *cp;	/* pointer to a command buffer */
	register char *resp;		/* pointer to response buffer */
	register int j, ix;
	register struct vcmds *cpp;
	char type;
#if NVBSC > 0
	register struct bsc *bp;	/* bsc change */
#endif

	/*
	 * Only initialize once.
	 */
	if (vbtbl) {
		for (j = 0;j < NVIOCX; j++)
			vxbopno[j] = (char)-1;
		vbtbl = 0;
	}

	kp = VBAS(i);		/* get base adr of cntl blok for VIOC */
	xp = &vcx[i];		/* index info/command buffers */

	cpp = &v_cmds[i];
	type = kp->v_ident;
	vxtype[i] = 0;		/* Type is VIOC-X */
	switch (type) {
	case PVIOCX:
	case VIOCX:
		printf("WARNING:  Old vioc no longer supported.\n");
		xp->v_loport = xp->v_hiport = 0;
		return;

	case NWVIOCX:
	case NPVIOCX:
		xp->v_vers = V_NEW;
		xp->v_silosiz = kp->v_maxsilo;
		/*
		 * Initialize the port types.
		 */
		for (j = 0; j < 16; j++)
			xp->vx_type[j] = kp->v_portyp[j];
		break;

	case VIOCB:	/* old f/w, Bisync board */
		if (wait) {		/* Just boot up */
			if (bscno >= NVBSC) {
			        printf("\nVIOCB no%ld is not configured in software", bscno);
				break;
			}
			if (bscno >= MXVIOC_B) {
				printf("\nvxinit: exceed max no of VIOC-B:%ld",
					MXVIOC_B);
				break;
			}
		}
		printf("(kp:%lx)(xp:%lx): %lx---%x OLD VIOC-B, ",
					(long)kp, (long)xp,(int)kp->v_ident,
					(int)kp->v_fault);
		xp->v_vers = V_OLD;

		if (wait) 				/* Use v_xmtcnt to */
			xp->v_xmtcnt = (char)bscno;	/* save VIOC-B ctlrno */
		else
			bscno = (long)xp->v_xmtcnt&0x7f;

		bp = &bsc[0+(bscno*4)];
		for (ix = 0; ix < 4; ix++, bp++)
			bp->b_devregs = (caddr_t)xp;
		bscno++;
		bscport[(i<<4)+0] = BISYNC;
		bscport[(i<<4)+1] = BISYNC;
		bscport[(i<<4)+2] = BISYNC;
		bscport[(i<<4)+3] = BISYNC;
		printf("        Bisync initialized\n");
		break;

	case NWVIOCB:	/* new f/w, Bisync board */
		if (wait) {		/* Just boot up */
			if (bscno >= NVBSC) {
			        printf("\nVIOCB no%ld is not configured in software", bscno);
				break;
			}
			if (bscno >= MXVIOC_B) {
				printf("\nvxinit: exceed max no of VIOC-B:%ld",
					MXVIOC_B);
				break;
			}
		}
		xp->v_vers = V_NEW;
		xp->v_silosiz = kp->v_maxsilo;

		if (wait) 				/* Use v_xmtcnt to */
			xp->v_xmtcnt = (char)bscno;	/* save VIOC-B ctlrno */
		else
			bscno = (long)xp->v_xmtcnt&0x7f;

		bp = &bsc[bscno*4];
		for (ix = 0; ix < 4; ix++, bp++)
			bp->b_devregs = (caddr_t)xp;
		bscno++;
		bscport[(i<<4)+0] = BISYNC;
		bscport[(i<<4)+1] = BISYNC;
		bscport[(i<<4)+2] = BISYNC;
		bscport[(i<<4)+3] = BISYNC;
		printf("        Bisync initialized\n");
		break;

	case VBOPID:		/* VIOC-BOP */
		if (vxtype[i] == 0) {	/* don't increment if already seen */
			vxbbno++;
			vxtype[i] = 1;
			vxbopno[i] = vxbbno;
		}
		printf("        VIOC-BOP initialized\n");

	default:
		return;			/* Not a viocx type */
	}
	xp->v_nbr = -1;			/* no number for it yet */
	xp->v_maxcmd = xp->v_vers == V_NEW ? 23 : 3;

	for (j = 0; j < NVCXBUFS; j++) {/* init all cmd buffers */
		cp = &xp->vx_lst[j];	/* index a buffer */
		cp->c_fwd = &xp->vx_lst[j+1];	/* point to next buf */
	}
	xp->vx_avail = &xp->vx_lst[0];	/* set idx to 1st free buf */
	cp->c_fwd = (struct vxcmd *)0;	/* mark last buf in free list */

	/*
	 * Assures proper state when reinit. in case of INT. ERR
	 */
	cpp->v_cmdsem = cpp->v_curcnt = cpp->v_fill = 0;
	cpp->v_empty = cpp->v_itrfill = cpp->v_itrempt = 0;

	cp = vobtain(xp);		/* grap the control block */
	cp->cmd = LIDENT;		/* set command type */
	cp->par[0] = i * 4 + VCVECT; 	/* ack vector */
	cp->par[1] = cp->par[0] + 1;	/* cmd resp vector */
	cp->par[3] = cp->par[0] + 2;	/* unsol intr vector */
	cp->par[4] = 15;		/* max ports, no longer used */
	cp->par[5] = 0;			/* set 1st port number */
	vcmd(i, &cp->cmd);		/* initialize the VIOC-X */
	if (!wait)
		return;

	while (cp->cmd == LIDENT)	/* wait for command completion */
		;

 	/*
	 * Calculate address of response buffer.
	 */
	resp = (char *)kp;
	resp += kp->v_rspoff&0x3FFF;

	if (resp[0] != 0 && (resp[0]&0177) != 3) {	/* did init work? */
		vrelease(xp, cp);	/* init failed */
		return;			/* try next VIOC-X */
	}

	xp->v_loport = cp->par[5];	/* save low port number */
	xp->v_hiport = cp->par[7];	/* VIOC knows high port numbr */
	vrelease(xp, cp);		/* done with this control block */
	xp->v_nbr = i;			/* assign VIOC-X board number */
}

/*
 * Obtain a command buffer.
 */
struct	vxcmd *
vobtain(xp)
register struct	vcx *xp;
{
	register struct	vxcmd *p;
	register int s;

	s = spl8();
	p = xp->vx_avail;
	if (p == (struct vxcmd *)0) {
		vpanic("vx: no buffs");
		vxstreset(xp - vcx);
		splx(s);
		return(vobtain(xp));	/* guaranteed to work this time */
	}
	xp->vx_avail = (xp->vx_avail)->c_fwd;
	splx(s);
	return((struct vxcmd *)p);
}

/*
 * Release a command buffer.
 */
vrelease(xp, cp)
register struct vcx *xp;
register struct vxcmd *cp;
{
	register int s = spl8();

	cp->c_fwd = xp->vx_avail;
	xp->vx_avail = cp;
	splx(s);
}

/*
 * Arrange for "cnt" bytes from "addr" to be written to port number
 * "port" on VIOC described by "xp".
 */
vsend(xp, port, addr, cnt)
register struct vcx *xp;/* points to vioc control structure for this port */
int port;		/* port number to get the data */
caddr_t	addr;		/* beginning address of the block */
register int cnt;	/* size of the block of characters */
{
	register struct vxcmd *cp;
	register struct vxmit *mp;
	register int i;
	register char *src, *dst;

	/*
	 * Get a command.
	 */
	cp = vobtain(xp);

	/*
	 * Fill out the port information.
	 */
	mp = (struct vxmit *)cp->par;
	mp->bcount = cnt-1;
	mp->line = port;

	if (cnt <= 6) {
		/*
		 * If small enough, we can give the data directly to
		 * the vioc, eliminating the need for DMA.
		 */
		cp->cmd = XMITIMM;
		src = addr;
		i = cnt;
	} else {
		/*
		 * Get the physical address of the block to DMA.
		 */
		cp->cmd = XMITDTA;
		addr = vtoph(0, (caddr_t)addr);
		src = (char *)&addr;
		i = sizeof(addr);
	}

	/*
	 * Copy the data or address into the command.
	 */
	dst = mp->ostream;
	while (--i >= 0)
		*dst++ = *src++;

	xp->v_xmtcnt++;
	vcmd(xp->v_nbr, (char *)&cp->cmd);
	return;
}
#endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.