xref: /csrg-svn/sys/tahoe/vba/vx.c (revision 49755)
134406Skarels /*
234406Skarels  * Copyright (c) 1988 Regents of the University of California.
335057Skarels  * All rights reserved.
434406Skarels  *
535057Skarels  * This code is derived from software contributed to Berkeley by
635057Skarels  * Computer Consoles Inc.
735057Skarels  *
844535Sbostic  * %sccs.include.redist.c%
935057Skarels  *
10*49755Smarc  *	@(#)vx.c	7.13 (Berkeley) 05/16/91
1134406Skarels  */
1224003Ssam 
1324003Ssam #include "vx.h"
1424003Ssam #if NVX > 0
1524003Ssam /*
1625857Ssam  * VIOC-X driver
1724003Ssam  */
1825877Ssam #ifdef VXPERF
1925948Ssam #define	DOSCOPE
2025877Ssam #endif
2125877Ssam 
2245799Sbostic #include "sys/param.h"
2345799Sbostic #include "sys/ioctl.h"
2445799Sbostic #include "sys/tty.h"
2545799Sbostic #include "sys/user.h"
2645799Sbostic #include "sys/map.h"
2745799Sbostic #include "sys/buf.h"
2845799Sbostic #include "sys/conf.h"
2945799Sbostic #include "sys/file.h"
3045799Sbostic #include "sys/proc.h"
3145799Sbostic #include "sys/vm.h"
3245799Sbostic #include "sys/kernel.h"
3345799Sbostic #include "sys/syslog.h"
3425675Ssam 
3545799Sbostic #include "../include/pte.h"
3634406Skarels 
3745799Sbostic #include "../vba/vbavar.h"
3845799Sbostic #include "../vba/vbaparam.h"
3945799Sbostic #include "../vba/vxreg.h"
4045799Sbostic #include "../vba/scope.h"
4124003Ssam 
4225881Ssam #ifdef VX_DEBUG
4325881Ssam long	vxintr4 = 0;
4425948Ssam #define	VXERR4	1
4525948Ssam #define	VXNOBUF	2
4625881Ssam long	vxdebug = 0;
4725948Ssam #define	VXVCM	1
4825948Ssam #define	VXVCC	2
4925948Ssam #define	VXVCX	4
5025881Ssam #endif
5124003Ssam 
5225881Ssam /*
5325881Ssam  * Interrupt type bits passed to vinthandl().
5425881Ssam  */
5525948Ssam #define	CMDquals 0		/* command completed interrupt */
5625948Ssam #define	RSPquals 1		/* command response interrupt */
5725948Ssam #define	UNSquals 2		/* unsolicited interrupt */
5824003Ssam 
5930372Skarels #define	VXUNIT(n)	((n) >> 4)
6030372Skarels #define	VXPORT(n)	((n) & 0xf)
6130372Skarels 
6225881Ssam struct	tty vx_tty[NVX*16];
6329954Skarels #ifndef lint
6429954Skarels int	nvx = NVX*16;
6529954Skarels #endif
6625881Ssam int	vxstart(), ttrstrt();
6725881Ssam struct	vxcmd *vobtain(), *nextcmd();
6824003Ssam 
6924003Ssam /*
7024003Ssam  * Driver information for auto-configuration stuff.
7124003Ssam  */
7224003Ssam int	vxprobe(), vxattach(), vxrint();
7325881Ssam struct	vba_device *vxinfo[NVX];
7424003Ssam long	vxstd[] = { 0 };
7524003Ssam struct	vba_driver vxdriver =
7625857Ssam     { vxprobe, 0, vxattach, 0, vxstd, "vx", vxinfo };
7724003Ssam 
7825881Ssam struct	vx_softc {
7940738Skarels 	struct	vxdevice *vs_addr;	/* H/W address */
8025881Ssam 	u_char	vs_type;	/* 0: viox-x/vioc-b, 1: vioc-bop */
8125881Ssam 	u_char	vs_bop;		/* bop board # for vioc-bop's */
8225881Ssam 	u_char	vs_loport;	/* low port nbr */
8325881Ssam 	u_char	vs_hiport;	/* high port nbr */
8425881Ssam 	u_short	vs_nbr;		/* viocx number */
8525881Ssam 	u_short	vs_maxcmd;	/* max number of concurrent cmds */
8625881Ssam 	u_short	vs_silosiz;	/* silo size */
8725881Ssam 	short	vs_vers;	/* vioc/pvioc version */
8825948Ssam #define	VXV_OLD	0		/* PVIOCX | VIOCX */
8925948Ssam #define	VXV_NEW	1		/* NPVIOCX | NVIOCX */
9025881Ssam 	short 	vs_state;	/* controller state */
9125948Ssam #define	VXS_READY	0	/* ready for commands */
9225948Ssam #define	VXS_RESET	1	/* in process of reseting */
9330372Skarels 	u_short	vs_softCAR;	/* soft carrier */
9440738Skarels 	u_int	vs_ivec;	/* interrupt vector base */
9525881Ssam 	caddr_t vs_mricmd;	/* most recent issued cmd */
9640738Skarels 	/* The remaining fields are zeroed on reset... */
9740738Skarels #define vs_zero vs_xmtcnt
9840738Skarels 	int	vs_xmtcnt;	/* xmit commands pending */
9925881Ssam 	struct	vxcmd *vs_avail;/* next available command buffer */
10025881Ssam 	struct	vxcmd *vs_build;
10125881Ssam 	struct	vxcmd vs_lst[NVCXBUFS];
10225881Ssam 	struct	vcmds vs_cmds;
10325881Ssam } vx_softc[NVX];
10424003Ssam 
10537608Smarc struct speedtab vxspeedtab[] = {
10637608Smarc 	EXTA,	V19200,
10737608Smarc 	EXTB,	V19200,
10837608Smarc 	19200,	V19200,
10937608Smarc 	9600,	13,
11037608Smarc 	4800,	12,
11137608Smarc 	2400,	11,
11237608Smarc 	1800,	10,
11337608Smarc 	1200,	9,
11437608Smarc 	600,	8,
11537608Smarc 	300,	7,
11637608Smarc 	200,	6,
11737608Smarc 	150,	5,
11837608Smarc 	134,	4,
11937608Smarc 	110,	3,
12037608Smarc 	75,	2,
12137608Smarc 	50,	1,
12237608Smarc 	0,	0,
12337608Smarc 	-1,	-1,
12437608Smarc };
12537608Smarc 
vxprobe(reg,vi)12625857Ssam vxprobe(reg, vi)
12724003Ssam 	caddr_t reg;
12825857Ssam 	struct vba_device *vi;
12924003Ssam {
13025857Ssam 	register int br, cvec;			/* must be r12, r11 */
13138114Sbostic 	register struct vxdevice *vp;
13225881Ssam 	register struct vx_softc *vs;
13338114Sbostic 	struct pte *dummypte;
13424003Ssam 
13524003Ssam #ifdef lint
13624003Ssam 	br = 0; cvec = br; br = cvec;
13740738Skarels 	vackint(0); vunsol(0); vcmdrsp(0);
13840738Skarels #ifdef VX_DEBUG
13940738Skarels 	vxfreset(0);
14024003Ssam #endif
14140738Skarels #endif /* lint */
14240738Skarels 	/*
14340738Skarels 	 * If on an HCX-9, the device has a 32-bit address,
14440738Skarels 	 * and we receive that address so we can set up a map.
14540738Skarels 	 * On VERSAbus devices, the address is 24-bit, and is
14640738Skarels 	 * already mapped (into vmem[]) by autoconf.
14740738Skarels 	 */
14840738Skarels 	if (!(reg >= vmem && reg < &vmem[ctob(VBIOSIZE)]) &&	/* XXX */
14940738Skarels 	    !vbmemalloc(16, reg, &dummypte, &reg)) {
15038114Sbostic 		printf("vx%d: vbmemalloc failed.\n", vi->ui_unit);
15138114Sbostic 		return(0);
15238114Sbostic 	}
15338114Sbostic 	vp = (struct vxdevice *)reg;
15425675Ssam 	if (badaddr((caddr_t)vp, 1))
15525675Ssam 		return (0);
15625675Ssam 	vp->v_fault = 0;
15725675Ssam 	vp->v_vioc = V_BSY;
15825675Ssam 	vp->v_hdwre = V_RESET;		/* reset interrupt */
15924003Ssam 	DELAY(4000000);
16025881Ssam 	if (vp->v_fault != VXF_READY)
16125675Ssam 		return (0);
16225881Ssam 	vs = &vx_softc[vi->ui_unit];
16325857Ssam #ifdef notdef
16425857Ssam 	/*
16525857Ssam 	 * Align vioc interrupt vector base to 4 vector
16625857Ssam 	 * boundary and fitting in 8 bits (is this necessary,
16725857Ssam 	 * wish we had documentation).
16825857Ssam 	 */
16925857Ssam 	if ((vi->ui_hd->vh_lastiv -= 3) > 0xff)
17025857Ssam 		vi->ui_hd->vh_lastiv = 0xff;
17125881Ssam 	vs->vs_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x3;
17225857Ssam #else
17325881Ssam 	vs->vs_ivec = 0x40+vi->ui_unit*4;
17425857Ssam #endif
17525881Ssam 	br = 0x18, cvec = vs->vs_ivec;	/* XXX */
17625881Ssam 	return (sizeof (struct vxdevice));
17724003Ssam }
17824003Ssam 
vxattach(vi)17925857Ssam vxattach(vi)
18025857Ssam 	register struct vba_device *vi;
18124003Ssam {
18240738Skarels 	register struct vx_softc *vs = &vx_softc[vi->ui_unit];
18325675Ssam 
18440738Skarels 	vs->vs_softCAR = vi->ui_flags;
18540738Skarels 	vs->vs_addr = (struct vxdevice *)vi->ui_addr;
18629954Skarels 	vxinit(vi->ui_unit, 1);
18724003Ssam }
18824003Ssam 
18924003Ssam /*
19024003Ssam  * Open a VX line.
19124003Ssam  */
19225675Ssam /*ARGSUSED*/
vxopen(dev,flag)19324003Ssam vxopen(dev, flag)
19425881Ssam 	dev_t dev;
19525881Ssam 	int flag;
19624003Ssam {
19724003Ssam 	register struct tty *tp;	/* pointer to tty struct for port */
19825881Ssam 	register struct vx_softc *vs;
19925881Ssam 	register struct vba_device *vi;
20040738Skarels 	int unit, vx, s, error = 0;
20137608Smarc 	int vxparam();
20224003Ssam 
20325881Ssam 	unit = minor(dev);
20430372Skarels 	vx = VXUNIT(unit);
20530372Skarels 	if (vx >= NVX || (vi = vxinfo[vx])== 0 || vi->ui_alive == 0)
20625881Ssam 		return (ENXIO);
20730372Skarels 	vs = &vx_softc[vx];
20825881Ssam 	tp = &vx_tty[unit];
20930372Skarels 	unit = VXPORT(unit);
21025881Ssam 	if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
21125881Ssam 		return (EBUSY);
21230372Skarels 	if (unit < vs->vs_loport || unit > vs->vs_hiport)
21325881Ssam 		return (ENXIO);
21425881Ssam 	tp->t_addr = (caddr_t)vs;
21525881Ssam 	tp->t_oproc = vxstart;
21637608Smarc 	tp->t_param = vxparam;
21725881Ssam 	tp->t_dev = dev;
21825881Ssam 	s = spl8();
21925881Ssam 	if ((tp->t_state&TS_ISOPEN) == 0) {
22042951Smarc 		tp->t_state |= TS_WOPEN;
22125881Ssam 		ttychars(tp);
22225881Ssam 		if (tp->t_ispeed == 0) {
22337608Smarc 			tp->t_iflag = TTYDEF_IFLAG;
22437608Smarc 			tp->t_oflag = TTYDEF_OFLAG;
22537608Smarc 			tp->t_lflag = TTYDEF_LFLAG;
22637608Smarc 			tp->t_cflag = TTYDEF_CFLAG;
22737608Smarc 			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
22824003Ssam 		}
22937608Smarc 		vxparam(tp, &tp->t_termios);
23037608Smarc 		ttsetwater(tp);
23124003Ssam 	}
23230372Skarels 	vcmodem(dev, VMOD_ON);
23337608Smarc 	while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
23442957Smarc 	      (tp->t_state&TS_CARR_ON) == 0) {
23542951Smarc 		tp->t_state |= TS_WOPEN;
23644397Smarc 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
23744397Smarc 		    ttopen, 0))
23840738Skarels 			break;
23942957Smarc 	}
24040738Skarels 	if (error == 0)
24140738Skarels 		error = (*linesw[tp->t_line].l_open)(dev,tp);
24225881Ssam 	splx(s);
24325881Ssam 	return (error);
24424003Ssam }
24524003Ssam 
24624003Ssam /*
24724003Ssam  * Close a VX line.
24824003Ssam  */
24925675Ssam /*ARGSUSED*/
vxclose(dev,flag,mode,p)250*49755Smarc vxclose(dev, flag, mode, p)
25125881Ssam 	dev_t dev;
252*49755Smarc 	int flag, mode;
253*49755Smarc 	struct proc *p;
25424003Ssam {
25524003Ssam 	register struct tty *tp;
25640738Skarels 	int unit, s, error = 0;
25724003Ssam 
25825881Ssam 	unit = minor(dev);
25925881Ssam 	tp = &vx_tty[unit];
26025881Ssam 	s = spl8();
261*49755Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
26237608Smarc 	if (tp->t_cflag & HUPCL || (tp->t_state & TS_ISOPEN) == 0)
26330372Skarels 		vcmodem(dev, VMOD_OFF);
26424003Ssam 	/* wait for the last response */
26540738Skarels 	while (tp->t_state&TS_FLUSH && error == 0)
26640738Skarels 		error = tsleep((caddr_t)&tp->t_state, TTOPRI | PCATCH,
26740738Skarels 		    ttclos, 0);
26825881Ssam 	splx(s);
26940738Skarels 	if (error)
27040738Skarels 		return (error);
27140738Skarels 	return (ttyclose(tp));
27224003Ssam }
27324003Ssam 
27424003Ssam /*
27524003Ssam  * Read from a VX line.
27624003Ssam  */
vxread(dev,uio,flag)27737608Smarc vxread(dev, uio, flag)
27824003Ssam 	dev_t dev;
27924003Ssam 	struct uio *uio;
28024003Ssam {
28125881Ssam 	struct tty *tp = &vx_tty[minor(dev)];
28225881Ssam 
28337608Smarc 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
28424003Ssam }
28524003Ssam 
28624003Ssam /*
28724003Ssam  * write on a VX line
28824003Ssam  */
vxwrite(dev,uio,flag)28937608Smarc vxwrite(dev, uio, flag)
29024003Ssam 	dev_t dev;
29124003Ssam 	struct uio *uio;
29224003Ssam {
29325881Ssam 	register struct tty *tp = &vx_tty[minor(dev)];
29425881Ssam 
29537608Smarc 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
29624003Ssam }
29724003Ssam 
29824003Ssam /*
29924003Ssam  * VIOCX unsolicited interrupt.
30024003Ssam  */
vxrint(vx)30125881Ssam vxrint(vx)
30225881Ssam 	register vx;
30324003Ssam {
30425881Ssam 	register struct tty *tp, *tp0;
30525881Ssam 	register struct vxdevice *addr;
30625881Ssam 	register struct vx_softc *vs;
30725881Ssam 	struct vba_device *vi;
30825881Ssam 	register int nc, c;
30925881Ssam 	register struct silo {
31040738Skarels 		u_char	data, port;
31125881Ssam 	} *sp;
31225881Ssam 	short *osp;
31325881Ssam 	int overrun = 0;
31424003Ssam 
31525881Ssam 	vi = vxinfo[vx];
31625881Ssam 	if (vi == 0 || vi->ui_alive == 0)
31725881Ssam 		return;
31825881Ssam 	addr = (struct vxdevice *)vi->ui_addr;
31925881Ssam 	switch (addr->v_uqual&037) {
32024003Ssam 	case 0:
32124003Ssam 		break;
32224003Ssam 	case 2:
32340738Skarels 		if (addr->v_ustat == VP_SILO_OFLOW)
32440738Skarels 			log(LOG_ERR, "vx%d: input silo overflow\n", vx);
32540738Skarels 		else {
32640738Skarels 			printf("vx%d: vc proc err, ustat %x\n",
32740738Skarels 			    vx, addr->v_ustat);
32840738Skarels 			vxstreset(vx);
32940738Skarels 		}
33030372Skarels 		return;
33124003Ssam 	case 3:
33225881Ssam 		vcmintr(vx);
33330372Skarels 		return;
33424003Ssam 	case 4:
33530372Skarels 		return;
33624003Ssam 	default:
33730372Skarels 		printf("vx%d: vc uqual err, uqual %x\n", vx, addr->v_uqual);
33825881Ssam 		vxstreset(vx);
33930372Skarels 		return;
34024003Ssam 	}
34125881Ssam 	vs = &vx_softc[vx];
34225881Ssam 	if (vs->vs_vers == VXV_NEW)
34325881Ssam 		sp = (struct silo *)((caddr_t)addr + *(short *)addr->v_usdata);
34425881Ssam 	else
34525881Ssam 		sp = (struct silo *)((caddr_t)addr+VX_SILO+(addr->v_usdata[0]<<6));
34625881Ssam 	nc = *(osp = (short *)sp);
34725881Ssam 	if (nc == 0)
34830372Skarels 		return;
34925881Ssam 	if (vs->vs_vers == VXV_NEW && nc > vs->vs_silosiz) {
35025881Ssam 		printf("vx%d: %d exceeds silo size\n", nc);
35125881Ssam 		nc = vs->vs_silosiz;
35224003Ssam 	}
35325881Ssam 	tp0 = &vx_tty[vx*16];
35425881Ssam 	sp = (struct silo *)(((short *)sp)+1);
35525881Ssam 	for (; nc > 0; nc--, sp = (struct silo *)(((short *)sp)+1)) {
35625881Ssam 		c = sp->port & 017;
35725881Ssam 		if (vs->vs_loport > c || c > vs->vs_hiport)
35825881Ssam 			continue;
35925881Ssam 		tp = tp0 + c;
36025881Ssam 		if( (tp->t_state&TS_ISOPEN) == 0) {
36124003Ssam 			wakeup((caddr_t)&tp->t_rawq);
36224003Ssam 			continue;
36324003Ssam 		}
36437608Smarc 		c = sp->data&((tp->t_cflag&CSIZE)==CS8 ? 0xff : 0x7f);
36525881Ssam 		if ((sp->port&VX_RO) == VX_RO && !overrun) {
36629954Skarels 			log(LOG_ERR, "vx%d: receiver overrun\n", vi->ui_unit);
36725881Ssam 			overrun = 1;
36825881Ssam 			continue;
36925881Ssam 		}
37025881Ssam 		if (sp->port&VX_PE)
37137608Smarc 			c |= TTY_PE;
37237608Smarc 		if (sp->port&VX_FE)
37337608Smarc 			c |= TTY_FE;
37424003Ssam 		(*linesw[tp->t_line].l_rint)(c, tp);
37524003Ssam 	}
37625881Ssam 	*osp = 0;
37724003Ssam }
37824003Ssam 
37924003Ssam /*
38025881Ssam  * Ioctl for VX.
38124003Ssam  */
vxioctl(dev,cmd,data,flag)38224003Ssam vxioctl(dev, cmd, data, flag)
38325881Ssam 	dev_t dev;
38425881Ssam 	caddr_t	data;
38524003Ssam {
38625881Ssam 	register struct tty *tp;
38725881Ssam 	int error;
38824003Ssam 
38925881Ssam 	tp = &vx_tty[minor(dev)];
39024003Ssam 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
39137608Smarc 	if (error >= 0)
39225881Ssam 		return (error);
39325881Ssam 	error = ttioctl(tp, cmd, data, flag);
39437608Smarc 	if (error >= 0)
39525881Ssam 		return (error);
39625881Ssam 	return (ENOTTY);
39724003Ssam }
39824003Ssam 
39937608Smarc vxparam(tp, t)
40037608Smarc 	struct tty *tp;
40137608Smarc 	struct termios *t;
40224003Ssam {
40325881Ssam 
40437608Smarc 	return (vxcparam(tp, t, 1));
40524003Ssam }
40624003Ssam 
40724003Ssam /*
40824003Ssam  * Set parameters from open or stty into the VX hardware
40924003Ssam  * registers.
41024003Ssam  */
41137608Smarc vxcparam(tp, t, wait)
41237608Smarc 	struct tty *tp;
41337608Smarc 	struct termios *t;
41425881Ssam 	int wait;
41524003Ssam {
41625881Ssam 	register struct vx_softc *vs;
41725881Ssam 	register struct vxcmd *cp;
41840738Skarels 	int s, error = 0;
41937608Smarc 	int speedcode = ttspeedtab(t->c_ospeed, vxspeedtab);
42024003Ssam 
42137608Smarc 	if (speedcode < 0 || (t->c_ispeed != t->c_ospeed && t->c_ispeed))
42240738Skarels 		return (EINVAL);
42325881Ssam 	vs = (struct vx_softc *)tp->t_addr;
42425881Ssam 	cp = vobtain(vs);
42524003Ssam 	s = spl8();
42625933Ssam 	/*
42725933Ssam 	 * Construct ``load parameters'' command block
42825933Ssam 	 * to setup baud rates, xon-xoff chars, parity,
42925933Ssam 	 * and stop bits for the specified port.
43025933Ssam 	 */
43125933Ssam 	cp->cmd = VXC_LPARAX;
43240738Skarels 	cp->par[1] = VXPORT(minor(tp->t_dev));
43337608Smarc 	/*
43437608Smarc 	 * note: if the hardware does flow control, ^V doesn't work
43537608Smarc 	 * to escape ^S
43637608Smarc 	 */
43737608Smarc 	if (t->c_iflag&IXON) {
43837608Smarc 		if (t->c_cc[VSTART] == _POSIX_VDISABLE)
43937608Smarc 			cp->par[2] = 0;
44037608Smarc 		else
44137608Smarc 			cp->par[2] = t->c_cc[VSTART];
44237608Smarc 		if (t->c_cc[VSTOP] == _POSIX_VDISABLE)
44337608Smarc 			cp->par[3] = 0;
44437608Smarc 		else
44537608Smarc 			cp->par[3] = t->c_cc[VSTOP];
44637608Smarc 	} else
44737608Smarc 		cp->par[2] = cp->par[3] = 0;
44830372Skarels #ifdef notnow
44940738Skarels 	switch (t->c_cflag & CSIZE) {	/* XXX */
45040738Skarels 	case CS8:
45130372Skarels #endif
45230372Skarels 		cp->par[4] = BITS8;		/* 8 bits of data */
45330372Skarels #ifdef notnow
45440738Skarels 		break;
45540738Skarels 	case CS7:
45630372Skarels 		cp->par[4] = BITS7;		/* 7 bits of data */
45740738Skarels 		break;
45840738Skarels 	case CS6:
45940738Skarels 		cp->par[4] = BITS6;		/* 6 bits of data */
46040738Skarels 		break;
46140738Skarels 	case CS5:
46240738Skarels 		cp->par[4] = BITS5;		/* 5 bits of data */
46340738Skarels 		break;
46424003Ssam 	}
46540738Skarels 	if ((t->c_cflag & PARENB) == 0)		/* XXX */
46630372Skarels #endif
46740738Skarels 		cp->par[7] = VNOPARITY;		/* no parity */
46840738Skarels #ifdef notnow
46940738Skarels 	else if (t->c_cflag&PARODD)
47040738Skarels 		cp->par[7] = VODDP;	/* odd parity */
47140738Skarels 	else
47240738Skarels 		cp->par[7] = VEVENP;	/* even parity */
47340738Skarels #endif
47437608Smarc 	cp->par[5] = (t->c_cflag&CSTOPB) ? VSTOP2 : VSTOP1;
47537608Smarc 	cp->par[6] = speedcode;
47630372Skarels 	if (vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd) && wait)
47740738Skarels 		error = tsleep((caddr_t)cp, TTIPRI | PCATCH, ttyout, 0);
47837608Smarc 	if ((t->c_ospeed)==0) {
47937608Smarc 		tp->t_cflag |= HUPCL;
48040738Skarels 		vcmodem(tp->t_dev, VMOD_OFF);
48137608Smarc 	}
48224003Ssam 	splx(s);
48340738Skarels 	return (error);
48424003Ssam }
48524003Ssam 
48624003Ssam /*
48724003Ssam  * VIOCX command response interrupt.
48824003Ssam  * For transmission, restart output to any active port.
48924003Ssam  * For all other commands, just clean up.
49024003Ssam  */
vxxint(vx,cp)49125881Ssam vxxint(vx, cp)
49225881Ssam 	register int vx;
49325881Ssam 	register struct vxcmd *cp;
49424003Ssam {
49530372Skarels 	register struct vxmit *vp;
49625933Ssam 	register struct tty *tp, *tp0;
49725933Ssam 	register struct vx_softc *vs;
49824003Ssam 
49925881Ssam 	vs = &vx_softc[vx];
50025881Ssam 	cp = (struct vxcmd *)((long *)cp-1);
50129954Skarels 
50225881Ssam 	switch (cp->cmd&0xff00) {
50325881Ssam 
50425881Ssam 	case VXC_LIDENT:	/* initialization complete */
50525881Ssam 		if (vs->vs_state == VXS_RESET) {
50625881Ssam 			vxfnreset(vx, cp);
50725881Ssam 			vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
50824003Ssam 		}
50924003Ssam 		cp->cmd++;
51024003Ssam 		return;
51125881Ssam 
51225881Ssam 	case VXC_XMITDTA:
51325881Ssam 	case VXC_XMITIMM:
51424003Ssam 		break;
51525881Ssam 
51625881Ssam 	case VXC_LPARAX:
51725675Ssam 		wakeup((caddr_t)cp);
51825881Ssam 		/* fall thru... */
51925881Ssam 	default:	/* VXC_MDMCTL or VXC_FDTATOX */
52025881Ssam 		vrelease(vs, cp);
52125881Ssam 		if (vs->vs_state == VXS_RESET)
52225881Ssam 			vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
52324003Ssam 		return;
52424003Ssam 	}
52525881Ssam 	tp0 = &vx_tty[vx*16];
52625881Ssam 	vp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizeof (struct vxmit));
52725881Ssam 	for (; vp >= (struct vxmit *)cp->par; vp--) {
52825881Ssam 		tp = tp0 + (vp->line & 017);
52924003Ssam 		tp->t_state &= ~TS_BUSY;
53025881Ssam 		if (tp->t_state & TS_FLUSH) {
53124003Ssam 			tp->t_state &= ~TS_FLUSH;
53225881Ssam 			wakeup((caddr_t)&tp->t_state);
53325881Ssam 		} else
53424003Ssam 		 	ndflush(&tp->t_outq, vp->bcount+1);
53524003Ssam 	}
53625881Ssam 	vrelease(vs, cp);
53730372Skarels 	if (vs->vs_vers == VXV_NEW)
53832112Skarels 		(*linesw[tp->t_line].l_start)(tp);
53930372Skarels 	else {
54025881Ssam 		tp0 = &vx_tty[vx*16 + vs->vs_hiport];
54125881Ssam 		for(tp = &vx_tty[vx*16 + vs->vs_loport]; tp <= tp0; tp++)
54232112Skarels 			(*linesw[tp->t_line].l_start)(tp);
54325881Ssam 		if ((cp = nextcmd(vs)) != NULL) {	/* command to send? */
54425881Ssam 			vs->vs_xmtcnt++;
54530372Skarels 			(void) vcmd(vx, (caddr_t)&cp->cmd);
54624003Ssam 		}
54724003Ssam 	}
54830372Skarels 	vs->vs_xmtcnt--;
54924003Ssam }
55024003Ssam 
55124003Ssam /*
55224003Ssam  * Force out partial XMIT command after timeout
55324003Ssam  */
vxforce(vs)55425881Ssam vxforce(vs)
55525881Ssam 	register struct vx_softc *vs;
55624003Ssam {
55725881Ssam 	register struct vxcmd *cp;
55825881Ssam 	int s;
55924003Ssam 
56024003Ssam 	s = spl8();
56125881Ssam 	if ((cp = nextcmd(vs)) != NULL) {
56225881Ssam 		vs->vs_xmtcnt++;
56330372Skarels 		(void) vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd);
56424003Ssam 	}
56524003Ssam 	splx(s);
56624003Ssam }
56724003Ssam 
56824003Ssam /*
56924003Ssam  * Start (restart) transmission on the given VX line.
57024003Ssam  */
vxstart(tp)57124003Ssam vxstart(tp)
57225881Ssam 	register struct tty *tp;
57324003Ssam {
57425675Ssam 	register short n;
57525933Ssam 	register struct vx_softc *vs;
57625933Ssam 	int s, port;
57724003Ssam 
57824003Ssam 	s = spl8();
57940738Skarels 	port = VXPORT(minor(tp->t_dev));
58025881Ssam 	vs = (struct vx_softc *)tp->t_addr;
58125881Ssam 	if ((tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) == 0) {
58237608Smarc 		if (tp->t_outq.c_cc <= tp->t_lowat) {
58324003Ssam 			if (tp->t_state&TS_ASLEEP) {
58424003Ssam 				tp->t_state &= ~TS_ASLEEP;
58524003Ssam 				wakeup((caddr_t)&tp->t_outq);
58624003Ssam 			}
58724003Ssam 			if (tp->t_wsel) {
58824003Ssam 				selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
58924003Ssam 				tp->t_wsel = 0;
59024003Ssam 				tp->t_state &= ~TS_WCOLL;
59124003Ssam 			}
59224003Ssam 		}
59325881Ssam 		if (tp->t_outq.c_cc == 0) {
59424003Ssam 			splx(s);
59530372Skarels 			return;
59624003Ssam 		}
59725877Ssam 		scope_out(3);
59837608Smarc 		if (1 || !(tp->t_oflag&OPOST))	/* XXX */
59930372Skarels 			n = ndqb(&tp->t_outq, 0);
60030372Skarels 		else {
60130372Skarels 			n = ndqb(&tp->t_outq, 0200);
60230372Skarels 			if (n == 0) {
60325675Ssam 				n = getc(&tp->t_outq);
60425881Ssam 				timeout(ttrstrt, (caddr_t)tp, (n&0177)+6);
60524003Ssam 				tp->t_state |= TS_TIMEOUT;
60630372Skarels 				n = 0;
60724003Ssam 			}
60830372Skarels 		}
60930372Skarels 		if (n) {
61024003Ssam 			tp->t_state |= TS_BUSY;
61130372Skarels 			vsetq(vs, port, (char *)tp->t_outq.c_cf, n);
61224003Ssam 		}
61324003Ssam 	}
61424003Ssam 	splx(s);
61524003Ssam }
61624003Ssam 
61724003Ssam /*
61824003Ssam  * Stop output on a line.
61924003Ssam  */
vxstop(tp)62024003Ssam vxstop(tp)
62125881Ssam 	register struct tty *tp;
62224003Ssam {
62325881Ssam 	int s;
62424003Ssam 
62524003Ssam 	s = spl8();
62625881Ssam 	if (tp->t_state&TS_BUSY)
62725881Ssam 		if ((tp->t_state&TS_TTSTOP) == 0)
62824003Ssam 			tp->t_state |= TS_FLUSH;
62924003Ssam 	splx(s);
63024003Ssam }
63124003Ssam 
63225881Ssam static	int vxbbno = -1;
63324003Ssam /*
63424003Ssam  * VIOCX Initialization.  Makes free lists of command buffers.
63524003Ssam  * Resets all viocx's.  Issues a LIDENT command to each
63625933Ssam  * viocx to establish interrupt vectors and logical port numbers.
63724003Ssam  */
vxinit(vx,wait)63840738Skarels vxinit(vx, wait)
63925881Ssam 	register int vx;
64025881Ssam 	int wait;
64124003Ssam {
64225933Ssam 	register struct vx_softc *vs;
64325933Ssam 	register struct vxdevice *addr;
64425933Ssam 	register struct vxcmd *cp;
64525881Ssam 	register char *resp;
64625881Ssam 	register int j;
64730372Skarels 	char type, *typestring;
64824003Ssam 
64925881Ssam 	vs = &vx_softc[vx];
65040738Skarels 	addr = vs->vs_addr;
65125881Ssam 	type = addr->v_ident;
65225881Ssam 	vs->vs_vers = (type&VXT_NEW) ? VXV_NEW : VXV_OLD;
65325881Ssam 	if (vs->vs_vers == VXV_NEW)
65425881Ssam 		vs->vs_silosiz = addr->v_maxsilo;
65525881Ssam 	switch (type) {
65624003Ssam 
65725881Ssam 	case VXT_VIOCX:
65825881Ssam 	case VXT_VIOCX|VXT_NEW:
65930372Skarels 		typestring = "VIOC-X";
66030372Skarels 		/* set soft carrier for printer ports */
66130372Skarels 		for (j = 0; j < 16; j++)
66240738Skarels 			if (vs->vs_softCAR & (1 << j) ||
66340738Skarels 			    addr->v_portyp[j] == VXT_PARALLEL) {
66430372Skarels 				vs->vs_softCAR |= 1 << j;
66525881Ssam 				addr->v_dcd |= 1 << j;
66630372Skarels 			}
66725881Ssam 		break;
66824003Ssam 
66925881Ssam 	case VXT_PVIOCX:
67025881Ssam 	case VXT_PVIOCX|VXT_NEW:
67130372Skarels 		typestring = "VIOC-X (old connector panel)";
67225881Ssam 		break;
67325881Ssam 	case VXT_VIOCBOP:		/* VIOC-BOP */
67425881Ssam 		vs->vs_type = 1;
67525881Ssam 		vs->vs_bop = ++vxbbno;
67625881Ssam 		printf("VIOC-BOP no. %d at %x\n", vs->vs_bop, addr);
67740738Skarels 		goto unsup;
67825933Ssam 	default:
67925881Ssam 		printf("vx%d: unknown type %x\n", vx, type);
68040738Skarels 	unsup:
68130372Skarels 		vxinfo[vx]->ui_alive = 0;
68225881Ssam 		return;
68324003Ssam 	}
68440738Skarels 	vs->vs_nbr = vx;		/* assign board number */
68525933Ssam 	vs->vs_maxcmd = (vs->vs_vers == VXV_NEW) ? 24 : 4;
68625933Ssam 	/*
68725933Ssam 	 * Initialize all cmd buffers by linking them
68825933Ssam 	 * into a free list.
68925933Ssam 	 */
69025881Ssam 	for (j = 0; j < NVCXBUFS; j++) {
69125933Ssam 		cp = &vs->vs_lst[j];
69225933Ssam 		cp->c_fwd = &vs->vs_lst[j+1];
69325881Ssam 	}
69425881Ssam 	vs->vs_avail = &vs->vs_lst[0];	/* set idx to 1st free buf */
69524003Ssam 	cp->c_fwd = (struct vxcmd *)0;	/* mark last buf in free list */
69624003Ssam 
69725933Ssam 	/*
69825933Ssam 	 * Establish the interrupt vectors and define the port numbers.
69925933Ssam 	 */
70025933Ssam 	cp = vobtain(vs);
70125933Ssam 	cp->cmd = VXC_LIDENT;
70225881Ssam 	cp->par[0] = vs->vs_ivec; 	/* ack vector */
70325857Ssam 	cp->par[1] = cp->par[0]+1;	/* cmd resp vector */
70425857Ssam 	cp->par[3] = cp->par[0]+2;	/* unsol intr vector */
70525881Ssam 	cp->par[4] = 15;		/* max ports, no longer used */
70625881Ssam 	cp->par[5] = 0;			/* set 1st port number */
70730372Skarels 	(void) vcmd(vx, (caddr_t)&cp->cmd);
70825881Ssam 	if (!wait)
70925881Ssam 		return;
71040738Skarels 
71125881Ssam 	for (j = 0; cp->cmd == VXC_LIDENT && j < 4000000; j++)
71225857Ssam 		;
71325857Ssam 	if (j >= 4000000)
71425881Ssam 		printf("vx%d: didn't respond to LIDENT\n", vx);
71524003Ssam 
71624003Ssam  	/* calculate address of response buffer */
71725881Ssam  	resp = (char *)addr + (addr->v_rspoff&0x3fff);
71825933Ssam 	if (resp[0] != 0 && (resp[0]&0177) != 3) {
71925933Ssam 		vrelease(vs, cp);	/* init failed */
72025881Ssam 		return;
72124003Ssam 	}
72225881Ssam 	vs->vs_loport = cp->par[5];
72325881Ssam 	vs->vs_hiport = cp->par[7];
72430372Skarels 	printf("vx%d: %s%s, ports %d-%d\n", vx,
72530372Skarels 	    (vs->vs_vers == VXV_NEW) ? "" : "old ", typestring,
72630372Skarels 	    vs->vs_loport, vs->vs_hiport);
72725881Ssam 	vrelease(vs, cp);
72824003Ssam }
72924003Ssam 
73024003Ssam /*
73124003Ssam  * Obtain a command buffer
73224003Ssam  */
73325881Ssam struct vxcmd *
vobtain(vs)73425881Ssam vobtain(vs)
73525933Ssam 	register struct vx_softc *vs;
73624003Ssam {
73725933Ssam 	register struct vxcmd *p;
73825881Ssam 	int s;
73924003Ssam 
74024003Ssam 	s = spl8();
74125881Ssam 	p = vs->vs_avail;
74225881Ssam 	if (p == (struct vxcmd *)0) {
74324003Ssam #ifdef VX_DEBUG
74425881Ssam 		if (vxintr4&VXNOBUF)
74525881Ssam 			vxintr4 &= ~VXNOBUF;
74624003Ssam #endif
74740738Skarels 		printf("vx%d: no buffers\n", vs->vs_nbr);
74840738Skarels 		vxstreset(vs->vs_nbr);
74924003Ssam 		splx(s);
75025881Ssam 		return (vobtain(vs));
75124003Ssam 	}
75230372Skarels 	vs->vs_avail = p->c_fwd;
75324003Ssam 	splx(s);
75425881Ssam 	return ((struct vxcmd *)p);
75524003Ssam }
75624003Ssam 
75724003Ssam /*
75824003Ssam  * Release a command buffer
75924003Ssam  */
vrelease(vs,cp)76025881Ssam vrelease(vs, cp)
76125933Ssam 	register struct vx_softc *vs;
76225933Ssam 	register struct vxcmd *cp;
76324003Ssam {
76425881Ssam 	int s;
76524003Ssam 
76624003Ssam #ifdef VX_DEBUG
76725881Ssam 	if (vxintr4&VXNOBUF)
76825881Ssam 		return;
76924003Ssam #endif
77024003Ssam 	s = spl8();
77125881Ssam 	cp->c_fwd = vs->vs_avail;
77225881Ssam 	vs->vs_avail = cp;
77324003Ssam 	splx(s);
77424003Ssam }
77524003Ssam 
77625881Ssam struct vxcmd *
nextcmd(vs)77725881Ssam nextcmd(vs)
77825933Ssam 	register struct vx_softc *vs;
77924003Ssam {
78025933Ssam 	register struct vxcmd *cp;
78125881Ssam 	int s;
78224003Ssam 
78324003Ssam 	s = spl8();
78425881Ssam 	cp = vs->vs_build;
78525881Ssam 	vs->vs_build = (struct vxcmd *)0;
78624003Ssam 	splx(s);
78725881Ssam 	return (cp);
78824003Ssam }
78924003Ssam 
79024003Ssam /*
79125933Ssam  * Assemble transmits into a multiple command;
79230372Skarels  * up to 8 transmits to 8 lines can be assembled together
79330372Skarels  * (on PVIOCX only).
79424003Ssam  */
vsetq(vs,line,addr,n)79525933Ssam vsetq(vs, line, addr, n)
79625933Ssam 	register struct vx_softc *vs;
79725881Ssam 	caddr_t	addr;
79824003Ssam {
79925933Ssam 	register struct vxcmd *cp;
80025933Ssam 	register struct vxmit *mp;
80124003Ssam 
80225933Ssam 	/*
80325933Ssam 	 * Grab a new command buffer or append
80425933Ssam 	 * to the current one being built.
80525933Ssam 	 */
80625881Ssam 	cp = vs->vs_build;
80725881Ssam 	if (cp == (struct vxcmd *)0) {
80825881Ssam 		cp = vobtain(vs);
80925881Ssam 		vs->vs_build = cp;
81025881Ssam 		cp->cmd = VXC_XMITDTA;
81124003Ssam 	} else {
81230372Skarels 		if ((cp->cmd & 07) == 07 || vs->vs_vers == VXV_NEW) {
81325881Ssam 			printf("vx%d: setq overflow\n", vs-vx_softc);
81430372Skarels 			vxstreset((int)vs->vs_nbr);
81530372Skarels 			return;
81624003Ssam 		}
81724003Ssam 		cp->cmd++;
81824003Ssam 	}
81925933Ssam 	/*
82025933Ssam 	 * Select the next vxmit buffer and copy the
82125933Ssam 	 * characters into the buffer (if there's room
82225933Ssam 	 * and the device supports ``immediate mode'',
82325933Ssam 	 * or store an indirect pointer to the data.
82425933Ssam 	 */
82525881Ssam 	mp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizeof (struct vxmit));
82625675Ssam 	mp->bcount = n-1;
82725933Ssam 	mp->line = line;
82825933Ssam 	if (vs->vs_vers == VXV_NEW && n <= sizeof (mp->ostream)) {
82925881Ssam 		cp->cmd = VXC_XMITIMM;
83030372Skarels 		bcopy(addr, mp->ostream, (unsigned)n);
83124003Ssam 	} else {
83225933Ssam 		/* get system address of clist block */
83325675Ssam 		addr = (caddr_t)vtoph((struct proc *)0, (unsigned)addr);
83430372Skarels 		bcopy((caddr_t)&addr, mp->ostream, sizeof (addr));
83524003Ssam 	}
83630372Skarels 	/*
83730372Skarels 	 * We send the data immediately if a VIOCX,
83830372Skarels 	 * the command buffer is full, or if we've nothing
83930372Skarels 	 * currently outstanding.  If we don't send it,
84030372Skarels 	 * set a timeout to force the data to be sent soon.
84130372Skarels 	 */
84230372Skarels 	if (vs->vs_vers == VXV_NEW || (cp->cmd & 07) == 7 ||
84330372Skarels 	    vs->vs_xmtcnt == 0) {
84430372Skarels 		vs->vs_xmtcnt++;
84530372Skarels 		(void) vcmd((int)vs->vs_nbr, (char *)&cp->cmd);
84630372Skarels 		vs->vs_build = 0;
84730372Skarels 	} else
84830372Skarels 		timeout(vxforce, (caddr_t)vs, 3);
84924003Ssam }
85025881Ssam 
85125881Ssam /*
85225881Ssam  * Write a command out to the VIOC
85325881Ssam  */
vcmd(vx,cmdad)85425881Ssam vcmd(vx, cmdad)
85525881Ssam 	register int vx;
85625881Ssam 	register caddr_t cmdad;
85725881Ssam {
85825933Ssam 	register struct vcmds *cp;
85940738Skarels 	register struct vx_softc *vs = &vx_softc[vx];
86025881Ssam 	int s;
86125881Ssam 
86225881Ssam 	s = spl8();
86325933Ssam 	/*
86425933Ssam 	 * When the vioc is resetting, don't process
86525933Ssam 	 * anything other than VXC_LIDENT commands.
86625933Ssam 	 */
86725881Ssam 	if (vs->vs_state == VXS_RESET && cmdad != NULL) {
86825933Ssam 		struct vxcmd *vcp = (struct vxcmd *)(cmdad-sizeof (vcp->c_fwd));
86925881Ssam 
87025933Ssam 		if (vcp->cmd != VXC_LIDENT) {
87125933Ssam 			vrelease(vs, vcp);
87225881Ssam 			return (0);
87325881Ssam 		}
87425881Ssam 	}
87525881Ssam 	cp = &vs->vs_cmds;
87625881Ssam 	if (cmdad != (caddr_t)0) {
87725881Ssam 		cp->cmdbuf[cp->v_fill] = cmdad;
87825881Ssam 		if (++cp->v_fill >= VC_CMDBUFL)
87925881Ssam 			cp->v_fill = 0;
88025881Ssam 		if (cp->v_fill == cp->v_empty) {
88125881Ssam 			printf("vx%d: cmd q overflow\n", vx);
88225881Ssam 			vxstreset(vx);
88325881Ssam 			splx(s);
88425881Ssam 			return (0);
88525881Ssam 		}
88625881Ssam 		cp->v_cmdsem++;
88725881Ssam 	}
88825881Ssam 	if (cp->v_cmdsem && cp->v_curcnt < vs->vs_maxcmd) {
88925881Ssam 		cp->v_cmdsem--;
89025881Ssam 		cp->v_curcnt++;
89125881Ssam 		vinthandl(vx, ((V_BSY|CMDquals) << 8)|V_INTR);
89225881Ssam 	}
89325881Ssam 	splx(s);
89425881Ssam 	return (1);
89525881Ssam }
89625881Ssam 
89725881Ssam /*
89825881Ssam  * VIOC acknowledge interrupt.  The VIOC has received the new
89925881Ssam  * command.  If no errors, the new command becomes one of 16 (max)
90025881Ssam  * current commands being executed.
90125881Ssam  */
vackint(vx)90225881Ssam vackint(vx)
90325881Ssam 	register vx;
90425881Ssam {
90525933Ssam 	register struct vxdevice *vp;
90625933Ssam 	register struct vcmds *cp;
90725881Ssam 	struct vx_softc *vs;
90825881Ssam 	int s;
90925881Ssam 
91025881Ssam 	scope_out(5);
91125881Ssam 	vs = &vx_softc[vx];
91229954Skarels 	if (vs->vs_type)	/* Its a BOP */
91325881Ssam 		return;
91425881Ssam 	s = spl8();
91540738Skarels 	vp = vs->vs_addr;
91625881Ssam 	cp = &vs->vs_cmds;
91725933Ssam 	if (vp->v_vcid&V_ERR) {
91825881Ssam 		register char *resp;
91925881Ssam 		register i;
92025933Ssam 
92130372Skarels 		printf("vx%d: ackint error type %x v_dcd %x\n", vx,
92225881Ssam 		    vp->v_vcid & 07, vp->v_dcd & 0xff);
92325881Ssam 		resp = (char *)vs->vs_mricmd;
92425881Ssam 		for (i = 0; i < 16; i++)
92525881Ssam 			printf("%x ", resp[i]&0xff);
92625881Ssam 		printf("\n");
92725881Ssam 		splx(s);
92825881Ssam 		vxstreset(vx);
92925881Ssam 		return;
93025881Ssam 	}
93125881Ssam 	if ((vp->v_hdwre&017) == CMDquals) {
93225881Ssam #ifdef VX_DEBUG
93325881Ssam 		if (vxintr4 & VXERR4) {	/* causes VIOC INTR ERR 4 */
93425933Ssam 			struct vxcmd *cp1, *cp0;
93525881Ssam 
93625933Ssam 			cp0 = (struct vxcmd *)
93725933Ssam 			    ((caddr_t)cp->cmdbuf[cp->v_empty]-sizeof (cp0->c_fwd));
93825881Ssam 			if (cp0->cmd == VXC_XMITDTA || cp0->cmd == VXC_XMITIMM) {
93925881Ssam 				cp1 = vobtain(vs);
94025881Ssam 				*cp1 = *cp0;
94125881Ssam 				vxintr4 &= ~VXERR4;
94225881Ssam 				(void) vcmd(vx, &cp1->cmd);
94325881Ssam 			}
94425881Ssam 		}
94525881Ssam #endif
94625881Ssam 		cp->v_curcmd[vp->v_vcid & VCMDLEN-1] = cp->cmdbuf[cp->v_empty];
94725881Ssam 		if (++cp->v_empty >= VC_CMDBUFL)
94825881Ssam 			cp->v_empty = 0;
94925881Ssam 	}
95025881Ssam 	if (++cp->v_itrempt >= VC_IQLEN)
95125881Ssam 		cp->v_itrempt = 0;
95225881Ssam 	vintempt(vx);
95325881Ssam 	splx(s);
95425881Ssam 	(void) vcmd(vx, (caddr_t)0);	/* queue next cmd, if any */
95525881Ssam }
95625881Ssam 
95725881Ssam /*
95825881Ssam  * Command Response interrupt.  The Vioc has completed
95925881Ssam  * a command.  The command may now be returned to
96025881Ssam  * the appropriate device driver.
96125881Ssam  */
vcmdrsp(vx)96225881Ssam vcmdrsp(vx)
96325881Ssam 	register vx;
96425881Ssam {
96525933Ssam 	register struct vxdevice *vp;
96625933Ssam 	register struct vcmds *cp;
96725881Ssam 	register caddr_t cmd;
96825881Ssam 	register struct vx_softc *vs;
96925881Ssam 	register char *resp;
97025881Ssam 	register k;
97125881Ssam 	register int s;
97225881Ssam 
97325881Ssam 	scope_out(6);
97425881Ssam 	vs = &vx_softc[vx];
97525881Ssam 	if (vs->vs_type) {	/* Its a BOP */
97625881Ssam 		printf("vx%d: vcmdrsp interrupt\n", vx);
97725881Ssam 		return;
97825881Ssam 	}
97925881Ssam 	s = spl8();
98040738Skarels 	vp = vs->vs_addr;
98125881Ssam 	cp = &vs->vs_cmds;
98225881Ssam 	resp = (char *)vp + (vp->v_rspoff&0x7fff);
98325881Ssam 	if (((k = resp[1])&V_UNBSY) == 0) {
98425881Ssam 		printf("vx%d: cmdresp debug\n", vx);
98525881Ssam 		splx(s);
98625881Ssam 		vxstreset(vx);
98725881Ssam 		return;
98825881Ssam 	}
98925881Ssam 	k &= VCMDLEN-1;
99025881Ssam 	cmd = cp->v_curcmd[k];
99125881Ssam 	cp->v_curcmd[k] = (caddr_t)0;
99225881Ssam 	cp->v_curcnt--;
99325881Ssam 	k = *((short *)&resp[4]);	/* cmd operation code */
99425881Ssam 	if ((k&0xff00) == VXC_LIDENT)	/* want hiport number */
99525881Ssam 		for (k = 0; k < VRESPLEN; k++)
99625881Ssam 			cmd[k] = resp[k+4];
99725881Ssam 	resp[1] = 0;
99825881Ssam 	vxxint(vx, (struct vxcmd *)cmd);
99925881Ssam 	if (vs->vs_state == VXS_READY)
100025881Ssam 		vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
100125881Ssam 	splx(s);
100225881Ssam }
100325881Ssam 
100425881Ssam /*
100525881Ssam  * Unsolicited interrupt.
100625881Ssam  */
vunsol(vx)100725881Ssam vunsol(vx)
100825881Ssam 	register vx;
100925881Ssam {
101025933Ssam 	register struct vxdevice *vp;
101125881Ssam 	struct vx_softc *vs;
101225881Ssam 	int s;
101325881Ssam 
101425881Ssam 	scope_out(1);
101525881Ssam 	vs = &vx_softc[vx];
101625881Ssam 	if (vs->vs_type) {	/* Its a BOP */
101725881Ssam 		printf("vx%d: vunsol from BOP\n", vx);
101825881Ssam 		return;
101925881Ssam 	}
102025881Ssam 	s = spl8();
102140738Skarels 	vp = vs->vs_addr;
102225881Ssam 	if (vp->v_uqual&V_UNBSY) {
102325881Ssam 		vxrint(vx);
102425881Ssam 		vinthandl(vx, ((V_BSY|UNSquals) << 8)|V_INTR);
102525881Ssam #ifdef notdef
102625881Ssam 	} else {
102725881Ssam 		printf("vx%d: unsolicited interrupt error\n", vx);
102825881Ssam 		splx(s);
102925881Ssam 		vxstreset(vx);
103025881Ssam #endif
103125881Ssam 	}
103225881Ssam 	splx(s);
103325881Ssam }
103425881Ssam 
103525881Ssam /*
103625933Ssam  * Enqueue an interrupt.
103725881Ssam  */
vinthandl(vx,item)103825881Ssam vinthandl(vx, item)
103925881Ssam 	register int vx;
104025881Ssam 	register item;
104125881Ssam {
104225881Ssam 	register struct vcmds *cp;
104325881Ssam 	int empty;
104425881Ssam 
104525881Ssam 	cp = &vx_softc[vx].vs_cmds;
104625933Ssam 	empty = (cp->v_itrfill == cp->v_itrempt);
104725881Ssam 	cp->v_itrqueu[cp->v_itrfill] = item;
104825881Ssam 	if (++cp->v_itrfill >= VC_IQLEN)
104925881Ssam 		cp->v_itrfill = 0;
105025881Ssam 	if (cp->v_itrfill == cp->v_itrempt) {
105125881Ssam 		printf("vx%d: interrupt q overflow\n", vx);
105225881Ssam 		vxstreset(vx);
105325881Ssam 	} else if (empty)
105425881Ssam 		vintempt(vx);
105525881Ssam }
105625881Ssam 
vintempt(vx)105725881Ssam vintempt(vx)
105840738Skarels 	int vx;
105925881Ssam {
106025881Ssam 	register struct vcmds *cp;
106125881Ssam 	register struct vxdevice *vp;
106240738Skarels 	register struct vx_softc *vs;
106325881Ssam 	register short item;
106425881Ssam 	register short *intr;
106525881Ssam 
106640738Skarels 	vs = &vx_softc[vx];
106740738Skarels 	vp = vs->vs_addr;
106825881Ssam 	if (vp->v_vioc&V_BSY)
106925881Ssam 		return;
107040738Skarels 	cp = &vs->vs_cmds;
107125881Ssam 	if (cp->v_itrempt == cp->v_itrfill)
107225881Ssam 		return;
107325881Ssam 	item = cp->v_itrqueu[cp->v_itrempt];
107425881Ssam 	intr = (short *)&vp->v_vioc;
107525881Ssam 	switch ((item >> 8)&03) {
107625881Ssam 
107725881Ssam 	case CMDquals: {		/* command */
107825881Ssam 		int phys;
107925881Ssam 
108025881Ssam 		if (cp->v_empty == cp->v_fill || vp->v_vcbsy&V_BSY)
108125881Ssam 			break;
108240738Skarels 		vs->vs_mricmd = (caddr_t)cp->cmdbuf[cp->v_empty];
108325881Ssam 		phys = vtoph((struct proc *)0,
108425881Ssam 		    (unsigned)cp->cmdbuf[cp->v_empty]);
108525881Ssam 		vp->v_vcp[0] = ((short *)&phys)[0];
108625881Ssam 		vp->v_vcp[1] = ((short *)&phys)[1];
108725881Ssam 		vp->v_vcbsy = V_BSY;
108825881Ssam 		*intr = item;
108925881Ssam 		scope_out(4);
109025881Ssam 		break;
109125881Ssam 	}
109225881Ssam 
109325881Ssam 	case RSPquals:		/* command response */
109425881Ssam 		*intr = item;
109525881Ssam 		scope_out(7);
109625881Ssam 		break;
109725881Ssam 
109825881Ssam 	case UNSquals:		/* unsolicited interrupt */
109925881Ssam 		vp->v_uqual = 0;
110025881Ssam 		*intr = item;
110125881Ssam 		scope_out(2);
110225881Ssam 		break;
110325881Ssam 	}
110425881Ssam }
110525881Ssam 
110625881Ssam /*
110725881Ssam  * Start a reset on a vioc after error (hopefully)
110825881Ssam  */
vxstreset(vx)110925881Ssam vxstreset(vx)
111040738Skarels 	register int vx;
111125881Ssam {
111225881Ssam 	register struct vx_softc *vs;
111325933Ssam 	register struct vxdevice *vp;
111425881Ssam 	register struct vxcmd *cp;
111525881Ssam 	register int j;
111625881Ssam 	extern int vxinreset();
111725881Ssam 	int s;
111825881Ssam 
111925881Ssam 	vs = &vx_softc[vx];
112040738Skarels 	s = spl8();
112125881Ssam 	if (vs->vs_state == VXS_RESET) {	/* avoid recursion */
112225881Ssam 		splx(s);
112325881Ssam 		return;
112425881Ssam 	}
112540738Skarels 	vp = vs->vs_addr;
112625881Ssam 	/*
112725881Ssam 	 * Zero out the vioc structures, mark the vioc as being
112825881Ssam 	 * reset, reinitialize the free command list, reset the vioc
112925881Ssam 	 * and start a timer to check on the progress of the reset.
113025881Ssam 	 */
113140738Skarels 	bzero((caddr_t)&vs->vs_zero,
113240738Skarels 	    (unsigned)((caddr_t)(vs + 1) - (caddr_t)&vs->vs_zero));
113325881Ssam 
113425881Ssam 	/*
113525881Ssam 	 * Setting VXS_RESET prevents others from issuing
113625881Ssam 	 * commands while allowing currently queued commands to
113725881Ssam 	 * be passed to the VIOC.
113825881Ssam 	 */
113925881Ssam 	vs->vs_state = VXS_RESET;
114025881Ssam 	/* init all cmd buffers */
114125881Ssam 	for (j = 0; j < NVCXBUFS; j++) {
114225933Ssam 		cp = &vs->vs_lst[j];
114325933Ssam 		cp->c_fwd = &vs->vs_lst[j+1];
114425881Ssam 	}
114525933Ssam 	vs->vs_avail = &vs->vs_lst[0];
114625933Ssam 	cp->c_fwd = (struct vxcmd *)0;
114725881Ssam 	printf("vx%d: reset...", vx);
114825881Ssam 	vp->v_fault = 0;
114925881Ssam 	vp->v_vioc = V_BSY;
115025933Ssam 	vp->v_hdwre = V_RESET;		/* generate reset interrupt */
115125881Ssam 	timeout(vxinreset, (caddr_t)vx, hz*5);
115225881Ssam 	splx(s);
115325881Ssam }
115425881Ssam 
115525881Ssam /* continue processing a reset on a vioc after an error (hopefully) */
vxinreset(vx)115625881Ssam vxinreset(vx)
115725881Ssam 	int vx;
115825881Ssam {
115925933Ssam 	register struct vxdevice *vp;
116025881Ssam 	int s = spl8();
116125881Ssam 
116240738Skarels 	vp = vx_softc[vx].vs_addr;
116325881Ssam 	/*
116425881Ssam 	 * See if the vioc has reset.
116525881Ssam 	 */
116625881Ssam 	if (vp->v_fault != VXF_READY) {
116740738Skarels 		printf(" vxreset failed\n");
116825881Ssam 		splx(s);
116925881Ssam 		return;
117025881Ssam 	}
117125881Ssam 	/*
117225881Ssam 	 * Send a LIDENT to the vioc and mess with carrier flags
117325881Ssam 	 * on parallel printer ports.
117425881Ssam 	 */
117529954Skarels 	vxinit(vx, 0);
117625881Ssam 	splx(s);
117725881Ssam }
117825881Ssam 
117925881Ssam /*
118025933Ssam  * Finish the reset on the vioc after an error (hopefully).
118125933Ssam  *
118225881Ssam  * Restore modem control, parameters and restart output.
118325881Ssam  * Since the vioc can handle no more then 24 commands at a time
118425881Ssam  * and we could generate as many as 48 commands, we must do this in
118525881Ssam  * phases, issuing no more then 16 commands at a time.
118625881Ssam  */
vxfnreset(vx,cp)118725881Ssam vxfnreset(vx, cp)
118825881Ssam 	register int vx;
118925881Ssam 	register struct vxcmd *cp;
119025881Ssam {
119125881Ssam 	register struct vx_softc *vs;
119240738Skarels 	register struct vxdevice *vp;
119325881Ssam 	register struct tty *tp, *tp0;
119425881Ssam 	register int i;
119525881Ssam #ifdef notdef
119625881Ssam 	register int on;
119725881Ssam #endif
119825881Ssam 	extern int vxrestart();
119925881Ssam 	int s = spl8();
120025881Ssam 
120125881Ssam 	vs = &vx_softc[vx];
120225881Ssam 	vrelease(vs, cp);
120325881Ssam 	vs->vs_state = VXS_READY;
120425881Ssam 
120540738Skarels 	vp = vs->vs_addr;
120625881Ssam 	vp->v_vcid = 0;
120725881Ssam 
120825881Ssam 	/*
120925881Ssam 	 * Restore modem information and control.
121025881Ssam 	 */
121125881Ssam 	tp0 = &vx_tty[vx*16];
121225881Ssam 	for (i = vs->vs_loport; i <= vs->vs_hiport; i++) {
121325881Ssam 		tp = tp0 + i;
121425881Ssam 		if (tp->t_state&(TS_ISOPEN|TS_WOPEN)) {
121525881Ssam 			tp->t_state &= ~TS_CARR_ON;
121625881Ssam 			vcmodem(tp->t_dev, VMOD_ON);
121725881Ssam 			if (tp->t_state&TS_CARR_ON)
121829954Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
121929954Skarels 			else if (tp->t_state & TS_ISOPEN)
122029954Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 0);
122125881Ssam 		}
122229954Skarels #ifdef notdef
122325881Ssam 		/*
122425881Ssam 		 * If carrier has changed while we were resetting,
122525881Ssam 		 * take appropriate action.
122625881Ssam 		 */
122725881Ssam 		on = vp->v_dcd & 1<<i;
122829954Skarels 		if (on && (tp->t_state&TS_CARR_ON) == 0)
122929954Skarels 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
123029954Skarels 		else if (!on && tp->t_state&TS_CARR_ON)
123129954Skarels 			(void)(*linesw[tp->t_line].l_modem)(tp, 0);
123225881Ssam #endif
123325881Ssam 	}
123425881Ssam 	vs->vs_state = VXS_RESET;
123525881Ssam 	timeout(vxrestart, (caddr_t)vx, hz);
123625881Ssam 	splx(s);
123725881Ssam }
123825881Ssam 
123925881Ssam /*
124025881Ssam  * Restore a particular aspect of the VIOC.
124125881Ssam  */
vxrestart(vx)124225881Ssam vxrestart(vx)
124325881Ssam 	int vx;
124425881Ssam {
124525881Ssam 	register struct tty *tp, *tp0;
124625881Ssam 	register struct vx_softc *vs;
124730372Skarels 	register int i, count;
124825881Ssam 	int s = spl8();
124925881Ssam 
125030372Skarels 	count = vx >> 8;
125125881Ssam 	vx &= 0xff;
125225881Ssam 	vs = &vx_softc[vx];
125325881Ssam 	vs->vs_state = VXS_READY;
125425881Ssam 	tp0 = &vx_tty[vx*16];
125525881Ssam 	for (i = vs->vs_loport; i <= vs->vs_hiport; i++) {
125625881Ssam 		tp = tp0 + i;
125730372Skarels 		if (count != 0) {
125825881Ssam 			tp->t_state &= ~(TS_BUSY|TS_TIMEOUT);
125925881Ssam 			if (tp->t_state&(TS_ISOPEN|TS_WOPEN))
126025881Ssam 				vxstart(tp);	/* restart pending output */
126125881Ssam 		} else {
126225881Ssam 			if (tp->t_state&(TS_WOPEN|TS_ISOPEN))
126337608Smarc 				vxcparam(tp, &tp->t_termios, 0);
126425881Ssam 		}
126525881Ssam 	}
126630372Skarels 	if (count == 0) {
126725881Ssam 		vs->vs_state = VXS_RESET;
126825881Ssam 		timeout(vxrestart, (caddr_t)(vx + 1*256), hz);
126925881Ssam 	} else
127040738Skarels 		printf(" vx reset done\n");
127125881Ssam 	splx(s);
127225881Ssam }
127325881Ssam 
vxreset(dev)127425881Ssam vxreset(dev)
127525881Ssam 	dev_t dev;
127625881Ssam {
127725881Ssam 
127830372Skarels 	vxstreset((int)VXUNIT(minor(dev)));	/* completes asynchronously */
127925881Ssam }
128025881Ssam 
128140738Skarels #ifdef VX_DEBUG
vxfreset(vx)128225881Ssam vxfreset(vx)
128325881Ssam 	register int vx;
128425881Ssam {
128525881Ssam 	struct vba_device *vi;
128625881Ssam 
128725881Ssam 	if ((unsigned)vx > NVX || (vi = vxinfo[vx]) == 0 || vi->ui_addr == 0)
128825881Ssam 		return (ENODEV);
128925881Ssam 	vx_softc[vx].vs_state = VXS_READY;
129025881Ssam 	vxstreset(vx);
129125881Ssam 	return (0);		/* completes asynchronously */
129225881Ssam }
129330372Skarels #endif
129425881Ssam 
vcmodem(dev,flag)129525881Ssam vcmodem(dev, flag)
129625881Ssam 	dev_t dev;
129725881Ssam {
129825881Ssam 	struct tty *tp;
129925881Ssam 	register struct vxcmd *cp;
130025881Ssam 	register struct vx_softc *vs;
130125881Ssam 	register struct vxdevice *kp;
130225881Ssam 	register port;
130325881Ssam 	int unit;
130425881Ssam 
130525881Ssam 	unit = minor(dev);
130625881Ssam 	tp = &vx_tty[unit];
130725881Ssam 	vs = (struct vx_softc *)tp->t_addr;
130830372Skarels 	if (vs->vs_state != VXS_READY)
130930372Skarels 		return;
131025881Ssam 	cp = vobtain(vs);
131140738Skarels 	kp = vs->vs_addr;
131225881Ssam 
131340738Skarels 	port = VXPORT(unit);
131425881Ssam 	/*
131525881Ssam 	 * Issue MODEM command
131625881Ssam 	 */
131725881Ssam 	cp->cmd = VXC_MDMCTL;
131830372Skarels 	if (flag == VMOD_ON) {
131940738Skarels 		if (vs->vs_softCAR & (1 << port)) {
132030372Skarels 			cp->par[0] = V_MANUAL | V_DTR_ON | V_RTS;
132140738Skarels 			kp->v_dcd |= (1 << port);
132240738Skarels 		} else
132340738Skarels 			cp->par[0] = V_AUTO | V_DTR_ON;
132430372Skarels 	} else
132530372Skarels 		cp->par[0] = V_DTR_OFF;
132625881Ssam 	cp->par[1] = port;
132730372Skarels 	(void) vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd);
132830372Skarels 	if ((kp->v_dcd | vs->vs_softCAR) & (1 << port) && flag == VMOD_ON)
132930372Skarels 		tp->t_state |= TS_CARR_ON;
133025881Ssam }
133125881Ssam 
133225881Ssam /*
133340738Skarels  * VCMINTR called when an unsolicited interrupt occurs signaling
133425881Ssam  * some change of modem control state.
133525881Ssam  */
vcmintr(vx)133625881Ssam vcmintr(vx)
133725881Ssam 	register vx;
133825881Ssam {
133925881Ssam 	register struct vxdevice *kp;
134025881Ssam 	register struct tty *tp;
134125881Ssam 	register port;
134230372Skarels 	register struct vx_softc *vs;
134325881Ssam 
134440738Skarels 	vs = &vx_softc[vx];
134540738Skarels 	kp = vs->vs_addr;
134625881Ssam 	port = kp->v_usdata[0] & 017;
134725881Ssam 	tp = &vx_tty[vx*16+port];
134825881Ssam 
134929954Skarels 	if (kp->v_ustat & DCD_ON)
135029954Skarels 		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
135129954Skarels 	else if ((kp->v_ustat & DCD_OFF) &&
135230372Skarels 	    ((vs->vs_softCAR & (1 << port))) == 0 &&
135329954Skarels 	    (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
135429954Skarels 		register struct vcmds *cp;
135529954Skarels 		register struct vxcmd *cmdp;
135625881Ssam 
135730372Skarels 		/* clear all pending transmits */
135829954Skarels 		if (tp->t_state&(TS_BUSY|TS_FLUSH) &&
135929954Skarels 		    vs->vs_vers == VXV_NEW) {
136029954Skarels 			int i, cmdfound = 0;
136125881Ssam 
136229954Skarels 			cp = &vs->vs_cmds;
136329954Skarels 			for (i = cp->v_empty; i != cp->v_fill; ) {
136429954Skarels 				cmdp = (struct vxcmd *)((long *)cp->cmdbuf[i]-1);
136529954Skarels 				if ((cmdp->cmd == VXC_XMITDTA ||
136629954Skarels 				    cmdp->cmd == VXC_XMITIMM) &&
136729954Skarels 				    ((struct vxmit *)cmdp->par)->line == port) {
136829954Skarels 					cmdfound++;
136925881Ssam 					cmdp->cmd = VXC_FDTATOX;
137025881Ssam 					cmdp->par[1] = port;
137125881Ssam 				}
137229954Skarels 				if (++i >= VC_CMDBUFL)
137329954Skarels 					i = 0;
137425881Ssam 			}
137529954Skarels 			if (cmdfound)
137629954Skarels 				tp->t_state &= ~(TS_BUSY|TS_FLUSH);
137729954Skarels 			/* cmd is already in vioc, have to flush it */
137829954Skarels 			else {
137929954Skarels 				cmdp = vobtain(vs);
138029954Skarels 				cmdp->cmd = VXC_FDTATOX;
138129954Skarels 				cmdp->par[1] = port;
138230372Skarels 				(void) vcmd(vx, (caddr_t)&cmdp->cmd);
138325881Ssam 			}
138425881Ssam 		}
138529954Skarels 	} else if ((kp->v_ustat&BRK_CHR) && (tp->t_state&TS_ISOPEN)) {
138637608Smarc 		(*linesw[tp->t_line].l_rint)(TTY_FE, tp);
138725881Ssam 		return;
138825881Ssam 	}
138925881Ssam }
139025881Ssam #endif
1391