First Commit of my working state
[simh.git] / Interdata / id_pas.c
1 /* id_pas.c: Interdata programmable async line adapter simulator
2
3 Copyright (c) 2001-2007, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 pas Programmable asynchronous line adapter(s)
27
28 18-Jun-07 RMS Added UNIT_IDLE flag
29 18-Oct-06 RMS Synced PASLA to clock
30 22-Nov-05 RMS Revised for new terminal processing routines
31 29-Jun-05 RMS Added SET PASLn DISCONNECT
32 21-Jun-05 RMS Fixed bug in SHOW CONN/STATS
33 05-Jan-04 RMS Revised for tmxr library changes
34 09-May-03 RMS Added network device flag
35
36 This module implements up to 32 individual serial interfaces, representing
37 either individual PASLA modules or combinations of the 2-line and 8-line
38 multiplexors, which are functionally very similar. These interfaces are mapped
39 to Telnet based connections as the lines of a terminal multiplexor. The
40 connection polling mechanism and the character input polling for all lines
41 are done through a single polling job.
42 */
43
44 #include "id_defs.h"
45 #include "sim_sock.h"
46 #include "sim_tmxr.h"
47 #include <ctype.h>
48
49 #define PAS_LINES 32
50
51 #define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */
52 #define UNIT_MDM (1 << UNIT_V_MDM)
53
54 #define PASL_WAIT 500
55
56 /* Status byte */
57
58 #define STA_OVR 0x80 /* overrun RO */
59 #define STA_PF 0x40 /* parity err RONI */
60 #define STA_NCL2S 0x40 /* not clr to snd XO */
61 #define STA_FR 0x20 /* framing err RO */
62 #define STA_RCR 0x10 /* rv chan rcv NI */
63 #define STA_CROF 0x02 /* carrier off RO */
64 #define STA_RING 0x01 /* ring RO */
65 #define STA_RCV (STA_OVR|STA_PF|STA_FR|STA_RCR|STA_CROF|STA_RING)
66 #define SET_EX (STA_OVR|STA_PF|STA_FR)
67 #define STA_XMT (STA_BSY)
68
69 /* Command bytes 1,0 */
70
71 #define CMD_DTR (0x20 << 8) /* DTR */
72 #define CMD_ECHO (0x10 << 8) /* echoplex */
73 #define CMD_RCT (0x08 << 8) /* RCT/DTB NI */
74 #define CMD_XMTB (0x04 << 8) /* xmt break NI */
75 #define CMD_WRT (0x02 << 8) /* write/read */
76 #define CMD_V_CLK 6 /* baud rate */
77 #define CMD_M_CLK 0x3
78 #define CMD_V_DB 4 /* data bits */
79 #define CMD_M_DB 0x3
80 #define CMD_STOP 0x80 /* stop bit */
81 #define CMD_V_PAR 1 /* parity */
82 #define CMD_M_PAR 0x3
83 #define GET_PAR(x) (((x) >> CMD_V_PAR) & CMD_M_PAR)
84 #define PAR_NONE 0
85 #define PAR_RAW 1
86 #define PAR_ODD 2
87 #define PAR_EVEN 3
88
89 #define CMD_TYP 0x01 /* command type */
90
91 extern uint32 int_req[INTSZ], int_enb[INTSZ];
92 extern int32 lfc_poll;
93
94 uint8 pas_sta[PAS_LINES]; /* status */
95 uint16 pas_cmd[PAS_LINES]; /* command */
96 uint8 pas_rbuf[PAS_LINES]; /* rcv buf */
97 uint8 pas_xbuf[PAS_LINES]; /* xmt buf */
98 uint8 pas_rarm[PAS_LINES]; /* rcvr int armed */
99 uint8 pas_xarm[PAS_LINES]; /* xmt int armed */
100 uint8 pas_rchp[PAS_LINES]; /* rcvr chr pend */
101 uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */
102
103 TMLN pas_ldsc[PAS_LINES] = { 0 }; /* line descriptors */
104 TMXR pas_desc = { 8, 0, 0, pas_ldsc }; /* mux descriptor */
105 #define PAS_ENAB pas_desc.lines
106
107 uint32 pas (uint32 dev, uint32 op, uint32 dat);
108 void pas_ini (t_bool dtpl);
109 t_stat pasi_svc (UNIT *uptr);
110 t_stat paso_svc (UNIT *uptr);
111 t_stat pas_reset (DEVICE *dptr);
112 t_stat pas_attach (UNIT *uptr, char *cptr);
113 t_stat pas_detach (UNIT *uptr);
114 t_stat pas_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
115 t_stat pas_show (FILE *st, UNIT *uptr, int32 val, void *desc);
116 int32 pas_par (int32 cmd, int32 c);
117 t_stat pas_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);
118 void pas_reset_ln (int32 i);
119
120 /* PAS data structures
121
122 pas_dev PAS device descriptor
123 pas_unit PAS unit descriptor
124 pas_reg PAS register list
125 pas_mod PAS modifiers list
126 */
127
128 DIB pas_dib = { d_PAS, -1, v_PAS, pas_tplte, &pas, &pas_ini };
129
130 UNIT pas_unit = { UDATA (&pasi_svc, UNIT_ATTABLE|UNIT_IDLE, 0), 0 };
131
132 REG pas_nlreg = { DRDATA (NLINES, PAS_ENAB, 6), PV_LEFT };
133
134 REG pas_reg[] = {
135 { BRDATA (STA, pas_sta, 16, 8, PAS_LINES) },
136 { BRDATA (CMD, pas_cmd, 16, 16, PAS_LINES) },
137 { BRDATA (RBUF, pas_rbuf, 16, 8, PAS_LINES) },
138 { BRDATA (XBUF, pas_xbuf, 16, 8, PAS_LINES) },
139 { BRDATA (IREQ, &int_req[l_PAS], 16, 32, PAS_LINES / 16) },
140 { BRDATA (IENB, &int_enb[l_PAS], 16, 32, PAS_LINES / 16) },
141 { BRDATA (RARM, pas_rarm, 16, 1, PAS_LINES) },
142 { BRDATA (XARM, pas_xarm, 16, 1, PAS_LINES) },
143 { BRDATA (RCHP, pas_rchp, 16, 1, PAS_LINES) },
144 { HRDATA (DEVNO, pas_dib.dno, 8), REG_HRO },
145 { NULL }
146 };
147
148 MTAB pas_mod[] = {
149 { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES",
150 &pas_vlines, NULL, &pas_nlreg },
151 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
152 &tmxr_dscln, NULL, &pas_desc },
153 { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &pas_summ },
154 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
155 NULL, &pas_show, NULL },
156 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
157 NULL, &pas_show, NULL },
158 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
159 &set_dev, &show_dev, NULL },
160 { 0 }
161 };
162
163 DEVICE pas_dev = {
164 "PAS", &pas_unit, pas_reg, pas_mod,
165 1, 10, 31, 1, 16, 8,
166 &tmxr_ex, &tmxr_dep, &pas_reset,
167 NULL, &pas_attach, &pas_detach,
168 &pas_dib, DEV_NET | DEV_DISABLE
169 };
170
171 /* PASL data structures
172
173 pasl_dev PASL device descriptor
174 pasl_unit PASL unit descriptor
175 pasl_reg PASL register list
176 pasl_mod PASL modifiers list
177 */
178
179 UNIT pasl_unit[] = {
180 { UDATA (&paso_svc, 0, 0), PASL_WAIT }, /* all but 8 dis */
181 { UDATA (&paso_svc, 0, 0), PASL_WAIT },
182 { UDATA (&paso_svc, 0, 0), PASL_WAIT },
183 { UDATA (&paso_svc, 0, 0), PASL_WAIT },
184 { UDATA (&paso_svc, 0, 0), PASL_WAIT },
185 { UDATA (&paso_svc, 0, 0), PASL_WAIT },
186 { UDATA (&paso_svc, 0, 0), PASL_WAIT },
187 { UDATA (&paso_svc, 0, 0), PASL_WAIT },
188 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
189 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
190 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
191 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
192 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
193 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
194 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
195 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
196 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
197 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
198 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
199 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
200 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
201 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
202 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
203 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
204 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
205 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
206 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
207 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
208 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
209 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
210 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT },
211 { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }
212 };
213
214 MTAB pasl_mod[] = {
215 { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
216 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
217 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
218 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
219 { UNIT_MDM, 0, "no dataset", "NODATASET", NULL },
220 { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL },
221 { MTAB_XTD|MTAB_VDV, 0, NULL, "DISCONNECT",
222 &tmxr_dscln, NULL, &pas_desc },
223 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
224 &tmxr_set_log, &tmxr_show_log, &pas_desc },
225 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
226 &tmxr_set_nolog, NULL, &pas_desc },
227 { 0 }
228 };
229
230 REG pasl_reg[] = {
231 { URDATA (TIME, pasl_unit[0].wait, 16, 24, 0,
232 PAS_LINES, REG_NZ + PV_LEFT) },
233 { NULL }
234 };
235
236 DEVICE pasl_dev = {
237 "PASL", pasl_unit, pasl_reg, pasl_mod,
238 PAS_LINES, 10, 31, 1, 16, 8,
239 NULL, NULL, &pas_reset,
240 NULL, NULL, NULL,
241 NULL, 0
242 };
243
244 /* PAS: IO routine */
245
246 uint32 pas (uint32 dev, uint32 op, uint32 dat)
247 {
248 int32 ln = (dev - pas_dib.dno) >> 1;
249 int32 xmt = (dev - pas_dib.dno) & 1;
250 int32 t, old_cmd;
251
252 switch (op) { /* case IO op */
253
254 case IO_ADR: /* select */
255 return BY; /* byte only */
256
257 case IO_RD: /* read */
258 pas_rchp[ln] = 0; /* clr chr pend */
259 pas_sta[ln] = pas_sta[ln] & ~STA_OVR; /* clr overrun */
260 return pas_rbuf[ln]; /* return buf */
261
262 case IO_WD: /* write */
263 pas_xbuf[ln] = dat & 0xFF; /* store char */
264 pas_sta[ln] = pas_sta[ln] | STA_BSY; /* set busy */
265 sim_activate (&pasl_unit[ln], pasl_unit[ln].wait);
266 break;
267
268 case IO_SS: /* status */
269 if (xmt) { /* xmt side? */
270 if (pas_ldsc[ln].conn == 0) /* not conn? */
271 t = STA_NCL2S | STA_BSY; /* busy, not clr */
272 else t = pas_sta[ln] & STA_XMT; /* else just busy */
273 }
274 else {
275 t = pas_sta[ln] & STA_RCV; /* get static */
276 if (!pas_rchp[ln]) t = t | STA_BSY; /* no char? busy */
277 if (pas_ldsc[ln].conn == 0) /* not connected? */
278 t = t | STA_BSY | STA_EX; /* = !dsr */
279 if (t & SET_EX) t = t | STA_EX; /* test for ex */
280 }
281 return t;
282
283 case IO_OC: /* command */
284 old_cmd = pas_cmd[ln]; /* old cmd */
285 if (dat & CMD_TYP) { /* type 1? */
286 pas_cmd[ln] = (pas_cmd[ln] & 0xFF) | (dat << 8);
287 if (pas_cmd[ln] & CMD_WRT) /* write? */
288 pas_xarm[ln] = int_chg (v_PASX + ln + ln, dat, pas_xarm[ln]);
289 else pas_rarm[ln] = int_chg (v_PAS + ln + ln, dat, pas_rarm[ln]);
290 }
291 else pas_cmd[ln] = (pas_cmd[ln] & ~0xFF) | dat;
292 if (pasl_unit[ln].flags & UNIT_MDM) { /* modem ctrl? */
293 if ((pas_cmd[ln] & CMD_DTR) && (pas_sta[ln] & STA_RING))
294 pas_sta[ln] = pas_sta[ln] & ~(STA_CROF | STA_RING);
295 if (old_cmd & ~pas_cmd[ln] & CMD_DTR) {
296 tmxr_linemsg (&pas_ldsc[ln], "\r\nLine hangup\r\n");
297 tmxr_reset_ln (&pas_ldsc[ln]); /* reset line */
298 pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */
299 if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln);
300 }
301 }
302 break;
303 }
304
305 return 0;
306 }
307
308 /* Unit service - receive side
309
310 Poll all active lines for input
311 Poll for new connections
312 */
313
314 t_stat pasi_svc (UNIT *uptr)
315 {
316 int32 ln, c, out;
317
318 if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
319 sim_activate (uptr, lfc_poll); /* continue poll */
320 ln = tmxr_poll_conn (&pas_desc); /* look for connect */
321 if (ln >= 0) { /* got one? */
322 if ((pasl_unit[ln].flags & UNIT_MDM) && /* modem control */
323 ((pas_cmd[ln] & CMD_DTR) == 0)) /* & !dtr? */
324 pas_sta[ln] = pas_sta[ln] | STA_RING | STA_CROF; /* set ring, no cd */
325 else pas_sta[ln] = pas_sta[ln] & ~STA_CROF; /* just answer */
326 if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln); /* interrupt */
327 pas_ldsc[ln].rcve = 1; /* rcv enabled */
328 }
329 tmxr_poll_rx (&pas_desc); /* poll for input */
330 for (ln = 0; ln < PAS_ENAB; ln++) { /* loop thru lines */
331 if (pas_ldsc[ln].conn) { /* connected? */
332 if (c = tmxr_getc_ln (&pas_ldsc[ln])) { /* any char? */
333 pas_sta[ln] = pas_sta[ln] & ~(STA_FR | STA_PF);
334 if (pas_rchp[ln]) pas_sta[ln] = pas_sta[ln] | STA_OVR;
335 if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln);
336 if (c & SCPE_BREAK) { /* break? */
337 pas_sta[ln] = pas_sta[ln] | STA_FR; /* framing error */
338 pas_rbuf[ln] = 0; /* no character */
339 }
340 else { /* normal */
341 out = c & 0x7F; /* echo is 7b */
342 c = sim_tt_inpcvt (c, TT_GET_MODE (pasl_unit[ln].flags));
343 if (TT_GET_MODE (pasl_unit[ln].flags) != TT_MODE_8B)
344 c = pas_par (pas_cmd[ln], c); /* apply parity */
345 pas_rbuf[ln] = c; /* save char */
346 pas_rchp[ln] = 1; /* char pending */
347 if ((pas_cmd[ln] & CMD_ECHO) && pas_ldsc[ln].xmte) {
348 TMLN *lp = &pas_ldsc[ln]; /* get line */
349 out = sim_tt_outcvt (out, TT_GET_MODE (pasl_unit[ln].flags));
350 if (out >= 0) tmxr_putc_ln (lp, out); /* output char */
351 tmxr_poll_tx (&pas_desc); /* poll xmt */
352 }
353 } /* end else normal */
354 } /* end if char */
355 } /* end if conn */
356 else if ((pas_sta[ln] & STA_CROF) == 0) { /* not conn, was conn? */
357 pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */
358 if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln); /* intr */
359 }
360 } /* end for */
361 return SCPE_OK;
362 }
363
364 /* Unit service - transmit side */
365
366 t_stat paso_svc (UNIT *uptr)
367 {
368 int32 c;
369 uint32 ln = uptr - pasl_unit; /* line # */
370
371 if (pas_ldsc[ln].conn) { /* connected? */
372 if (pas_ldsc[ln].xmte) { /* xmt enabled? */
373 TMLN *lp = &pas_ldsc[ln]; /* get line */
374 if (TT_GET_MODE (pasl_unit[ln].flags) == TT_MODE_8B)
375 c = pas_par (pas_cmd[ln], pas_xbuf[ln]); /* apply parity */
376 else c = sim_tt_outcvt (pas_xbuf[ln], TT_GET_MODE (pasl_unit[ln].flags));
377 if (c >= 0) {
378 tmxr_putc_ln (lp, c); /* output char */
379 }
380 tmxr_poll_tx (&pas_desc); /* poll xmt */
381 }
382 else { /* buf full */
383 tmxr_poll_tx (&pas_desc); /* poll xmt */
384 sim_activate (uptr, pasl_unit[ln].wait); /* wait */
385 return SCPE_OK;
386 }
387 }
388 pas_sta[ln] = pas_sta[ln] & ~STA_BSY; /* not busy */
389 if (pas_xarm[ln]) SET_INT (v_PASX + ln + ln); /* set intr */
390 return SCPE_OK;
391 }
392
393 int32 pas_par (int32 cmd, int32 c)
394 {
395 int32 pf = GET_PAR (cmd);
396 static const uint8 odd_par[] = {
397 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 00 */
398 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
399 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 10 */
400 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
401 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 20 */
402 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
403 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 30 */
404 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
405 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 40 */
406 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
407 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 50 */
408 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
409 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 60 */
410 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
411 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 70 */
412 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
413 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 80 */
414 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
415 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 90 */
416 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
417 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* A0 */
418 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
419 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* B0 */
420 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
421 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* C0 */
422 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
423 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* D0 */
424 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
425 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* E0 */
426 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
427 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* F0 */
428 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80
429 };
430
431 switch (pf) { /* case on parity */
432
433 case PAR_ODD:
434 return (odd_par[c & 0x7F]) | (c & 0x7F);
435
436 case PAR_EVEN:
437 return (odd_par[c & 0x7F] ^ 0x80) | (c & 0x7F);
438
439 case PAR_NONE:
440 case PAR_RAW:
441 break;
442 }
443
444 return c & 0xFF;
445 }
446
447 /* Reset routine */
448
449 t_stat pas_reset (DEVICE *dptr)
450 {
451 int32 i;
452
453 if (dptr->flags & DEV_DIS) { /* disabled? */
454 pas_dev.flags = pas_dev.flags | DEV_DIS; /* disable lines */
455 pasl_dev.flags = pasl_dev.flags | DEV_DIS;
456 }
457 else {
458 pas_dev.flags = pas_dev.flags & ~DEV_DIS; /* enable lines */
459 pasl_dev.flags = pasl_dev.flags & ~DEV_DIS;
460 }
461 if (pas_unit.flags & UNIT_ATT) /* master att? */
462 sim_activate_abs (&pas_unit, lfc_poll); /* cosched with clock */
463 else sim_cancel (&pas_unit); /* else stop */
464 for (i = 0; i < PAS_LINES; i++) pas_reset_ln (i);
465 return SCPE_OK;
466 }
467
468 /* Attach master unit */
469
470 t_stat pas_attach (UNIT *uptr, char *cptr)
471 {
472 t_stat r;
473
474 r = tmxr_attach (&pas_desc, uptr, cptr); /* attach */
475 if (r != SCPE_OK) return r; /* error */
476 sim_activate_abs (uptr, 100); /* quick poll */
477 return SCPE_OK;
478 }
479
480 /* Detach master unit */
481
482 t_stat pas_detach (UNIT *uptr)
483 {
484 int32 i;
485 t_stat r;
486
487 r = tmxr_detach (&pas_desc, uptr); /* detach */
488 for (i = 0; i < PAS_LINES; i++) pas_ldsc[i].rcve = 0; /* disable rcv */
489 sim_cancel (uptr); /* stop poll */
490 return r;
491 }
492
493 /* Show summary processor */
494
495 t_stat pas_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
496 {
497 int32 i, t;
498
499 for (i = t = 0; i < PAS_LINES; i++) t = t + (pas_ldsc[i].conn != 0);
500 if (t == 1) fprintf (st, "1 connection");
501 else fprintf (st, "%d connections", t);
502 return SCPE_OK;
503 }
504
505 /* SHOW CONN/STAT processor */
506
507 t_stat pas_show (FILE *st, UNIT *uptr, int32 val, void *desc)
508 {
509 int32 i, t;
510
511 for (i = t = 0; i < PAS_LINES; i++) t = t + (pas_ldsc[i].conn != 0);
512 if (t) {
513 for (i = 0; i < PAS_LINES; i++) {
514 if (pas_ldsc[i].conn) {
515 if (val) tmxr_fconns (st, &pas_ldsc[i], i);
516 else tmxr_fstats (st, &pas_ldsc[i], i);
517 }
518 }
519 }
520 else fprintf (st, "all disconnected\n");
521 return SCPE_OK;
522 }
523
524 /* Change number of lines */
525
526 t_stat pas_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
527 {
528 int32 newln, i, t;
529 t_stat r;
530
531 if (cptr == NULL) return SCPE_ARG;
532 newln = get_uint (cptr, 10, PAS_LINES, &r);
533 if ((r != SCPE_OK) || (newln == PAS_ENAB)) return r;
534 if (newln == 0) return SCPE_ARG;
535 if (newln < PAS_ENAB) {
536 for (i = newln, t = 0; i < PAS_ENAB; i++) t = t | pas_ldsc[i].conn;
537 if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
538 return SCPE_OK;
539 for (i = newln; i < PAS_ENAB; i++) {
540 if (pas_ldsc[i].conn) {
541 tmxr_linemsg (&pas_ldsc[i], "\r\nOperator disconnected line\r\n");
542 tmxr_reset_ln (&pas_ldsc[i]); /* reset line */
543 }
544 pasl_unit[i].flags = pasl_unit[i].flags | UNIT_DIS;
545 pas_reset_ln (i);
546 }
547 }
548 else {
549 for (i = PAS_ENAB; i < newln; i++) {
550 pasl_unit[i].flags = pasl_unit[i].flags & ~UNIT_DIS;
551 pas_reset_ln (i);
552 }
553 }
554 PAS_ENAB = newln;
555 return SCPE_OK;
556 }
557
558 /* Reset an individual line */
559
560 void pas_reset_ln (int32 i)
561 {
562 CLR_INT (v_PAS + i + i); /* clear int */
563 CLR_ENB (v_PAS + i + i);
564 CLR_INT (v_PASX + i + i); /* disable int */
565 CLR_ENB (v_PASX + i + i);
566 pas_rarm[i] = pas_xarm[i] = 0; /* disarm int */
567 pas_rbuf[i] = pas_xbuf[i] = 0; /* clear state */
568 pas_cmd[i] = 0;
569 pas_rchp[i] = 0;
570 pas_sta[i] = 0;
571 if (pas_ldsc[i].conn == 0) /* clear carrier */
572 pas_sta[i] = pas_sta[i] | STA_CROF;
573 sim_cancel (&pasl_unit[i]);
574 return;
575 }
576
577 /* Init template */
578
579 void pas_ini (t_bool dtpl)
580 {
581 int32 i, j;
582
583 for (i = j = 0; i < PAS_ENAB; i++) {
584 pas_tplte[j] = j;
585 pas_tplte[j + 1] = j + o_PASX;
586 j = j + 2;
587 }
588 pas_tplte[j] = TPL_END;
589 return;
590 }