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, ®)) {
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