* Copyright (c) 1988 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution is only permitted until one year after the first shipment
* of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
* binary forms are permitted provided that: (1) source distributions retain
* this entire copyright notice and comment, and (2) distributions including
* binaries display the following acknowledgement: This product includes
* software developed by the University of California, Berkeley and its
* contributors'' in the documentation or other materials provided with the
* distribution and in all advertising materials mentioning features or use
* of this software. Neither the name of the University nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)vx.c 7.11 (Berkeley) 6/28/90
#include "../tahoe/pte.h"
#include "../tahoevba/vbavar.h"
#include "../tahoevba/vbaparam.h"
#include "../tahoevba/vxreg.h"
#include "../tahoevba/scope.h"
* Interrupt type bits passed to vinthandl().
#define CMDquals 0 /* command completed interrupt */
#define RSPquals 1 /* command response interrupt */
#define UNSquals 2 /* unsolicited interrupt */
#define VXUNIT(n) ((n) >> 4)
#define VXPORT(n) ((n) & 0xf)
struct tty vx_tty
[NVX
*16];
int vxstart(), ttrstrt();
struct vxcmd
*vobtain(), *nextcmd();
* Driver information for auto-configuration stuff.
int vxprobe(), vxattach(), vxrint();
struct vba_device
*vxinfo
[NVX
];
struct vba_driver vxdriver
=
{ vxprobe
, 0, vxattach
, 0, vxstd
, "vx", vxinfo
};
struct vxdevice
*vs_addr
; /* H/W address */
u_char vs_type
; /* 0: viox-x/vioc-b, 1: vioc-bop */
u_char vs_bop
; /* bop board # for vioc-bop's */
u_char vs_loport
; /* low port nbr */
u_char vs_hiport
; /* high port nbr */
u_short vs_nbr
; /* viocx number */
u_short vs_maxcmd
; /* max number of concurrent cmds */
u_short vs_silosiz
; /* silo size */
short vs_vers
; /* vioc/pvioc version */
#define VXV_OLD 0 /* PVIOCX | VIOCX */
#define VXV_NEW 1 /* NPVIOCX | NVIOCX */
short vs_state
; /* controller state */
#define VXS_READY 0 /* ready for commands */
#define VXS_RESET 1 /* in process of reseting */
u_short vs_softCAR
; /* soft carrier */
u_int vs_ivec
; /* interrupt vector base */
caddr_t vs_mricmd
; /* most recent issued cmd */
/* The remaining fields are zeroed on reset... */
#define vs_zero vs_xmtcnt
int vs_xmtcnt
; /* xmit commands pending */
struct vxcmd
*vs_avail
;/* next available command buffer */
struct vxcmd vs_lst
[NVCXBUFS
];
struct speedtab vxspeedtab
[] = {
register int br
, cvec
; /* must be r12, r11 */
register struct vxdevice
*vp
;
register struct vx_softc
*vs
;
br
= 0; cvec
= br
; br
= cvec
;
vackint(0); vunsol(0); vcmdrsp(0);
* If on an HCX-9, the device has a 32-bit address,
* and we receive that address so we can set up a map.
* On VERSAbus devices, the address is 24-bit, and is
* already mapped (into vmem[]) by autoconf.
if (!(reg
>= vmem
&& reg
< &vmem
[ctob(VBIOSIZE
)]) && /* XXX */
!vbmemalloc(16, reg
, &dummypte
, ®
)) {
printf("vx%d: vbmemalloc failed.\n", vi
->ui_unit
);
vp
= (struct vxdevice
*)reg
;
if (badaddr((caddr_t
)vp
, 1))
vp
->v_hdwre
= V_RESET
; /* reset interrupt */
if (vp
->v_fault
!= VXF_READY
)
vs
= &vx_softc
[vi
->ui_unit
];
* Align vioc interrupt vector base to 4 vector
* boundary and fitting in 8 bits (is this necessary,
* wish we had documentation).
if ((vi
->ui_hd
->vh_lastiv
-= 3) > 0xff)
vi
->ui_hd
->vh_lastiv
= 0xff;
vs
->vs_ivec
= vi
->ui_hd
->vh_lastiv
= vi
->ui_hd
->vh_lastiv
&~ 0x3;
vs
->vs_ivec
= 0x40+vi
->ui_unit
*4;
br
= 0x18, cvec
= vs
->vs_ivec
; /* XXX */
return (sizeof (struct vxdevice
));
register struct vba_device
*vi
;
register struct vx_softc
*vs
= &vx_softc
[vi
->ui_unit
];
vs
->vs_softCAR
= vi
->ui_flags
;
vs
->vs_addr
= (struct vxdevice
*)vi
->ui_addr
;
register struct tty
*tp
; /* pointer to tty struct for port */
register struct vx_softc
*vs
;
register struct vba_device
*vi
;
int unit
, vx
, s
, error
= 0;
if (vx
>= NVX
|| (vi
= vxinfo
[vx
])== 0 || vi
->ui_alive
== 0)
if (tp
->t_state
&TS_XCLUDE
&& u
.u_uid
!= 0)
if (unit
< vs
->vs_loport
|| unit
> vs
->vs_hiport
)
tp
->t_addr
= (caddr_t
)vs
;
if ((tp
->t_state
&TS_ISOPEN
) == 0) {
tp
->t_iflag
= TTYDEF_IFLAG
;
tp
->t_oflag
= TTYDEF_OFLAG
;
tp
->t_lflag
= TTYDEF_LFLAG
;
tp
->t_cflag
= TTYDEF_CFLAG
;
tp
->t_ispeed
= tp
->t_ospeed
= TTYDEF_SPEED
;
vxparam(tp
, &tp
->t_termios
);
while (!(flag
&O_NONBLOCK
) && !(tp
->t_cflag
&CLOCAL
) &&
(tp
->t_state
&TS_CARR_ON
) == 0) {
if (error
= ttysleep(tp
, (caddr_t
)&tp
->t_rawq
, TTIPRI
| PCATCH
,
error
= (*linesw
[tp
->t_line
].l_open
)(dev
,tp
);
(*linesw
[tp
->t_line
].l_close
)(tp
);
if (tp
->t_cflag
& HUPCL
|| (tp
->t_state
& TS_ISOPEN
) == 0)
/* wait for the last response */
while (tp
->t_state
&TS_FLUSH
&& error
== 0)
error
= tsleep((caddr_t
)&tp
->t_state
, TTOPRI
| PCATCH
,
struct tty
*tp
= &vx_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_read
)(tp
, uio
, flag
));
register struct tty
*tp
= &vx_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_write
)(tp
, uio
, flag
));
* VIOCX unsolicited interrupt.
register struct tty
*tp
, *tp0
;
register struct vxdevice
*addr
;
register struct vx_softc
*vs
;
if (vi
== 0 || vi
->ui_alive
== 0)
addr
= (struct vxdevice
*)vi
->ui_addr
;
switch (addr
->v_uqual
&037) {
if (addr
->v_ustat
== VP_SILO_OFLOW
)
log(LOG_ERR
, "vx%d: input silo overflow\n", vx
);
printf("vx%d: vc proc err, ustat %x\n",
printf("vx%d: vc uqual err, uqual %x\n", vx
, addr
->v_uqual
);
if (vs
->vs_vers
== VXV_NEW
)
sp
= (struct silo
*)((caddr_t
)addr
+ *(short *)addr
->v_usdata
);
sp
= (struct silo
*)((caddr_t
)addr
+VX_SILO
+(addr
->v_usdata
[0]<<6));
nc
= *(osp
= (short *)sp
);
if (vs
->vs_vers
== VXV_NEW
&& nc
> vs
->vs_silosiz
) {
printf("vx%d: %d exceeds silo size\n", nc
);
sp
= (struct silo
*)(((short *)sp
)+1);
for (; nc
> 0; nc
--, sp
= (struct silo
*)(((short *)sp
)+1)) {
if (vs
->vs_loport
> c
|| c
> vs
->vs_hiport
)
if( (tp
->t_state
&TS_ISOPEN
) == 0) {
wakeup((caddr_t
)&tp
->t_rawq
);
c
= sp
->data
&((tp
->t_cflag
&CSIZE
)==CS8
? 0xff : 0x7f);
if ((sp
->port
&VX_RO
) == VX_RO
&& !overrun
) {
log(LOG_ERR
, "vx%d: receiver overrun\n", vi
->ui_unit
);
(*linesw
[tp
->t_line
].l_rint
)(c
, tp
);
vxioctl(dev
, cmd
, data
, flag
)
tp
= &vx_tty
[minor(dev
)];
error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, data
, flag
);
error
= ttioctl(tp
, cmd
, data
, flag
);
return (vxcparam(tp
, t
, 1));
* Set parameters from open or stty into the VX hardware
register struct vx_softc
*vs
;
register struct vxcmd
*cp
;
int speedcode
= ttspeedtab(t
->c_ospeed
, vxspeedtab
);
if (speedcode
< 0 || (t
->c_ispeed
!= t
->c_ospeed
&& t
->c_ispeed
))
vs
= (struct vx_softc
*)tp
->t_addr
;
* Construct ``load parameters'' command block
* to setup baud rates, xon-xoff chars, parity,
* and stop bits for the specified port.
cp
->par
[1] = VXPORT(minor(tp
->t_dev
));
* note: if the hardware does flow control, ^V doesn't work
if (t
->c_cc
[VSTART
] == _POSIX_VDISABLE
)
cp
->par
[2] = t
->c_cc
[VSTART
];
if (t
->c_cc
[VSTOP
] == _POSIX_VDISABLE
)
cp
->par
[3] = t
->c_cc
[VSTOP
];
cp
->par
[2] = cp
->par
[3] = 0;
switch (t
->c_cflag
& CSIZE
) { /* XXX */
cp
->par
[4] = BITS8
; /* 8 bits of data */
cp
->par
[4] = BITS7
; /* 7 bits of data */
cp
->par
[4] = BITS6
; /* 6 bits of data */
cp
->par
[4] = BITS5
; /* 5 bits of data */
if ((t
->c_cflag
& PARENB
) == 0) /* XXX */
cp
->par
[7] = VNOPARITY
; /* no parity */
else if (t
->c_cflag
&PARODD
)
cp
->par
[7] = VODDP
; /* odd parity */
cp
->par
[7] = VEVENP
; /* even parity */
cp
->par
[5] = (t
->c_cflag
&CSTOPB
) ? VSTOP2
: VSTOP1
;
if (vcmd((int)vs
->vs_nbr
, (caddr_t
)&cp
->cmd
) && wait
)
error
= tsleep((caddr_t
)cp
, TTIPRI
| PCATCH
, ttyout
, 0);
vcmodem(tp
->t_dev
, VMOD_OFF
);
* VIOCX command response interrupt.
* For transmission, restart output to any active port.
* For all other commands, just clean up.
register struct vxcmd
*cp
;
register struct vxmit
*vp
;
register struct tty
*tp
, *tp0
;
register struct vx_softc
*vs
;
cp
= (struct vxcmd
*)((long *)cp
-1);
switch (cp
->cmd
&0xff00) {
case VXC_LIDENT
: /* initialization complete */
if (vs
->vs_state
== VXS_RESET
) {
vinthandl(vx
, ((V_BSY
|RSPquals
) << 8)|V_INTR
);
default: /* VXC_MDMCTL or VXC_FDTATOX */
if (vs
->vs_state
== VXS_RESET
)
vinthandl(vx
, ((V_BSY
|RSPquals
) << 8)|V_INTR
);
vp
= (struct vxmit
*)(cp
->par
+ (cp
->cmd
& 07)*sizeof (struct vxmit
));
for (; vp
>= (struct vxmit
*)cp
->par
; vp
--) {
tp
= tp0
+ (vp
->line
& 017);
if (tp
->t_state
& TS_FLUSH
) {
tp
->t_state
&= ~TS_FLUSH
;
wakeup((caddr_t
)&tp
->t_state
);
ndflush(&tp
->t_outq
, vp
->bcount
+1);
if (vs
->vs_vers
== VXV_NEW
)
(*linesw
[tp
->t_line
].l_start
)(tp
);
tp0
= &vx_tty
[vx
*16 + vs
->vs_hiport
];
for(tp
= &vx_tty
[vx
*16 + vs
->vs_loport
]; tp
<= tp0
; tp
++)
(*linesw
[tp
->t_line
].l_start
)(tp
);
if ((cp
= nextcmd(vs
)) != NULL
) { /* command to send? */
(void) vcmd(vx
, (caddr_t
)&cp
->cmd
);
* Force out partial XMIT command after timeout
register struct vx_softc
*vs
;
register struct vxcmd
*cp
;
if ((cp
= nextcmd(vs
)) != NULL
) {
(void) vcmd((int)vs
->vs_nbr
, (caddr_t
)&cp
->cmd
);
* Start (restart) transmission on the given VX line.
register struct vx_softc
*vs
;
port
= VXPORT(minor(tp
->t_dev
));
vs
= (struct vx_softc
*)tp
->t_addr
;
if ((tp
->t_state
&(TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
)) == 0) {
if (tp
->t_outq
.c_cc
<= tp
->t_lowat
) {
if (tp
->t_state
&TS_ASLEEP
) {
tp
->t_state
&= ~TS_ASLEEP
;
wakeup((caddr_t
)&tp
->t_outq
);
selwakeup(tp
->t_wsel
, tp
->t_state
& TS_WCOLL
);
tp
->t_state
&= ~TS_WCOLL
;
if (tp
->t_outq
.c_cc
== 0) {
if (1 || !(tp
->t_oflag
&OPOST
)) /* XXX */
n
= ndqb(&tp
->t_outq
, 0);
n
= ndqb(&tp
->t_outq
, 0200);
timeout(ttrstrt
, (caddr_t
)tp
, (n
&0177)+6);
tp
->t_state
|= TS_TIMEOUT
;
vsetq(vs
, port
, (char *)tp
->t_outq
.c_cf
, n
);
if ((tp
->t_state
&TS_TTSTOP
) == 0)
* VIOCX Initialization. Makes free lists of command buffers.
* Resets all viocx's. Issues a LIDENT command to each
* viocx to establish interrupt vectors and logical port numbers.
register struct vx_softc
*vs
;
register struct vxdevice
*addr
;
register struct vxcmd
*cp
;
vs
->vs_vers
= (type
&VXT_NEW
) ? VXV_NEW
: VXV_OLD
;
if (vs
->vs_vers
== VXV_NEW
)
vs
->vs_silosiz
= addr
->v_maxsilo
;
/* set soft carrier for printer ports */
if (vs
->vs_softCAR
& (1 << j
) ||
addr
->v_portyp
[j
] == VXT_PARALLEL
) {
vs
->vs_softCAR
|= 1 << j
;
typestring
= "VIOC-X (old connector panel)";
case VXT_VIOCBOP
: /* VIOC-BOP */
printf("VIOC-BOP no. %d at %x\n", vs
->vs_bop
, addr
);
printf("vx%d: unknown type %x\n", vx
, type
);
vxinfo
[vx
]->ui_alive
= 0;
vs
->vs_nbr
= vx
; /* assign board number */
vs
->vs_maxcmd
= (vs
->vs_vers
== VXV_NEW
) ? 24 : 4;
* Initialize all cmd buffers by linking them
for (j
= 0; j
< NVCXBUFS
; j
++) {
cp
->c_fwd
= &vs
->vs_lst
[j
+1];
vs
->vs_avail
= &vs
->vs_lst
[0]; /* set idx to 1st free buf */
cp
->c_fwd
= (struct vxcmd
*)0; /* mark last buf in free list */
* Establish the interrupt vectors and define the port numbers.
cp
->par
[0] = vs
->vs_ivec
; /* ack vector */
cp
->par
[1] = cp
->par
[0]+1; /* cmd resp vector */
cp
->par
[3] = cp
->par
[0]+2; /* unsol intr vector */
cp
->par
[4] = 15; /* max ports, no longer used */
cp
->par
[5] = 0; /* set 1st port number */
(void) vcmd(vx
, (caddr_t
)&cp
->cmd
);
for (j
= 0; cp
->cmd
== VXC_LIDENT
&& j
< 4000000; j
++)
printf("vx%d: didn't respond to LIDENT\n", vx
);
/* calculate address of response buffer */
resp
= (char *)addr
+ (addr
->v_rspoff
&0x3fff);
if (resp
[0] != 0 && (resp
[0]&0177) != 3) {
vrelease(vs
, cp
); /* init failed */
vs
->vs_loport
= cp
->par
[5];
vs
->vs_hiport
= cp
->par
[7];
printf("vx%d: %s%s, ports %d-%d\n", vx
,
(vs
->vs_vers
== VXV_NEW
) ? "" : "old ", typestring
,
vs
->vs_loport
, vs
->vs_hiport
);
* Obtain a command buffer
register struct vx_softc
*vs
;
register struct vxcmd
*p
;
if (p
== (struct vxcmd
*)0) {
printf("vx%d: no buffers\n", vs
->vs_nbr
);
return ((struct vxcmd
*)p
);
* Release a command buffer
register struct vx_softc
*vs
;
register struct vxcmd
*cp
;
cp
->c_fwd
= vs
->vs_avail
;
register struct vx_softc
*vs
;
register struct vxcmd
*cp
;
vs
->vs_build
= (struct vxcmd
*)0;
* Assemble transmits into a multiple command;
* up to 8 transmits to 8 lines can be assembled together
register struct vx_softc
*vs
;
register struct vxcmd
*cp
;
register struct vxmit
*mp
;
* Grab a new command buffer or append
* to the current one being built.
if (cp
== (struct vxcmd
*)0) {
if ((cp
->cmd
& 07) == 07 || vs
->vs_vers
== VXV_NEW
) {
printf("vx%d: setq overflow\n", vs
-vx_softc
);
vxstreset((int)vs
->vs_nbr
);
* Select the next vxmit buffer and copy the
* characters into the buffer (if there's room
* and the device supports ``immediate mode'',
* or store an indirect pointer to the data.
mp
= (struct vxmit
*)(cp
->par
+ (cp
->cmd
& 07)*sizeof (struct vxmit
));
if (vs
->vs_vers
== VXV_NEW
&& n
<= sizeof (mp
->ostream
)) {
bcopy(addr
, mp
->ostream
, (unsigned)n
);
/* get system address of clist block */
addr
= (caddr_t
)vtoph((struct proc
*)0, (unsigned)addr
);
bcopy((caddr_t
)&addr
, mp
->ostream
, sizeof (addr
));
* We send the data immediately if a VIOCX,
* the command buffer is full, or if we've nothing
* currently outstanding. If we don't send it,
* set a timeout to force the data to be sent soon.
if (vs
->vs_vers
== VXV_NEW
|| (cp
->cmd
& 07) == 7 ||
(void) vcmd((int)vs
->vs_nbr
, (char *)&cp
->cmd
);
timeout(vxforce
, (caddr_t
)vs
, 3);
* Write a command out to the VIOC
register struct vcmds
*cp
;
register struct vx_softc
*vs
= &vx_softc
[vx
];
* When the vioc is resetting, don't process
* anything other than VXC_LIDENT commands.
if (vs
->vs_state
== VXS_RESET
&& cmdad
!= NULL
) {
struct vxcmd
*vcp
= (struct vxcmd
*)(cmdad
-sizeof (vcp
->c_fwd
));
if (vcp
->cmd
!= VXC_LIDENT
) {
if (cmdad
!= (caddr_t
)0) {
cp
->cmdbuf
[cp
->v_fill
] = cmdad
;
if (++cp
->v_fill
>= VC_CMDBUFL
)
if (cp
->v_fill
== cp
->v_empty
) {
printf("vx%d: cmd q overflow\n", vx
);
if (cp
->v_cmdsem
&& cp
->v_curcnt
< vs
->vs_maxcmd
) {
vinthandl(vx
, ((V_BSY
|CMDquals
) << 8)|V_INTR
);
* VIOC acknowledge interrupt. The VIOC has received the new
* command. If no errors, the new command becomes one of 16 (max)
* current commands being executed.
register struct vxdevice
*vp
;
register struct vcmds
*cp
;
if (vs
->vs_type
) /* Its a BOP */
printf("vx%d: ackint error type %x v_dcd %x\n", vx
,
vp
->v_vcid
& 07, vp
->v_dcd
& 0xff);
resp
= (char *)vs
->vs_mricmd
;
printf("%x ", resp
[i
]&0xff);
if ((vp
->v_hdwre
&017) == CMDquals
) {
if (vxintr4
& VXERR4
) { /* causes VIOC INTR ERR 4 */
((caddr_t
)cp
->cmdbuf
[cp
->v_empty
]-sizeof (cp0
->c_fwd
));
if (cp0
->cmd
== VXC_XMITDTA
|| cp0
->cmd
== VXC_XMITIMM
) {
(void) vcmd(vx
, &cp1
->cmd
);
cp
->v_curcmd
[vp
->v_vcid
& VCMDLEN
-1] = cp
->cmdbuf
[cp
->v_empty
];
if (++cp
->v_empty
>= VC_CMDBUFL
)
if (++cp
->v_itrempt
>= VC_IQLEN
)
(void) vcmd(vx
, (caddr_t
)0); /* queue next cmd, if any */
* Command Response interrupt. The Vioc has completed
* a command. The command may now be returned to
* the appropriate device driver.
register struct vxdevice
*vp
;
register struct vcmds
*cp
;
register struct vx_softc
*vs
;
if (vs
->vs_type
) { /* Its a BOP */
printf("vx%d: vcmdrsp interrupt\n", vx
);
resp
= (char *)vp
+ (vp
->v_rspoff
&0x7fff);
if (((k
= resp
[1])&V_UNBSY
) == 0) {
printf("vx%d: cmdresp debug\n", vx
);
cp
->v_curcmd
[k
] = (caddr_t
)0;
k
= *((short *)&resp
[4]); /* cmd operation code */
if ((k
&0xff00) == VXC_LIDENT
) /* want hiport number */
for (k
= 0; k
< VRESPLEN
; k
++)
vxxint(vx
, (struct vxcmd
*)cmd
);
if (vs
->vs_state
== VXS_READY
)
vinthandl(vx
, ((V_BSY
|RSPquals
) << 8)|V_INTR
);
register struct vxdevice
*vp
;
if (vs
->vs_type
) { /* Its a BOP */
printf("vx%d: vunsol from BOP\n", vx
);
if (vp
->v_uqual
&V_UNBSY
) {
vinthandl(vx
, ((V_BSY
|UNSquals
) << 8)|V_INTR
);
printf("vx%d: unsolicited interrupt error\n", vx
);
register struct vcmds
*cp
;
cp
= &vx_softc
[vx
].vs_cmds
;
empty
= (cp
->v_itrfill
== cp
->v_itrempt
);
cp
->v_itrqueu
[cp
->v_itrfill
] = item
;
if (++cp
->v_itrfill
>= VC_IQLEN
)
if (cp
->v_itrfill
== cp
->v_itrempt
) {
printf("vx%d: interrupt q overflow\n", vx
);
register struct vcmds
*cp
;
register struct vxdevice
*vp
;
register struct vx_softc
*vs
;
if (cp
->v_itrempt
== cp
->v_itrfill
)
item
= cp
->v_itrqueu
[cp
->v_itrempt
];
intr
= (short *)&vp
->v_vioc
;
switch ((item
>> 8)&03) {
case CMDquals
: { /* command */
if (cp
->v_empty
== cp
->v_fill
|| vp
->v_vcbsy
&V_BSY
)
vs
->vs_mricmd
= (caddr_t
)cp
->cmdbuf
[cp
->v_empty
];
phys
= vtoph((struct proc
*)0,
(unsigned)cp
->cmdbuf
[cp
->v_empty
]);
vp
->v_vcp
[0] = ((short *)&phys
)[0];
vp
->v_vcp
[1] = ((short *)&phys
)[1];
case RSPquals
: /* command response */
case UNSquals
: /* unsolicited interrupt */
* Start a reset on a vioc after error (hopefully)
register struct vx_softc
*vs
;
register struct vxdevice
*vp
;
register struct vxcmd
*cp
;
if (vs
->vs_state
== VXS_RESET
) { /* avoid recursion */
* Zero out the vioc structures, mark the vioc as being
* reset, reinitialize the free command list, reset the vioc
* and start a timer to check on the progress of the reset.
bzero((caddr_t
)&vs
->vs_zero
,
(unsigned)((caddr_t
)(vs
+ 1) - (caddr_t
)&vs
->vs_zero
));
* Setting VXS_RESET prevents others from issuing
* commands while allowing currently queued commands to
vs
->vs_state
= VXS_RESET
;
/* init all cmd buffers */
for (j
= 0; j
< NVCXBUFS
; j
++) {
cp
->c_fwd
= &vs
->vs_lst
[j
+1];
vs
->vs_avail
= &vs
->vs_lst
[0];
cp
->c_fwd
= (struct vxcmd
*)0;
printf("vx%d: reset...", vx
);
vp
->v_hdwre
= V_RESET
; /* generate reset interrupt */
timeout(vxinreset
, (caddr_t
)vx
, hz
*5);
/* continue processing a reset on a vioc after an error (hopefully) */
register struct vxdevice
*vp
;
vp
= vx_softc
[vx
].vs_addr
;
* See if the vioc has reset.
if (vp
->v_fault
!= VXF_READY
) {
printf(" vxreset failed\n");
* Send a LIDENT to the vioc and mess with carrier flags
* on parallel printer ports.
* Finish the reset on the vioc after an error (hopefully).
* Restore modem control, parameters and restart output.
* Since the vioc can handle no more then 24 commands at a time
* and we could generate as many as 48 commands, we must do this in
* phases, issuing no more then 16 commands at a time.
register struct vxcmd
*cp
;
register struct vx_softc
*vs
;
register struct vxdevice
*vp
;
register struct tty
*tp
, *tp0
;
vs
->vs_state
= VXS_READY
;
* Restore modem information and control.
for (i
= vs
->vs_loport
; i
<= vs
->vs_hiport
; i
++) {
if (tp
->t_state
&(TS_ISOPEN
|TS_WOPEN
)) {
tp
->t_state
&= ~TS_CARR_ON
;
vcmodem(tp
->t_dev
, VMOD_ON
);
if (tp
->t_state
&TS_CARR_ON
)
(void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
else if (tp
->t_state
& TS_ISOPEN
)
(void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 0);
* If carrier has changed while we were resetting,
* take appropriate action.
if (on
&& (tp
->t_state
&TS_CARR_ON
) == 0)
(void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
else if (!on
&& tp
->t_state
&TS_CARR_ON
)
(void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 0);
vs
->vs_state
= VXS_RESET
;
timeout(vxrestart
, (caddr_t
)vx
, hz
);
* Restore a particular aspect of the VIOC.
register struct tty
*tp
, *tp0
;
register struct vx_softc
*vs
;
vs
->vs_state
= VXS_READY
;
for (i
= vs
->vs_loport
; i
<= vs
->vs_hiport
; i
++) {
tp
->t_state
&= ~(TS_BUSY
|TS_TIMEOUT
);
if (tp
->t_state
&(TS_ISOPEN
|TS_WOPEN
))
vxstart(tp
); /* restart pending output */
if (tp
->t_state
&(TS_WOPEN
|TS_ISOPEN
))
vxcparam(tp
, &tp
->t_termios
, 0);
vs
->vs_state
= VXS_RESET
;
timeout(vxrestart
, (caddr_t
)(vx
+ 1*256), hz
);
printf(" vx reset done\n");
vxstreset((int)VXUNIT(minor(dev
))); /* completes asynchronously */
if ((unsigned)vx
> NVX
|| (vi
= vxinfo
[vx
]) == 0 || vi
->ui_addr
== 0)
vx_softc
[vx
].vs_state
= VXS_READY
;
return (0); /* completes asynchronously */
register struct vxcmd
*cp
;
register struct vx_softc
*vs
;
register struct vxdevice
*kp
;
vs
= (struct vx_softc
*)tp
->t_addr
;
if (vs
->vs_state
!= VXS_READY
)
if (vs
->vs_softCAR
& (1 << port
)) {
cp
->par
[0] = V_MANUAL
| V_DTR_ON
| V_RTS
;
kp
->v_dcd
|= (1 << port
);
cp
->par
[0] = V_AUTO
| V_DTR_ON
;
(void) vcmd((int)vs
->vs_nbr
, (caddr_t
)&cp
->cmd
);
if ((kp
->v_dcd
| vs
->vs_softCAR
) & (1 << port
) && flag
== VMOD_ON
)
tp
->t_state
|= TS_CARR_ON
;
* VCMINTR called when an unsolicited interrupt occurs signaling
* some change of modem control state.
register struct vxdevice
*kp
;
register struct vx_softc
*vs
;
port
= kp
->v_usdata
[0] & 017;
tp
= &vx_tty
[vx
*16+port
];
if (kp
->v_ustat
& DCD_ON
)
(void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
else if ((kp
->v_ustat
& DCD_OFF
) &&
((vs
->vs_softCAR
& (1 << port
))) == 0 &&
(*linesw
[tp
->t_line
].l_modem
)(tp
, 0) == 0) {
register struct vcmds
*cp
;
register struct vxcmd
*cmdp
;
/* clear all pending transmits */
if (tp
->t_state
&(TS_BUSY
|TS_FLUSH
) &&
vs
->vs_vers
== VXV_NEW
) {
for (i
= cp
->v_empty
; i
!= cp
->v_fill
; ) {
cmdp
= (struct vxcmd
*)((long *)cp
->cmdbuf
[i
]-1);
if ((cmdp
->cmd
== VXC_XMITDTA
||
cmdp
->cmd
== VXC_XMITIMM
) &&
((struct vxmit
*)cmdp
->par
)->line
== port
) {
tp
->t_state
&= ~(TS_BUSY
|TS_FLUSH
);
/* cmd is already in vioc, have to flush it */
(void) vcmd(vx
, (caddr_t
)&cmdp
->cmd
);
} else if ((kp
->v_ustat
&BRK_CHR
) && (tp
->t_state
&TS_ISOPEN
)) {
(*linesw
[tp
->t_line
].l_rint
)(TTY_FE
, tp
);