1 /* id_pas.c: Interdata programmable async line adapter simulator
2
3 Copyright (c) 2001-2012, 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-Apr-12 RMS Revised to use clock coscheduling
29 21-Mar-12 RMS Fixed TT_GET_MODE test to use TTUF_MODE_x (Michael Bloom)
30 19-Nov-08 RMS Revised for common TMXR show routines
31 18-Jun-07 RMS Added UNIT_IDLE flag
32 18-Oct-06 RMS Synced PASLA to clock
33 22-Nov-05 RMS Revised for new terminal processing routines
34 29-Jun-05 RMS Added SET PASLn DISCONNECT
35 21-Jun-05 RMS Fixed bug in SHOW CONN/STATS
36 05-Jan-04 RMS Revised for tmxr library changes
37 09-May-03 RMS Added network device flag
38
39 This module implements up to 32 individual serial interfaces, representing
40 either individual PASLA modules or combinations of the 2-line and 8-line
41 multiplexors, which are functionally very similar. These interfaces are mapped
42 to Telnet based connections as the lines of a terminal multiplexor. The
43 connection polling mechanism and the character input polling for all lines
44 are done through a single polling job.
45 */
46
47 #include "id_defs.h"
48 #include "sim_sock.h"
49 #include "sim_tmxr.h"
50 #include <ctype.h>
51
52 #define PAS_LINES 32
53
54 #define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */
55 #define UNIT_MDM (1 << UNIT_V_MDM)
56
57 #define PASL_WAIT 500
58
59 /* Status byte */
60
61 #define STA_OVR 0x80 /* overrun RO */
62 #define STA_PF 0x40 /* parity err RONI */
63 #define STA_NCL2S 0x40 /* not clr to snd XO */
64 #define STA_FR 0x20 /* framing err RO */
65 #define STA_RCR 0x10 /* rv chan rcv NI */
66 #define STA_CROF 0x02 /* carrier off RO */
67 #define STA_RING 0x01 /* ring RO */
68 #define STA_RCV (STA_OVR|STA_PF|STA_FR|STA_RCR|STA_CROF|STA_RING)
69 #define SET_EX (STA_OVR|STA_PF|STA_FR)
70 #define STA_XMT (STA_BSY)
71
72 /* Command bytes 1,0 */
73
74 #define CMD_DTR (0x20 << 8) /* DTR */
75 #define CMD_ECHO (0x10 << 8) /* echoplex */
76 #define CMD_RCT (0x08 << 8) /* RCT/DTB NI */
77 #define CMD_XMTB (0x04 << 8) /* xmt break NI */
78 #define CMD_WRT (0x02 << 8) /* write/read */
79 #define CMD_V_CLK 6 /* baud rate */
80 #define CMD_M_CLK 0x3
81 #define CMD_V_DB 4 /* data bits */
82 #define CMD_M_DB 0x3
83 #define CMD_STOP 0x80 /* stop bit */
84 #define CMD_V_PAR 1 /* parity */
85 #define CMD_M_PAR 0x3
86 #define GET_PAR(x) (((x) >> CMD_V_PAR) & CMD_M_PAR)
87 #define PAR_NONE 0
88 #define PAR_RAW 1
89 #define PAR_ODD 2
90 #define PAR_EVEN 3
91
92 #define CMD_TYP 0x01 /* command type */
93
94 extern uint32 int_req[INTSZ], int_enb[INTSZ];
95 extern int32 lfc_poll;
96
97 uint8 pas_sta[PAS_LINES]; /* status */
98 uint16 pas_cmd[PAS_LINES]; /* command */
99 uint8 pas_rbuf[PAS_LINES]; /* rcv buf */
100 uint8 pas_xbuf[PAS_LINES]; /* xmt buf */
101 uint8 pas_rarm[PAS_LINES]; /* rcvr int armed */
102 uint8 pas_xarm[PAS_LINES]; /* xmt int armed */
103 uint8 pas_rchp[PAS_LINES]; /* rcvr chr pend */
104 uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */
105
106 TMLN pas_ldsc[PAS_LINES] = { 0 }; /* line descriptors */
107 TMXR pas_desc = { 8, 0, 0, pas_ldsc }; /* mux descriptor */
108 #define PAS_ENAB pas_desc.lines
109
110 uint32 pas (uint32 dev, uint32 op, uint32 dat);
111 void pas_ini (t_bool dtpl);
112 t_stat pasi_svc (UNIT *uptr);
113 t_stat paso_svc (UNIT *uptr);
114 t_stat pas_reset (DEVICE *dptr);
115 t_stat pas_attach (UNIT *uptr, char *cptr);
116 t_stat pas_detach (UNIT *uptr);
117 int32 pas_par (int32 cmd, int32 c);
118 t_stat pas_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);
119 void pas_reset_ln (int32 i);
120
121 /* PAS data structures
122
123 pas_dev PAS device descriptor
124 pas_unit PAS unit descriptor
125 pas_reg PAS register list
126 pas_mod PAS modifiers list
127 */
128
129 DIB pas_dib = { d_PAS, -1, v_PAS, pas_tplte, &pas, &pas_ini };
130
131 UNIT pas_unit = { UDATA (&pasi_svc, UNIT_ATTABLE|UNIT_IDLE, 0), 0 };
132
133 REG pas_reg[] = {
134 { BRDATA (STA, pas_sta, 16, 8, PAS_LINES) },
135 { BRDATA (CMD, pas_cmd, 16, 16, PAS_LINES) },
136 { BRDATA (RBUF, pas_rbuf, 16, 8, PAS_LINES) },
137 { BRDATA (XBUF, pas_xbuf, 16, 8, PAS_LINES) },
138 { BRDATA (IREQ, &int_req[l_PAS], 16, 32, PAS_LINES / 16) },
139 { BRDATA (IENB, &int_enb[l_PAS], 16, 32, PAS_LINES / 16) },
140 { BRDATA (RARM, pas_rarm, 16, 1, PAS_LINES) },
141 { BRDATA (XARM, pas_xarm, 16, 1, PAS_LINES) },
142 { BRDATA (RCHP, pas_rchp, 16, 1, PAS_LINES) },
143 { HRDATA (DEVNO, pas_dib.dno, 8), REG_HRO },
144 { NULL }
145 };
146
147 MTAB pas_mod[] = {
148 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
149 &tmxr_dscln, NULL, (void *) &pas_desc },
150 { UNIT_ATT, UNIT_ATT, "summary", NULL,
151 NULL, &tmxr_show_summ, (void *) &pas_desc },
152 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
153 NULL, &tmxr_show_cstat, (void *) &pas_desc },
154 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
155 NULL, &tmxr_show_cstat, (void *) &pas_desc },
156 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
157 &set_dev, &show_dev, NULL },
158 { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES",
159 &pas_vlines, &tmxr_show_lines, (void *) &pas_desc },
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
pas(uint32 dev,uint32 op,uint32 dat)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]) /* no char? busy */
277 t = t | STA_BSY;
278 if (pas_ldsc[ln].conn == 0) /* not connected? */
279 t = t | STA_BSY | STA_EX; /* = !dsr */
280 if (t & SET_EX) /* test for ex */
281 t = t | STA_EX;
282 }
283 return t;
284
285 case IO_OC: /* command */
286 old_cmd = pas_cmd[ln]; /* old cmd */
287 if (dat & CMD_TYP) { /* type 1? */
288 pas_cmd[ln] = (pas_cmd[ln] & 0xFF) | (dat << 8);
289 if (pas_cmd[ln] & CMD_WRT) /* write? */
290 pas_xarm[ln] = int_chg (v_PASX + ln + ln, dat, pas_xarm[ln]);
291 else pas_rarm[ln] = int_chg (v_PAS + ln + ln, dat, pas_rarm[ln]);
292 }
293 else pas_cmd[ln] = (pas_cmd[ln] & ~0xFF) | dat;
294 if (pasl_unit[ln].flags & UNIT_MDM) { /* modem ctrl? */
295 if ((pas_cmd[ln] & CMD_DTR) && (pas_sta[ln] & STA_RING))
296 pas_sta[ln] = pas_sta[ln] & ~(STA_CROF | STA_RING);
297 if (old_cmd & ~pas_cmd[ln] & CMD_DTR) {
298 tmxr_linemsg (&pas_ldsc[ln], "\r\nLine hangup\r\n");
299 tmxr_reset_ln (&pas_ldsc[ln]); /* reset line */
300 pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */
301 if (pas_rarm[ln])
302 SET_INT (v_PAS + ln + ln);
303 }
304 }
305 break;
306 }
307
308 return 0;
309 }
310
311 /* Unit service - receive side
312
313 Poll all active lines for input
314 Poll for new connections
315 */
316
pasi_svc(UNIT * uptr)317 t_stat pasi_svc (UNIT *uptr)
318 {
319 int32 ln, c, out;
320
321 if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
322 return SCPE_OK;
323 sim_activate (uptr, lfc_cosched (lfc_poll)); /* continue poll */
324 ln = tmxr_poll_conn (&pas_desc); /* look for connect */
325 if (ln >= 0) { /* got one? */
326 if ((pasl_unit[ln].flags & UNIT_MDM) && /* modem control */
327 ((pas_cmd[ln] & CMD_DTR) == 0)) /* & !dtr? */
328 pas_sta[ln] = pas_sta[ln] | STA_RING | STA_CROF; /* set ring, no cd */
329 else pas_sta[ln] = pas_sta[ln] & ~STA_CROF; /* just answer */
330 if (pas_rarm[ln]) /* interrupt */
331 SET_INT (v_PAS + ln + ln);
332 pas_ldsc[ln].rcve = 1; /* rcv enabled */
333 }
334 tmxr_poll_rx (&pas_desc); /* poll for input */
335 for (ln = 0; ln < PAS_ENAB; ln++) { /* loop thru lines */
336 if (pas_ldsc[ln].conn) { /* connected? */
337 if ((c = tmxr_getc_ln (&pas_ldsc[ln]))) { /* any char? */
338 pas_sta[ln] = pas_sta[ln] & ~(STA_FR | STA_PF);
339 if (pas_rchp[ln])
340 pas_sta[ln] = pas_sta[ln] | STA_OVR;
341 if (pas_rarm[ln])
342 SET_INT (v_PAS + ln + ln);
343 if (c & SCPE_BREAK) { /* break? */
344 pas_sta[ln] = pas_sta[ln] | STA_FR; /* framing error */
345 pas_rbuf[ln] = 0; /* no character */
346 }
347 else { /* normal */
348 out = c & 0x7F; /* echo is 7b */
349 c = sim_tt_inpcvt (c, TT_GET_MODE (pasl_unit[ln].flags));
350 if (TT_GET_MODE (pasl_unit[ln].flags) != TTUF_MODE_8B)
351 c = pas_par (pas_cmd[ln], c); /* apply parity */
352 pas_rbuf[ln] = c; /* save char */
353 pas_rchp[ln] = 1; /* char pending */
354 if ((pas_cmd[ln] & CMD_ECHO) && pas_ldsc[ln].xmte) {
355 TMLN *lp = &pas_ldsc[ln]; /* get line */
356 out = sim_tt_outcvt (out, TT_GET_MODE (pasl_unit[ln].flags));
357 if (out >= 0) /* output char */
358 tmxr_putc_ln (lp, out);
359 tmxr_poll_tx (&pas_desc); /* poll xmt */
360 }
361 } /* end else normal */
362 } /* end if char */
363 } /* end if conn */
364 else if ((pas_sta[ln] & STA_CROF) == 0) { /* not conn, was conn? */
365 pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */
366 if (pas_rarm[ln]) /* intr */
367 SET_INT (v_PAS + ln + ln);
368 }
369 } /* end for */
370 return SCPE_OK;
371 }
372
373 /* Unit service - transmit side */
374
paso_svc(UNIT * uptr)375 t_stat paso_svc (UNIT *uptr)
376 {
377 int32 c;
378 uint32 ln = uptr - pasl_unit; /* line # */
379
380 if (pas_ldsc[ln].conn) { /* connected? */
381 if (pas_ldsc[ln].xmte) { /* xmt enabled? */
382 TMLN *lp = &pas_ldsc[ln]; /* get line */
383 if (TT_GET_MODE (pasl_unit[ln].flags) == TTUF_MODE_8B)
384 c = pas_par (pas_cmd[ln], pas_xbuf[ln]); /* apply parity */
385 else c = sim_tt_outcvt (pas_xbuf[ln], TT_GET_MODE (pasl_unit[ln].flags));
386 if (c >= 0) {
387 tmxr_putc_ln (lp, c); /* output char */
388 }
389 tmxr_poll_tx (&pas_desc); /* poll xmt */
390 }
391 else { /* buf full */
392 tmxr_poll_tx (&pas_desc); /* poll xmt */
393 sim_activate (uptr, pasl_unit[ln].wait); /* wait */
394 return SCPE_OK;
395 }
396 }
397 pas_sta[ln] = pas_sta[ln] & ~STA_BSY; /* not busy */
398 if (pas_xarm[ln]) /* set intr */
399 SET_INT (v_PASX + ln + ln);
400 return SCPE_OK;
401 }
402
pas_par(int32 cmd,int32 c)403 int32 pas_par (int32 cmd, int32 c)
404 {
405 int32 pf = GET_PAR (cmd);
406 static const uint8 odd_par[] = {
407 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 00 */
408 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
409 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 10 */
410 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
411 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 20 */
412 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
413 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 30 */
414 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
415 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 40 */
416 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
417 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 50 */
418 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
419 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 60 */
420 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
421 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 70 */
422 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
423 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 80 */
424 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
425 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 90 */
426 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
427 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* A0 */
428 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
429 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* B0 */
430 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
431 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* C0 */
432 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
433 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* D0 */
434 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
435 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* E0 */
436 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
437 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* F0 */
438 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80
439 };
440
441 switch (pf) { /* case on parity */
442
443 case PAR_ODD:
444 return (odd_par[c & 0x7F]) | (c & 0x7F);
445
446 case PAR_EVEN:
447 return (odd_par[c & 0x7F] ^ 0x80) | (c & 0x7F);
448
449 case PAR_NONE:
450 case PAR_RAW:
451 break;
452 }
453
454 return c & 0xFF;
455 }
456
457 /* Reset routine */
458
pas_reset(DEVICE * dptr)459 t_stat pas_reset (DEVICE *dptr)
460 {
461 int32 i;
462
463 if (dptr->flags & DEV_DIS) { /* disabled? */
464 pas_dev.flags = pas_dev.flags | DEV_DIS; /* disable lines */
465 pasl_dev.flags = pasl_dev.flags | DEV_DIS;
466 }
467 else {
468 pas_dev.flags = pas_dev.flags & ~DEV_DIS; /* enable lines */
469 pasl_dev.flags = pasl_dev.flags & ~DEV_DIS;
470 }
471 if (pas_unit.flags & UNIT_ATT) /* master att? */
472 sim_activate (&pas_unit, lfc_poll);
473 else sim_cancel (&pas_unit); /* else stop */
474 for (i = 0; i < PAS_LINES; i++)
475 pas_reset_ln (i);
476 return SCPE_OK;
477 }
478
479 /* Attach master unit */
480
pas_attach(UNIT * uptr,char * cptr)481 t_stat pas_attach (UNIT *uptr, char *cptr)
482 {
483 t_stat r;
484
485 r = tmxr_attach (&pas_desc, uptr, cptr); /* attach */
486 if (r != SCPE_OK) /* error */
487 return r;
488 sim_activate (uptr, 100); /* quick poll */
489 return SCPE_OK;
490 }
491
492 /* Detach master unit */
493
pas_detach(UNIT * uptr)494 t_stat pas_detach (UNIT *uptr)
495 {
496 int32 i;
497 t_stat r;
498
499 r = tmxr_detach (&pas_desc, uptr); /* detach */
500 for (i = 0; i < PAS_LINES; i++) /* disable rcv */
501 pas_ldsc[i].rcve = 0;
502 sim_cancel (uptr); /* stop poll */
503 return r;
504 }
505
506 /* Change number of lines */
507
pas_vlines(UNIT * uptr,int32 val,char * cptr,void * desc)508 t_stat pas_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
509 {
510 int32 newln, i, t;
511 t_stat r;
512
513 if (cptr == NULL)
514 return SCPE_ARG;
515 newln = get_uint (cptr, 10, PAS_LINES, &r);
516 if ((r != SCPE_OK) || (newln == PAS_ENAB))
517 return r;
518 if (newln == 0)
519 return SCPE_ARG;
520 if (newln < PAS_ENAB) {
521 for (i = newln, t = 0; i < PAS_ENAB; i++)
522 t = t | pas_ldsc[i].conn;
523 if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
524 return SCPE_OK;
525 for (i = newln; i < PAS_ENAB; i++) {
526 if (pas_ldsc[i].conn) {
527 tmxr_linemsg (&pas_ldsc[i], "\r\nOperator disconnected line\r\n");
528 tmxr_reset_ln (&pas_ldsc[i]); /* reset line */
529 }
530 pasl_unit[i].flags = pasl_unit[i].flags | UNIT_DIS;
531 pas_reset_ln (i);
532 }
533 }
534 else {
535 for (i = PAS_ENAB; i < newln; i++) {
536 pasl_unit[i].flags = pasl_unit[i].flags & ~UNIT_DIS;
537 pas_reset_ln (i);
538 }
539 }
540 PAS_ENAB = newln;
541 return SCPE_OK;
542 }
543
544 /* Reset an individual line */
545
pas_reset_ln(int32 i)546 void pas_reset_ln (int32 i)
547 {
548 CLR_INT (v_PAS + i + i); /* clear int */
549 CLR_ENB (v_PAS + i + i);
550 CLR_INT (v_PASX + i + i); /* disable int */
551 CLR_ENB (v_PASX + i + i);
552 pas_rarm[i] = pas_xarm[i] = 0; /* disarm int */
553 pas_rbuf[i] = pas_xbuf[i] = 0; /* clear state */
554 pas_cmd[i] = 0;
555 pas_rchp[i] = 0;
556 pas_sta[i] = 0;
557 if (pas_ldsc[i].conn == 0) /* clear carrier */
558 pas_sta[i] = pas_sta[i] | STA_CROF;
559 sim_cancel (&pasl_unit[i]);
560 return;
561 }
562
563 /* Init template */
564
pas_ini(t_bool dtpl)565 void pas_ini (t_bool dtpl)
566 {
567 int32 i, j;
568
569 for (i = j = 0; i < PAS_ENAB; i++) {
570 pas_tplte[j] = j;
571 pas_tplte[j + 1] = j + o_PASX;
572 j = j + 2;
573 }
574 pas_tplte[j] = TPL_END;
575 return;
576 }
577