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