blob: 97f4bf4bdb67b8d56b89a5272c0a1bd91ea0aec4 [file] [log] [blame] [raw]
/* sigma_coc.c: Sigma character-oriented communications subsystem simulator
Copyright (c) 2007-2008, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substanXIAl portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
coc 7611 communications multiplexor
*/
#include "sigma_io_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#include <ctype.h>
/* Constants */
#define MUX_LINES 64 /* max lines */
#define MUX_LINES_DFLT 8 /* default lines */
#define MUX_INIT_POLL 8000
#define MUXL_WAIT 500
#define MUX_NUMLIN mux_desc.lines /* curr # lines */
#define MUXC 0 /* channel thread */
#define MUXI 1 /* input thread */
/* Line status */
#define MUXL_XIA 0x01 /* xmt intr armed */
#define MUXL_XIR 0x02 /* xmt intr req */
#define MUXL_REP 0x04 /* rcv enable pend */
#define MUXL_RBP 0x10 /* rcv break pend */
/* Channel state */
#define MUXC_IDLE 0 /* idle */
#define MUXC_INIT 1 /* init */
#define MUXC_RCV 2 /* receive */
#define MUXC_END 3 /* end */
/* DIO address */
#define MUXDIO_V_FNC 0 /* function */
#define MUXDIO_M_FNC 0xF
#define MUXDIO_V_COC 4 /* ctlr num */
#define MUXDIO_M_COC 0xF
#define MUXDIO_GETFNC(x) (((x) >> MUXDIO_V_FNC) & MUXDIO_M_FNC)
#define MUXDIO_GETCOC(x) (((x) >> MUXDIO_V_COC) & MUXDIO_M_COC)
#define MUXDAT_V_LIN 0 /* line num */
#define MUXDAT_M_LIN (MUX_LINES - 1)
#define MUXDAT_V_CHR 8 /* output char */
#define MUXDAT_M_CHR 0xFF
#define MUXDAT_GETLIN(x) (((x) >> MUXDAT_V_LIN) & MUXDAT_M_LIN)
#define MUXDAT_GETCHR(x) (((x) >> MUXDAT_V_CHR) & MUXDAT_M_CHR)
uint8 mux_rbuf[MUX_LINES]; /* rcv buf */
uint8 mux_xbuf[MUX_LINES]; /* xmt buf */
uint8 mux_sta[MUX_LINES]; /* status */
uint32 mux_tps = RTC_HZ_50; /* polls/second */
uint32 mux_scan = 0; /* scanner */
uint32 mux_slck = 0; /* scanner locked */
uint32 muxc_cmd = MUXC_IDLE; /* channel state */
uint32 mux_rint = INTV (INTG_E2, 0);
uint32 mux_xint = INTV (INTG_E2, 1);
TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descrs */
TMXR mux_desc = { MUX_LINES_DFLT, 0, 0, mux_ldsc }; /* mux descrr */
extern uint32 chan_ctl_time;
extern uint32 CC;
extern uint32 *R;
uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst);
uint32 mux_dio (uint32 op, uint32 rn, uint32 ad);
uint32 mux_tio_status (void);
t_stat mux_chan_err (uint32 st);
t_stat muxc_svc (UNIT *uptr);
t_stat muxo_svc (UNIT *uptr);
t_stat muxi_rtc_svc (UNIT *uptr);
t_stat mux_reset (DEVICE *dptr);
t_stat mux_attach (UNIT *uptr, CONST char *cptr);
t_stat mux_detach (UNIT *uptr);
t_stat mux_vlines (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
void mux_reset_ln (int32 ln);
void mux_scan_next (t_bool clr);
t_stat muxi_put_char (uint32 c, uint32 ln);
/* MUX data structures
mux_dev MUX device descriptor
mux_unit MUX unit descriptor
mux_reg MUX register list
mux_mod MUX modifiers list
*/
dib_t mux_dib = { DVA_MUX, &mux_disp, DIO_MUX, &mux_dio };
UNIT mux_unit[] = {
{ UDATA (&muxc_svc, UNIT_ATTABLE, 0) },
{ UDATA (&muxi_rtc_svc, UNIT_DIS, 0) }
};
REG mux_reg[] = {
{ BRDATA (STA, mux_sta, 16, 8, MUX_LINES) },
{ BRDATA (RBUF, mux_rbuf, 16, 8, MUX_LINES) },
{ BRDATA (XBUF, mux_xbuf, 16, 8, MUX_LINES) },
{ DRDATA (SCAN, mux_scan, 6) },
{ FLDATA (SLCK, mux_slck, 0) },
{ DRDATA (CMD, muxc_cmd, 2) },
{ DRDATA (TPS, mux_tps, 8), REG_HRO },
{ NULL }
};
MTAB mux_mod[] = {
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &mux_desc },
{ UNIT_ATT, UNIT_ATT, "summary", NULL,
NULL, &tmxr_show_summ, (void *) &mux_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &tmxr_show_cstat, (void *) &mux_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &tmxr_show_cstat, (void *) &mux_desc },
{ MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN",
&io_set_dvc, &io_show_dvc, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA",
&io_set_dva, &io_show_dva, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",
&mux_vlines, &tmxr_show_lines, (void *) &mux_desc },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL,
NULL, &io_show_cst, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_COC, "POLL", "POLL",
&rtc_set_tps, &rtc_show_tps, (void *) &mux_tps },
{ 0 }
};
DEVICE mux_dev = {
"MUX", mux_unit, mux_reg, mux_mod,
2, 10, 31, 1, 16, 8,
&tmxr_ex, &tmxr_dep, &mux_reset,
NULL, &mux_attach, &mux_detach,
&mux_dib, DEV_NET | DEV_DISABLE
};
/* MUXL data structures
muxl_dev MUXL device descriptor
muxl_unit MUXL unit descriptor
muxl_reg MUXL register list
muxl_mod MUXL modifiers list
*/
UNIT muxl_unit[] = {
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }
};
MTAB muxl_mod[] = {
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &mux_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
&tmxr_set_log, &tmxr_show_log, &mux_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
&tmxr_set_nolog, NULL, &mux_desc },
{ 0 }
};
REG muxl_reg[] = {
{ URDATA (TIME, muxl_unit[0].wait, 10, 24, 0,
MUX_LINES, REG_NZ + PV_LEFT) },
{ NULL }
};
DEVICE muxl_dev = {
"MUXL", muxl_unit, muxl_reg, muxl_mod,
MUX_LINES, 10, 31, 1, 8, 8,
NULL, NULL, &mux_reset,
NULL, NULL, NULL,
NULL, 0
};
/* MUX: IO dispatch routine */
uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst)
{
switch (op) { /* case on op */
case OP_SIO: /* start I/O */
*dvst = mux_tio_status (); /* get status */
if ((*dvst & DVS_CST) == 0) { /* ctrl idle? */
muxc_cmd = MUXC_INIT; /* start dev thread */
sim_activate (&mux_unit[MUXC], chan_ctl_time);
}
break;
case OP_TIO: /* test status */
*dvst = mux_tio_status (); /* return status */
break;
case OP_TDV: /* test status */
*dvst = 0; /* no status */
break;
case OP_HIO: /* halt I/O */
*dvst = mux_tio_status (); /* get status */
muxc_cmd = MUXC_IDLE; /* stop dev thread */
sim_cancel (&mux_unit[MUXC]);
io_sclr_req (mux_rint, 0); /* clr rcv int */
io_sclr_req (mux_xint, 0);
break;
case OP_AIO: /* acknowledge int */
*dvst = 0; /* no status */
break;
default:
*dvst = 0;
return SCPE_IERR;
}
return 0;
}
/* MUX: DIO dispatch routine */
uint32 mux_dio (uint32 op, uint32 rn, uint32 ad)
{
int32 ln;
uint32 fnc = MUXDIO_GETFNC (ad);
uint32 coc = MUXDIO_GETCOC (ad);
if (op == OP_RD) { /* read direct */
if (coc != 0) /* nx COC? */
return 0;
R[rn] = mux_scan | 0x40; /* return line num */
mux_sta[mux_scan] &= ~MUXL_XIR; /* clear int req */
return 0;
}
ln = MUXDAT_GETLIN (R[rn]); /* get line num */
if (fnc & 0x4) { /* transmit */
if ((coc != 0) || /* nx COC or */
(ln >= MUX_NUMLIN)) { /* nx line? */
CC |= CC4;
return 0;
}
if ((fnc & 0x7) == 0x5) { /* send char? */
if (fnc & 0x8) /* space? */
mux_xbuf[ln] = 0;
else mux_xbuf[ln] = MUXDAT_GETCHR (R[rn]); /* no, get char */
sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);
mux_sta[ln] = (mux_sta[ln] | MUXL_XIA) & ~MUXL_XIR;
mux_scan_next (1); /* unlock scanner */
}
else if (fnc == 0x06) { /* stop transmit */
mux_sta[ln] &= ~MUXL_XIA|MUXL_XIR; /* disable int */
mux_scan_next (1); /* unlock scanner */
}
else if (fnc == 0x07) { /* disconnect */
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
mux_reset_ln (ln); /* reset state */
}
CC = (sim_is_active (&muxl_unit[ln])? 0: CC4) |
(mux_ldsc[ln].conn? CC3: 0);
}
else { /* receive */
if ((coc != 0) || /* nx COC or */
(ln >= MUX_NUMLIN)) /* nx line */
return 0;
if (fnc == 0x01) { /* set rcv enable */
if (mux_ldsc[ln].conn) /* connected? */
mux_ldsc[ln].rcve = 1; /* just enable */
else mux_sta[ln] |= MUXL_REP; /* enable pending */
}
else if (fnc == 0x02) { /* clr rcv enable */
mux_ldsc[ln].rcve = 0;
mux_sta[ln] &= ~MUXL_REP;
}
else if (fnc == 0x03) { /* disconnect */
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
mux_reset_ln (ln); /* reset state */
}
if (mux_sta[ln] & MUXL_RBP) /* break pending? */
CC = CC3|CC4;
else CC = mux_ldsc[ln].rcve? CC4: CC3;
}
return 0;
}
/* Unit service - channel overhead */
t_stat muxc_svc (UNIT *uptr)
{
uint32 st;
uint32 cmd;
if (muxc_cmd == MUXC_INIT) { /* init state? */
st = chan_get_cmd (mux_dib.dva, &cmd); /* get command */
if (CHS_IFERR (st)) /* channel error? */
mux_chan_err (st); /* go idle */
else muxc_cmd = MUXC_RCV; /* no, receive */
}
else if (muxc_cmd == MUXC_END) { /* end state? */
st = chan_end (mux_dib.dva); /* set channel end */
if (CHS_IFERR (st)) /* channel error? */
mux_chan_err (st); /* go idle */
else if (st == CHS_CCH) { /* command chain? */
muxc_cmd = MUXC_INIT; /* restart thread */
sim_activate (uptr, chan_ctl_time); /* schedule soon */
}
else muxc_cmd = MUXC_IDLE; /* else idle */
}
return SCPE_OK;
}
/* Unit service - polled input - called from rtc scheduler
Poll for new connections
Poll all connected lines for input
*/
t_stat muxi_rtc_svc (UNIT *uptr)
{
t_stat r;
int32 newln, ln, c;
if ((mux_unit[MUXC].flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
newln = tmxr_poll_conn (&mux_desc); /* look for connect */
if ((newln >= 0) && (mux_sta[newln] & MUXL_REP)) { /* rcv enb pending? */
mux_ldsc[newln].rcve = 1; /* enable rcv */
mux_sta[newln] &= ~MUXL_REP; /* clr pending */
}
tmxr_poll_rx (&mux_desc); /* poll for input */
for (ln = 0; ln < MUX_NUMLIN; ln++) { /* loop thru lines */
if (mux_ldsc[ln].conn) { /* connected? */
if ((c = tmxr_getc_ln (&mux_ldsc[ln]))) { /* get char */
if (c & SCPE_BREAK) /* break? */
mux_sta[ln] |= MUXL_RBP; /* set rcv brk */
else { /* normal char */
mux_sta[ln] &= ~MUXL_RBP; /* clr rcv brk */
c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags));
mux_rbuf[ln] = c; /* save char */
if ((muxc_cmd == MUXC_RCV) && /* chan active? */
(r = muxi_put_char (c, ln))) /* char to chan */
return r;
} /* end else char */
} /* end if char */
} /* end if conn */
else mux_sta[ln] &= ~MUXL_RBP; /* disconnected */
} /* end for */
return SCPE_OK;
}
/* Put character and line number in memory via channel */
t_stat muxi_put_char (uint32 c, uint32 ln)
{
uint32 st;
st = chan_WrMemB (mux_dib.dva, c); /* write char */
if (CHS_IFERR (st)) /* channel error? */
return mux_chan_err (st);
st = chan_WrMemB (mux_dib.dva, ln); /* write line */
if (CHS_IFERR (st)) /* channel error? */
return mux_chan_err (st);
if (st == CHS_ZBC) { /* bc == 0? */
muxc_cmd = MUXC_END; /* end state */
sim_activate (&mux_unit[MUXC], chan_ctl_time); /* quick schedule */
}
io_sclr_req (mux_rint, 1); /* req ext intr */
return SCPE_OK;
}
/* Channel error */
t_stat mux_chan_err (uint32 st)
{
chan_uen (mux_dib.dva); /* uend */
muxc_cmd = MUXC_IDLE; /* go idle */
if (st < CHS_ERR)
return st;
return 0;
}
/* Unit service - transmit side */
t_stat muxo_svc (UNIT *uptr)
{
int32 c;
uint32 ln = uptr - muxl_unit; /* line # */
if (mux_ldsc[ln].conn) { /* connected? */
if (mux_ldsc[ln].xmte) { /* xmt enabled? */
c = sim_tt_outcvt (mux_xbuf[ln], TT_GET_MODE (muxl_unit[ln].flags));
if (c >= 0)
tmxr_putc_ln (&mux_ldsc[ln], c); /* output char */
tmxr_poll_tx (&mux_desc); /* poll xmt */
if (mux_sta[ln] & MUXL_XIA) { /* armed? */
mux_sta[ln] |= MUXL_XIR; /* req intr */
mux_scan_next (0); /* kick scanner */
}
}
else { /* buf full */
tmxr_poll_tx (&mux_desc); /* poll xmt */
sim_activate (uptr, muxl_unit[ln].wait); /* wait */
return SCPE_OK;
}
}
return SCPE_OK;
}
/* MUX status routine */
uint32 mux_tio_status (void)
{
if (muxc_cmd == MUXC_IDLE) /* idle? */
return DVS_AUTO;
else return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC));
}
/* Kick scanner */
void mux_scan_next (t_bool clr)
{
int32 i;
if (clr) /* unlock? */
mux_slck = 0;
else if (mux_slck) /* locked? */
return;
for (i = 0; i < MUX_NUMLIN; i++) { /* scan lines */
mux_scan = mux_scan + 1; /* next line */
if (mux_scan >= (uint32) MUX_NUMLIN)
mux_scan = 0;
if (mux_sta[mux_scan] & MUXL_XIR) { /* flag set? */
mux_slck = 1; /* lock scanner */
io_sclr_req (mux_xint, 1); /* req ext int */
return;
}
}
return;
}
/* Reset routine */
t_stat mux_reset (DEVICE *dptr)
{
int32 i;
if (mux_dev.flags & DEV_DIS) /* master disabled? */
muxl_dev.flags = muxl_dev.flags | DEV_DIS; /* disable lines */
else muxl_dev.flags = muxl_dev.flags & ~DEV_DIS;
if (mux_unit[MUXC].flags & UNIT_ATT) /* master att? */
rtc_register (RTC_COC, mux_tps, &mux_unit[MUXI]); /* register timer */
else rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* else dereg */
for (i = 0; i < MUX_LINES; i++) /* reset lines */
mux_reset_ln (i);
return SCPE_OK;
}
/* Attach master unit */
t_stat mux_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;
r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) /* error */
return r;
rtc_register (RTC_COC, mux_tps, &mux_unit[MUXC]); /* register timer */
return SCPE_OK;
}
/* Detach master unit */
t_stat mux_detach (UNIT *uptr)
{
int32 i;
t_stat r;
r = tmxr_detach (&mux_desc, uptr); /* detach */
for (i = 0; i < MUX_LINES; i++) /* disable rcv */
mux_reset_ln (i);
rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* dereg */
return r;
}
/* Change number of lines */
t_stat mux_vlines (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
newln = get_uint (cptr, 10, MUX_LINES, &r);
if ((r != SCPE_OK) || (newln == MUX_NUMLIN))
return r;
if (newln == 0) return SCPE_ARG;
if (newln < MUX_NUMLIN) {
for (i = newln, t = 0; i < MUX_NUMLIN; i++) t = t | mux_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < MUX_NUMLIN; i++) {
if (mux_ldsc[i].conn) {
tmxr_linemsg (&mux_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_reset_ln (&mux_ldsc[i]); /* reset line */
}
muxl_unit[i].flags = muxl_unit[i].flags | UNIT_DIS;
mux_reset_ln (i);
}
}
else {
for (i = MUX_NUMLIN; i < newln; i++) {
muxl_unit[i].flags = muxl_unit[i].flags & ~UNIT_DIS;
mux_reset_ln (i);
}
}
MUX_NUMLIN = newln;
return SCPE_OK;
}
/* Reset an individual line */
void mux_reset_ln (int32 ln)
{
sim_cancel (&muxl_unit[ln]);
mux_sta[ln] = 0;
mux_rbuf[ln] = 0;
mux_xbuf[ln] = 0;
mux_ldsc[ln].rcve = 0;
return;
}