xref: /csrg-svn/sys/tahoe/vba/vx.c (revision 24003)
1 /*	vx.c	1.1	85/07/21	*/
2 
3 #include "vx.h"
4 #if NVX > 0
5 /*
6  *	VIOC-X driver
7  */
8 
9 #include "../h/param.h"
10 #include "../h/ioctl.h"
11 #include "../h/tty.h"
12 #include "../h/dir.h"
13 #include "../h/user.h"
14 #include "../h/map.h"
15 #include "../machine/pte.h"
16 #include "../h/buf.h"
17 #include "../vba/vbavar.h"
18 #include "../h/conf.h"
19 #include "../h/file.h"
20 #include "../h/uio.h"
21 #include "../vba/vioc.h"
22 #ifdef VXPERF
23 #include "../vba/scope.h"
24 #endif VXPERF
25 #include "vbsc.h"
26 #if NVBSC > 0
27 #include "../bsc/bscio.h"
28 #include "../bsc/bsc.h"
29 char bscport[NVXPORTS];
30 #endif
31 
32 #ifdef BSC_DEBUG
33 #include "../bsc/bscdebug.h"
34 #endif
35 
36 #ifdef	VX_DEBUG
37 long vxintr4 = 0;
38 long vxdebug = 0;
39 #include "../vba/vxdebug.h"
40 #endif
41 
42 #define RSPquals	1
43 
44 struct	vcx	vcx[NVIOCX] ;
45 struct	tty	vx_tty[NVXPORTS];
46 extern struct vcmds v_cmds[];
47 extern long reinit;
48 
49 int	vxstart() ;
50 int	ttrstrt() ;
51 caddr_t vtoph();
52 struct	vxcmd	*vobtain() ;
53 struct	vxcmd	*nextcmd() ;
54 
55 /*
56  * Driver information for auto-configuration stuff.
57  * (not tested and probably should be changed)
58  */
59 int	vxprobe(), vxattach(), vxrint();
60 struct	vba_device *vxinfo[NVIOCX];
61 long	vxstd[] = { 0 };
62 struct	vba_driver vxdriver =
63 	{ vxprobe, 0, vxattach, 0, vxstd, "vioc ", vxinfo };
64 
65 char vxtype[NVIOCX];	/* 0: viox-x/vioc-b; 1: vioc-bop */
66 char vxbbno = -1;
67 char vxbopno[NVIOCX];	/* BOP board no. if indicated by vxtype[] */
68 extern vbrall();
69 
70 
71 vxprobe(reg)
72 	caddr_t reg;
73 {
74 	register int br, cvec;
75 	register struct vblok *vp = (struct vblok *)reg;
76 
77 #ifdef lint
78 	br = 0; cvec = br; br = cvec;
79 #endif
80 
81 	if(badaddr(vp, 1))
82 		return(0);
83 	vp->v_fault = 0 ;
84 	vp->v_vioc = V_BSY ;
85 	vp->v_hdwre = V_RESET ;		/* reset interrupt */
86 
87 	DELAY(4000000);
88 	return ( vp->v_fault == VREADY);
89 }
90 
91 vxattach(ui)
92 	register struct vba_device *ui;
93 {
94 	VIOCBAS[ui->ui_unit] = ui->ui_addr;
95 	vxinit(ui->ui_unit,1);
96 }
97 
98 /*
99  * Open a VX line.
100  */
101 vxopen(dev, flag)
102 {
103 	register struct tty *tp;	/* pointer to tty struct for port */
104 	register struct vcx *xp;	/* pointer to VIOC-X info/cmd buffer */
105 	register d;			/* minor device number */
106 	register long jj;
107 
108 
109 	d = minor(dev);			/* get minor device number */
110 	if (d >= NVXPORTS)		/* validate minor device number */
111 		return ENXIO;		/* set errno to indicate bad port # */
112 	tp = &vx_tty[d];		/* index the tty structure for port */
113 
114 	xp = &vcx[d>>4];			/* index VIOC-X info/cmd area */
115 	d &= 017;
116 
117 	/* If we did not find a board with the correct port number on
118 	   it, or the entry for the VIOC-X had no ports on it, inform the
119 	   caller that the port does not exist. */
120 	if(!( xp->v_loport <= d && d <= xp->v_hiport )	/* home? */
121 	 || (xp->v_hiport - xp->v_loport)==0)
122 		return ENXIO;	/* bad minor device number */
123 	tp->t_addr = (caddr_t)xp;	/* store address of VIOC-X info */
124 	tp->t_oproc = vxstart;		/* store address of startup routine */
125 	tp->t_dev = dev;		/* store major/minor device numbers */
126 	d = spl8();
127 	tp->t_state |= TS_WOPEN;	/* mark device as waiting for open */
128 	if ((tp->t_state&TS_ISOPEN) == 0)	/* is device already open? */
129 	{				/*  no, open it */
130 		ttychars(tp);		/* set default control chars */
131 		if (tp->t_ispeed == 0)	/* if no default speeds set them */
132 		{
133 			tp->t_ispeed = SSPEED;	/* default input baud */
134 			tp->t_ospeed = SSPEED;	/* default output baud */
135 			tp->t_flags |= (ODDP|EVENP|ECHO); /* default modes */
136 		}
137 		vxparam(dev);		/* set parameters for this port */
138 	}
139 	splx(d);
140 	/* ? if already open for exclusive use open fails unless caller is
141 	     root. */
142 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
143 		return EBUSY;	/* device is busy, sorry */
144 
145 	/* wait for data carrier detect to go high */
146 	d = spl8();
147 	if( !vcmodem(dev,VMOD_ON) )
148 		while( (tp->t_state&TS_CARR_ON) == 0 )
149 			sleep(&tp->t_canq,TTIPRI);
150 	jj= (*linesw[tp->t_line].l_open)(dev,tp); /*let tty.c finish the open */
151 	splx(d);	/* 1/2/85 : assures open complete */
152 	return (jj);
153 }
154 
155 /*
156  * Close a VX line.
157  */
158 vxclose(dev, flag)
159 dev_t dev;
160 int  flag;
161 {
162 	register struct tty *tp;
163 	register d;
164 
165 	d = minor(dev) & 0377;
166 	tp = &vx_tty[d];
167 	d = spl8();
168 	(*linesw[tp->t_line].l_close)(tp);
169 	if ((tp->t_state&TS_ISOPEN) && (tp->t_state&TS_HUPCLS))
170 		if( !vcmodem(dev,VMOD_OFF) )
171 			tp->t_state &= ~TS_CARR_ON;
172 	/* wait for the last response */
173 	while(tp->t_state & TS_FLUSH)
174 		sleep( (caddr_t)&tp->t_state, TTOPRI ) ;
175 	ttyclose(tp);	/* let tty.c finish the close */
176 	splx(d);
177 }
178 
179 /*
180  * Read from a VX line.
181  */
182 vxread(dev, uio)
183 	dev_t dev;
184 	struct uio *uio;
185 {
186 	register struct tty *tp = &vx_tty[minor(dev) & 0377];
187 	return (*linesw[tp->t_line].l_read)(tp, uio);
188 }
189 
190 /*
191  * write on a VX line
192  */
193 vxwrite(dev, uio)
194 	dev_t dev;
195 	struct uio *uio;
196 {
197 	register struct tty *tp = &vx_tty[minor(dev) & 0377];
198 	return (*linesw[tp->t_line].l_write)(tp, uio);
199 }
200 
201 /*
202  * VIOCX unsolicited interrupt.
203  */
204 vxrint(n)
205 register n;				/* mux number */
206 {
207 	register struct tty *tp;
208 	register struct vcx *xp;
209 	register short *sp;
210 	register struct vblok *kp;
211 	register int i, c;
212 	short *savsilo;
213 	struct silo {
214 		char	data;
215 		char	port;
216 	};
217 
218 	kp = VBAS(n);
219 	xp = &vcx[n];
220 	switch(kp->v_uqual&037) {
221 	case 0:
222 		break;
223 	case 2:
224 		printf(" ERR NBR %x\n",kp->v_ustat);
225 		vpanic("vc: VC PROC ERR");
226 		vxstreset(n);
227 		return(0);
228 	case 3:
229 		vcmintr(n);
230 		return(1);
231 	case 4:
232 		return(1);
233 	default:
234 		printf(" ERR NBR %x\n",kp->v_uqual);
235 		vpanic("vc: VC UQUAL ERR");
236 		vxstreset(n);
237 		return(0);
238 	}
239 	if(xp->v_vers == V_NEW) {
240 		register short *aa ;
241 		aa = (short *)kp->v_usdata;
242 		sp = (short *)(*aa  + (char *)kp) ;
243 	} else {
244 		c = kp->v_usdata[0] << 6;
245 		sp = (short *)((char *)kp + SILOBAS + c);
246 	}
247 nextsilo:
248 	i = *(savsilo = sp);
249 	if (i == 0) return(1);
250 	if(xp->v_vers == V_NEW)
251 		if( i > xp->v_silosiz ) {
252 			printf("vx: %d exceeds silo size\n",i) ;
253 			i = xp->v_silosiz;
254 		}
255 	for(sp++;i > 0;i--,sp++) {
256 		c = ((struct silo *)sp)->port & 017;
257 		tp = &vx_tty[c+n*16];
258 		if(xp->v_loport > c || c > xp->v_hiport)
259 			continue;	/* port out of bounds */
260 		if( (tp->t_state & TS_ISOPEN) == 0) {
261 			wakeup((caddr_t)&tp->t_rawq);
262 			continue;
263 		}
264 		c = ((struct silo *)sp)->data;
265 		switch(((struct silo *)sp)->port&(PERROR|FERROR)) {
266 		case PERROR:
267 		case PERROR|FERROR:
268 			if( (tp->t_flags&(EVENP|ODDP)) == EVENP
269 			|| (tp->t_flags & (EVENP|ODDP)) == ODDP )
270 				continue;
271 			if(!(((struct silo *)sp)->port&FERROR))
272 				break;
273 		case FERROR:
274 			if(tp->t_flags & RAW) c = 0;
275 			else c = tp->t_intrc;
276 		}
277 		(*linesw[tp->t_line].l_rint)(c, tp);
278 	}
279 	*savsilo = 0;
280 	return(1);
281 }
282 
283 /*
284  * stty/gtty for VX
285  */
286 vxioctl(dev, cmd, data, flag)
287 int	dev;			/* major, minor device numbers */
288 int	cmd;			/* command */
289 caddr_t	data;
290 int	flag;
291 {
292 	register struct tty	*tp;
293 	register error;
294 
295 	tp = &vx_tty[minor(dev) & 0377];
296 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
297 	if (error == 0)
298 		return error;
299 	if((error = ttioctl(tp, cmd, data, flag)) >= 0)
300 	{
301 		if (cmd==TIOCSETP||cmd==TIOCSETN)
302 			vxparam(dev);
303 		return error;
304 	} else
305 		return ENOTTY;
306 }
307 
308 
309 vxparam(dev)
310 dev_t	dev;
311 {
312 	vxcparam(dev, 1);
313 }
314 
315 /*
316  * Set parameters from open or stty into the VX hardware
317  * registers.
318  */
319 vxcparam(dev, wait)
320 dev_t	dev;			/* major, minor device numbers */
321 int wait;			/* nonzero if we should wait for finish */
322 {
323 	register struct tty	*tp;
324 	register struct vcx	*xp;
325 	register struct vxcmd	*cp;
326 	register s;
327 
328 	tp = &vx_tty[minor(dev)];	/* pointer to tty structure for port */
329 	xp = (struct vcx *)tp->t_addr;	/* pointer to VIOCX info/cmd buffer */
330 	cp = vobtain(xp);
331 	s = spl8();
332 	cp->cmd = LPARAX;		/* set command to "load parameters" */
333 	cp->par[1] = minor(dev)&017;	/* port number */
334 
335 	cp->par[2] = (tp->t_flags&RAW)? 0 : tp->t_startc;	/* XON char */
336 	cp->par[3] = (tp->t_flags&RAW)? 0 : tp->t_stopc;	/* XOFF char */
337 
338 	if(tp->t_flags&(RAW|LITOUT) ||
339 	  (tp->t_flags&(EVENP|ODDP)) == (EVENP|ODDP)) {
340 		cp->par[4] = 0xc0;	/* 8 bits of data */
341 		cp->par[7] = 0;		/* no parity */
342 	} else {
343 		cp->par[4] = 0x40;	/* 7 bits of data */
344 		if((tp->t_flags&(EVENP|ODDP)) == ODDP)
345 			cp->par[7] = 1;		/* odd parity */
346 		else if((tp->t_flags&(EVENP|ODDP)) == EVENP)
347 			cp->par[7] = 3;		/* even parity */
348 		else
349 			cp->par[7] = 0;		/* no parity */
350 	}
351 	cp->par[5] = 0x4;			/* 1 stop bit */
352 	cp->par[6] = tp->t_ospeed;
353 
354 	if (vcmd(xp->v_nbr, &cp->cmd) && wait)
355 		sleep(cp,TTIPRI);
356 	splx(s);
357 }
358 
359 /*
360  * VIOCX command response interrupt.
361  * For transmission, restart output to any active port.
362  * For all other commands, just clean up.
363  */
364 vxxint(n,cp)
365 register int n;			/* VIOC number */
366 register struct vxcmd	*cp;	/* command structure */
367 {
368 	register struct	vxmit	*vp, *pvp;
369 	register struct	tty	*tp;
370 	register struct	vcx	*xp;
371 	register struct tty	*hp;
372 
373 	xp = &vcx[n];
374 	cp = (struct vxcmd *)( (long *)cp - 1);
375 #if NVBSC > 0
376 	switch(cp->cmd) {
377 	case MDMCTL1: case HUNTMD1: case LPARAX1:
378 		vrelease(xp, cp);
379 		wakeup(cp);
380 		return;
381 	}
382 #endif
383 	switch(cp->cmd&0xff00) {
384 	case LIDENT:	/* initialization complete */
385 		if (xp->v_state & V_RESETTING) {
386 			vxfnreset(n,cp);
387 			vinthandl(n,((V_BSY | RSPquals) << 8) | V_INTR);
388 		}
389 		cp->cmd++;
390 		return;
391 	case XMITDTA: case XMITIMM:
392 		break;
393 	case LPARAX:
394 		wakeup(cp);
395 	default:	/* MDMCTL or FDTATOX */
396 		vrelease(xp, cp);
397 		if (xp->v_state & V_RESETTING) {
398 			vinthandl(n,((V_BSY | RSPquals) << 8) | V_INTR);
399 		}
400 		return;
401 	}
402 	for(vp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizvxmit);
403 	    vp >= (struct vxmit *)cp->par;
404 	    vp = (struct vxmit *) ((char *)vp - sizvxmit) )
405 	{
406 		tp = &vx_tty[(vp->line & 017)+n*16];
407 /* cjk buffer bug */
408 #if NVBSC > 0
409 					/* bsc change */
410 		if (tp->t_line == LDISP) {
411 			vrelease(xp, cp);
412 			bsctxd((vp->line & 017));
413 			return ;
414 		}
415 					/* End of bsc change */
416 #endif
417 /* cjk */
418 		pvp = vp;
419 		tp->t_state &= ~TS_BUSY;
420 		if(tp->t_state & TS_FLUSH) {
421 			tp->t_state &= ~TS_FLUSH;
422 			wakeup( (caddr_t)&tp->t_state ) ;
423 		}
424 		else
425 		 	ndflush(&tp->t_outq, vp->bcount+1);
426 	}
427 	xp->v_xmtcnt--;
428 	vrelease(xp,cp);
429 	if(xp->v_vers == V_NEW) {
430 		vp = pvp;
431 		xp->v_actport[(vp->line & 017) - xp->v_loport] |= 1 ;
432 		if(vxstart(tp) && (cp = nextcmd(xp)) != NULL)
433 		{
434 			xp->v_xmtcnt++;
435 			vcmd(n, &cp->cmd);
436 			return ;
437 		}
438 		xp->v_actport[(vp->line & 017) - xp->v_loport] = 0 ;
439 		return ;
440 	}
441 	xp->v_actflg = 1;
442 	hp = &vx_tty[xp->v_hiport+n*16];
443 	for(tp = &vx_tty[xp->v_loport+n*16];tp <= hp;tp++)
444 		if(vxstart(tp) && (cp = nextcmd(xp)) != NULL)
445 		{
446 			xp->v_xmtcnt++;
447 			vcmd(n, &cp->cmd);
448 		}
449 	if( (cp = nextcmd(xp)) != NULL )		/* command to send ? */
450 	{
451 		xp->v_xmtcnt++;
452 		vcmd(n,&cp->cmd);
453 	}
454 	xp->v_actflg = 0;
455 }
456 
457 /*
458  * Force out partial XMIT command after timeout
459  */
460 vxforce(xp)
461 register struct vcx	*xp;
462 {
463 	register struct vxcmd	*cp;
464 	register int s;
465 
466 	s = spl8();
467 	if((cp = nextcmd(xp)) != NULL) {
468 		xp->v_xmtcnt++;
469 		vcmd(xp->v_nbr, &cp->cmd);
470 	}
471 	splx(s);
472 }
473 
474 /*
475  * Start (restart) transmission on the given VX line.
476  */
477 vxstart(tp)
478 register struct tty *tp;
479 {
480 	register short nch;
481 	register struct	vcx	*xp;
482 	register char *outb;
483 	register full = 0;
484 	int k, s, port;
485 
486 	s = spl8();
487 	port = minor(tp->t_dev) & 017;
488 	xp = (struct vcx *)tp->t_addr;
489 	if (!(tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
490 		if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
491 			if (tp->t_state&TS_ASLEEP) {
492 				tp->t_state &= ~TS_ASLEEP;
493 				wakeup((caddr_t)&tp->t_outq);
494 			}
495 			if (tp->t_wsel) {
496 				selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
497 				tp->t_wsel = 0;
498 				tp->t_state &= ~TS_WCOLL;
499 			}
500 		}
501 		if(tp->t_outq.c_cc == 0) {
502 			splx(s);
503 			return(0);
504 		}
505 #ifdef VXPERF
506 	scope_out(3);
507 #endif VXPERF
508 		if(!(tp->t_flags&(RAW|LITOUT)))
509 			full = 0200;
510 		if((nch = ndqb(&tp->t_outq, full)) == 0)   {
511 			if(full) {
512 				nch = getc(&tp->t_outq);
513 				timeout(ttrstrt, (caddr_t)tp, (nch&0177) +6);
514 				tp->t_state |= TS_TIMEOUT;
515 				full = 0;
516 			}
517 		} else {
518 			outb = (char *)tp->t_outq.c_cf;
519 			tp->t_state |= TS_BUSY;
520 			if(xp->v_vers == V_NEW)
521 				k = xp->v_actport[port - xp->v_loport] ;
522 			else
523 				k = xp->v_actflg ;
524 
525 			full = vsetq(xp, port, outb, nch);
526 
527 			if( (k&1) == 0 ) {	/* not called from vxxint */
528 				if(full || xp->v_xmtcnt == 0) {
529 					outb = (char *)(&nextcmd(xp)->cmd);
530 					xp->v_xmtcnt++;
531 					vcmd(xp->v_nbr, outb );
532 				} else
533 					timeout(vxforce,xp,3);
534 			}
535 		}
536 	}
537 	splx(s);
538 	return(full);	/* indicate if max commands or not */
539 }
540 
541 /*
542  * Stop output on a line.
543  */
544 vxstop(tp)
545 register struct tty *tp;
546 {
547 	register  s;
548 
549 	s = spl8();
550 	if (tp->t_state & TS_BUSY) {
551 		if ((tp->t_state&TS_TTSTOP)==0) {
552 			tp->t_state |= TS_FLUSH;
553 		}
554 	}
555 	splx(s);
556 }
557 
558 /*
559  * VIOCX Initialization.  Makes free lists of command buffers.
560  * Resets all viocx's.  Issues a LIDENT command to each
561  * viocx which establishes interrupt vectors and logical
562  * port numbers
563  */
564 vxinit(i,wait)
565 register int	i;
566 long wait;
567 {
568 	register struct	vcx	*xp;	/* ptr to VIOC-X info/cmd buffer */
569 	register struct	vblok	*kp;	/* pointer to VIOC-X control block */
570 	register struct	vxcmd	*cp;	/* pointer to a command buffer */
571 	register char	*resp;		/* pointer to response buffer */
572 	register int	j;
573 	register struct	vcmds	*cpp;
574 	char type;
575 	register struct	bsc	*bp;	/* bsc change */
576 	extern	 struct	bsc	bsc[];
577 
578 
579 	kp = VBAS(i);		/* get base adr of cntl blok for VIOC */
580 
581 	xp = &vcx[i];		/* index info/command buffers */
582 	cpp = &v_cmds[i];
583 	type = kp->v_ident;
584 	vxtype[i] =  0;		/* Type is Viox-x */
585 	switch(type) {
586 	case VIOCX:
587 		{
588 		xp->v_vers = V_OLD ;
589 		/* set DCD for printer ports */
590 		for(j = 0;j < 16;j++)
591 			if (kp->v_portyp[j] == 4 )
592 				kp->v_dcd |= 1 << j ;
593 		}
594 		break ;
595 	case NWVIOCX:
596 		{
597 		xp->v_vers = V_NEW ;
598 		xp->v_silosiz = kp->v_maxsilo ;
599 		/* set DCD for printer ports */
600 		for(j = 0;j < 16;j++)
601 			if (kp->v_portyp[j] == 4 )
602 				kp->v_dcd |= 1 << j ;
603 		}
604 		break ;
605 	case PVIOCX:
606 		xp->v_vers = V_OLD ;
607 		break ;
608 	case NPVIOCX:
609 		xp->v_vers = V_NEW ;
610 		xp->v_silosiz = kp->v_maxsilo ;
611 		break ;
612 #if NVBSC > 0
613 	case VIOCB:	/* old f/w, Bisync board */
614 		printf("%X: %x%x OLD VIOC-B, ",
615 					(long)kp, (int)kp->v_ident,
616 					(int)kp->v_fault);
617 		xp->v_vers = V_OLD ;
618 		/* save device specific info */
619 		for(bp = &bsc[0]; bp <= &bsc[NBSC]; bp++)
620 			bp->b_devregs = (caddr_t)xp ;
621 		printf("%d BSC Ports initialized.\n",NBSC);
622 		break ;
623 
624 	case NWVIOCB:	/* new f/w, Bisync board */
625 		printf("%X: %x%x 16K VIOC-B, ",
626 					(long)kp, (int)kp->v_ident,
627 					(int)kp->v_fault);
628 		xp->v_vers = V_NEW ;
629 		xp->v_silosiz = kp->v_maxsilo ;
630 		/* save device specific info */
631 		for(bp = &bsc[0]; bp <= &bsc[NBSC]; bp++)
632 			bp->b_devregs = (caddr_t)xp ;
633 		printf("%d BSC Ports initialized.\n",NBSC);
634 		if(CBSIZE > kp->v_maxxmt)
635 			printf("vxinit: Warning CBSIZE > maxxmt\n") ;
636 		break ;
637 #endif
638 	case VBOPID:		/* VIOC-BOP */
639 		vxbbno++;
640 		vxtype[i] = 1;
641 		vxbopno[i] = vxbbno;
642 		printf("VIOC-BOP no. %d at %lx\n",vxbopno[i],VIOCBAS[i]);
643 	default:
644 		return ;	/* Not a viocx type */
645 	}
646 	xp->v_nbr = -1;		/* no number for it yet */
647 	xp->v_maxcmd = xp->v_vers == V_NEW ? 24 : 4;
648 
649 	for(j=0; j<NVCXBUFS; j++)	/* init all cmd buffers */
650 	{
651 		cp = &xp->vx_lst[j];	/* index a buffer */
652 		cp->c_fwd = &xp->vx_lst[j+1];	/* point to next buf */
653 	}
654 	xp->vx_avail = &xp->vx_lst[0];	/* set idx to 1st free buf */
655 	cp->c_fwd = (struct vxcmd *)0;	/* mark last buf in free list */
656 
657 	cp = vobtain(xp);	/* grap the control block */
658 	cp->cmd = LIDENT;	/* set command type */
659 	cp->par[0] = i * 4 + VCVECT; 	/* ack vector */
660 	cp->par[1] = cp->par[0] + 1;	/* cmd resp vector */
661 	cp->par[3] = cp->par[0] + 2;	/* unsol intr vector */
662 	cp->par[4] = 15;	/* max ports, no longer used */
663 	cp->par[5] = 0;		/* set 1st port number */
664 	vcmd(i, &cp->cmd);	/* initialize the VIOC-X */
665 
666 	if (!wait) return;
667 	while(cp->cmd == LIDENT);    /* wait for command completion */
668 
669  	/* calculate address of response buffer */
670  	resp = (char *)kp;
671  	resp += kp->v_rspoff & 0x3FFF;
672 
673 	if(resp[0] != 0 && (resp[0]&0177) != 3)	/* did init work? */
674 	{
675 		vrelease(xp,cp);	/* init failed */
676 		return;			/* try next VIOC-X */
677 	}
678 
679 	xp->v_loport = cp->par[5];	/* save low port number */
680 	xp->v_hiport = cp->par[7];/* VIOC knows high port numbr */
681 	vrelease(xp,cp);	/* done with this control block */
682 	xp->v_nbr = i;		/* assign VIOC-X board number */
683 }
684 
685 /*
686  * Obtain a command buffer
687  */
688 struct	vxcmd *
689 vobtain(xp)
690 register struct	vcx	*xp;
691 {
692 
693 	register struct	vxcmd	*p;
694 	register s;
695 
696 	s = spl8();
697 	p = xp->vx_avail;
698 	if(p == (struct vxcmd *)0) {
699 #ifdef VX_DEBUG
700 		if (vxintr4 & VXNOBUF) vxintr4 &= ~VXNOBUF;
701 #endif
702 		vpanic("vx: no buffs");
703 		vxstreset(xp - vcx);
704 		splx(s);
705 		return(vobtain(xp));
706 	}
707 	xp->vx_avail = (xp->vx_avail)->c_fwd;
708 	splx(s);
709 	return( (struct vxcmd *)p);
710 }
711 
712 /*
713  * Release a command buffer
714  */
715 vrelease(xp,cp)
716 register struct	vcx	*xp;
717 register struct	vxcmd	*cp;
718 {
719 
720 	register s;
721 
722 #ifdef VX_DEBUG
723 	if (vxintr4 & VXNOBUF) return;
724 #endif
725 	s = spl8();
726 	cp->c_fwd = xp->vx_avail;
727 	xp->vx_avail = cp;
728 	splx(s);
729 }
730 
731 /*
732  * vxcmd -
733  *
734  */
735 struct vxcmd 	*
736 nextcmd(xp)
737 register struct	vcx	*xp;
738 {
739 	register struct	vxcmd	*cp;
740 	register int	s;
741 
742 	s = spl8();
743 	cp = xp->vx_build;
744 	xp->vx_build = (struct vxcmd *)0;
745 	splx(s);
746 	return(cp);
747 }
748 
749 /*
750  * assemble transmits into a multiple command.
751  * up to 8 transmits to 8 lines can be assembled together
752  */
753 vsetq(xp ,d ,addr, cnt)
754 register struct	vcx	*xp;
755 caddr_t	addr;
756 {
757 
758 	register struct	vxcmd	*cp;
759 	register struct	vxmit	*mp;
760 	register char	*p;
761 	register i;
762 
763 	cp = xp->vx_build;
764 	if(cp == (struct vxcmd *)0) {
765 		cp = vobtain(xp);
766 		xp->vx_build = cp;
767 		cp->cmd = XMITDTA;
768 	} else {
769 		if((cp->cmd & 07) == 07) {
770 			vpanic("vx: vsetq overflow");
771 			vxstreset(xp->v_nbr);
772 			return(0);
773 		}
774 		cp->cmd++;
775 	}
776 
777 	mp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizvxmit);
778 	mp->bcount = cnt-1;
779 
780 	mp->line = d;
781 	if((xp->v_vers == V_NEW) && (cnt <= 6)) {
782 		cp->cmd = XMITIMM ;
783 		p = addr;
784 		/* bcopy(addr, &(char *)mp->ostream, cnt) ; */
785 	} else {
786 		addr = vtoph(0, (caddr_t)addr) ; /* should be a sys address */
787 		p = (char *)&addr;
788 		cnt = sizeof addr;
789 		/* mp->ostream = addr ; */
790 	}
791 	for(i=0; i<cnt; i++)
792 		mp->ostream[i] = *p++;
793 	if(xp->v_vers == V_NEW)
794 		return(1) ;
795 	else
796 		return((cp->cmd&07) == 7) ;	/* Indicate if full */
797 }
798 #endif
799