This source file includes following definitions.
- prt_init
- prt_reset
- gc
- parseID
- buffered_write
- openPrtFile
- eoj
- print_buf
- loadImageBuffer
- readStatusRegister
- loadVFCImage
- print_cmd
- prt_cmd_202
- prt_cmd_300
- prt_cmd_300a
- prt_cmd_400
- prt_iom_cmd
- prt_show_nunits
- prt_set_nunits
- prt_show_device_name
- prt_set_device_model
- prt_show_device_model
- prt_set_device_name
- prt_show_path
- prt_set_path
- burst_printer
- signal_prt_ready
- prt_set_ready
- prt_set_config
- prt_show_config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <sys/stat.h>
36
37 #include "dps8.h"
38 #include "dps8_iom.h"
39 #include "dps8_prt.h"
40 #include "dps8_sys.h"
41 #include "dps8_cable.h"
42 #include "dps8_cpu.h"
43 #include "dps8_faults.h"
44 #include "dps8_scu.h"
45 #include "dps8_utils.h"
46
47 #if defined(__MINGW64__) || defined(__MINGW32__)
48 # include "bsd_random.h"
49 # define random bsd_random
50 # define srandom bsd_srandom
51 #endif
52
53 #if defined(FREE)
54 # undef FREE
55 #endif
56 #define FREE(p) \
57 do \
58 { \
59 free ((p)); \
60 (p) = NULL; \
61 } \
62 while (0)
63
64 #include "utfile.h"
65 #include "safemove.h"
66
67 #if defined(NO_LOCALE)
68 # define xstrerror_l strerror
69 #endif
70
71 #define DBG_CTR 1
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 #define N_PRT_UNITS 1
106
107 static t_stat prt_reset (DEVICE * dptr);
108 static t_stat prt_show_nunits (FILE *st, UNIT *uptr, int val, const void *desc);
109 static t_stat prt_set_nunits (UNIT * uptr, int32 value, const char * cptr, void * desc);
110 static t_stat prt_show_device_name (FILE *st, UNIT *uptr, int val, const void *desc);
111 static t_stat prt_set_device_name (UNIT * uptr, int32 value, const char * cptr, void * desc);
112 static t_stat prt_set_config (UNUSED UNIT * uptr, UNUSED int32 value,
113 const char * cptr, UNUSED void * desc);
114 static t_stat prt_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
115 UNUSED int val, UNUSED const void * desc);
116 static t_stat prt_show_path (UNUSED FILE * st, UNIT * uptr,
117 UNUSED int val, UNUSED const void * desc);
118 static t_stat prt_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
119 const UNUSED char * cptr, UNUSED void * desc);
120 static t_stat prt_set_ready (UNIT * uptr, UNUSED int32 value,
121 UNUSED const char * cptr,
122 UNUSED void * desc);
123
124 static t_stat prt_show_device_model (FILE *st, UNIT *uptr, int val, const void *desc);
125 static t_stat prt_set_device_model (UNIT * uptr, int32 value, const char * cptr, void * desc);
126
127 #define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
128 UNIT_IDLE )
129 UNIT prt_unit[N_PRT_UNITS_MAX] =
130 {
131 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
132 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
133 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
134 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
135 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
136 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
137 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
138 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
139 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
140 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
141 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
142 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
143 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
144 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
145 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
146 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
147 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
148 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
149 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
150 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
151 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
152 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
153 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
154 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
155 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
156 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
157 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
158 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
159 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
160 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
161 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
162 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
163 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
164 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}
165 };
166
167 #define PRT_UNIT_NUM(uptr) ((uptr) - prt_unit)
168
169 static DEBTAB prt_dt[] =
170 {
171 { "NOTIFY", DBG_NOTIFY, NULL },
172 { "INFO", DBG_INFO, NULL },
173 { "ERR", DBG_ERR, NULL },
174 { "WARN", DBG_WARN, NULL },
175 { "DEBUG", DBG_DEBUG, NULL },
176 { "ALL", DBG_ALL, NULL },
177 { NULL, 0, NULL }
178 };
179
180 #define UNIT_WATCH UNIT_V_UF
181
182 static MTAB prt_mod[] =
183 {
184 #if !defined(SPEED)
185 { UNIT_WATCH, 1, "WATCH", "WATCH", 0, 0, NULL, NULL },
186 { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
187 #endif
188 {
189 MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR,
190 0,
191 "NUNITS",
192 "NUNITS",
193 prt_set_nunits,
194 prt_show_nunits,
195 "Number of PRT units in the system",
196 NULL
197 },
198 {
199 MTAB_XTD | MTAB_VDV | MTAB_NMO | \
200 MTAB_VALR | MTAB_NC,
201 0,
202 "PATH",
203 "PATH",
204 prt_set_path,
205 prt_show_path,
206 "Path to write PRT files",
207 NULL
208 },
209 {
210 MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,
211 0,
212 "NAME",
213 "NAME",
214 prt_set_device_name,
215 prt_show_device_name,
216 "Select the printer name",
217 NULL
218 },
219
220 {
221 MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,
222 0,
223 "MODEL",
224 "MODEL",
225 prt_set_device_model,
226 prt_show_device_model,
227 "Select the printer model",
228 NULL
229 },
230 {
231 MTAB_XTD | MTAB_VUN,
232 0,
233 (char *) "CONFIG",
234 (char *) "CONFIG",
235 prt_set_config,
236 prt_show_config,
237 NULL,
238 NULL,
239 },
240 {
241 MTAB_XTD | MTAB_VUN | MTAB_NMO | MTAB_VALR,
242 0,
243 "READY",
244 "READY",
245 prt_set_ready,
246 NULL,
247 NULL,
248 NULL
249 },
250 { 0, 0, NULL, NULL, 0, 0, NULL, NULL }
251 };
252
253 DEVICE prt_dev = {
254 "PRT",
255 prt_unit,
256 NULL,
257 prt_mod,
258 N_PRT_UNITS,
259 10,
260 24,
261 1,
262 8,
263 36,
264 NULL,
265 NULL,
266 prt_reset,
267 NULL,
268 NULL,
269 NULL,
270 NULL,
271 DEV_DEBUG,
272 0,
273 prt_dt,
274 NULL,
275 NULL,
276 NULL,
277 NULL,
278 NULL,
279 NULL,
280 NULL
281 };
282
283 typedef struct
284 {
285 enum prt_mode
286 {
287 prtNoMode, prtPrt, prtLdImgBuf, prtRdStatReg, prtLdVFCImg
288 } ioMode;
289 int prtUnitNum;
290 bool isBCD;
291 bool isEdited;
292 int slew;
293 char device_name [MAX_DEV_NAME_LEN];
294 int prtfile;
295 char filename [SIR_MAXPATH];
296 bool cachedFF;
297 bool split;
298 int model;
299 bool in_trailing_banner;
300 bool secondary_sentinel_seen;
301 bool delay_secondary_sentinel_check;
302 char history_buf [42];
303 size_t history_buf_len;
304 } prt_state_t;
305
306 static prt_state_t prt_state[N_PRT_UNITS_MAX];
307
308 static char prt_path[1025];
309
310 #define N_MODELS 13
311
312 static const char * model_names[N_MODELS] =
313 {
314 "202", "300", "301", "302", "303", "304",
315 "401", "402", "901", "1000", "1200", "1201",
316 "1600"
317 };
318
319 #define MODEL_1600 12
320
321 static const int model_type[N_MODELS] =
322 { 1, 2, 2, 2, 3, 3,
323 4, 4, 4, 4, 4, 4,
324 4
325 };
326
327 #if defined(NO_C_ELLIPSIS)
328 static const uint8 newlines[128] = {
329 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
330 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
331 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
332 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
333 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
334 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
335 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
336 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
337 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
338 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
339 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
340 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
341 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
342 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
343 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
344 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'
345 };
346
347 static const uint8 spaces[128] = {
348 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
349 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
350 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
351 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
352 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
353 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
354 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
355 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
356 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
357 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
358 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
359 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
360 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
361 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
362 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
363 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
364 };
365 #else
366 static const uint8 newlines[128] = { [0 ... 127] = '\n' };
367 static const uint8 spaces[128] = { [0 ... 127] = ' ' };
368 #endif
369 static const uint8 formfeed[1] = { '\f' };
370 static const uint8 crlf[4] = { '\r', '\n', '\r', '\n' };
371 static const uint8 cr[2] = { '\r', '\n' };
372
373
374
375
376
377
378
379
380 void prt_init (void)
381 {
382 (void)memset (prt_path, 0, sizeof (prt_path));
383 (void)memset (prt_state, 0, sizeof (prt_state));
384 for (int i = 0; i < N_PRT_UNITS_MAX; i ++)
385 {
386 prt_state[i].prtfile = -1;
387 prt_state[i].model = MODEL_1600;
388 }
389 }
390
391 static t_stat prt_reset (UNUSED DEVICE * dptr)
392 {
393
394
395
396
397
398
399
400 return SCPE_OK;
401 }
402
403
404
405 static word9 gc (word36 * b, uint os)
406 {
407 uint wordno = os / 4;
408 uint charno = os % 4;
409 return (word9) getbits36_9 (b[wordno], charno * 9);
410 }
411
412
413 #define LONGEST 128
414
415
416
417
418
419
420
421 static int parseID (word36 * b, uint tally, char * qno, char * name)
422 {
423 if (tally < 3)
424 return 0;
425 if (gc (b, 0) != 040)
426 return 0;
427 if (gc (b, 1) != 040)
428 return 0;
429 uint i;
430 for (i = 0; i < 5; i ++)
431 {
432 word9 ch = gc (b, 2 + i);
433 if (ch < '0' || ch > '9')
434 return 0;
435 qno[i] = (char) ch;
436 }
437 qno[5] = 0;
438 if (gc (b, 7) != 037)
439 return 0;
440
441
442 for (i = 0; i < LONGEST; i ++)
443 {
444 word9 ch = gc (b, 9 + i);
445 if (ch == 037)
446 break;
447 if (! isprint (ch))
448 return 0;
449 name[i] = (char) ch;
450 }
451 name[i] = 0;
452 return -1;
453 }
454
455
456 static word36 eoj_history [N_PRT_UNITS_MAX] [2];
457 static int eoj_history_len [N_PRT_UNITS_MAX] = {0};
458
459
460 static ssize_t
461 buffered_write (int prt_unit_num, const void * data, size_t len)
462 {
463 prt_state_t * st = & prt_state [prt_unit_num];
464
465 size_t total_len = st -> history_buf_len + len;
466 char * temp_buf = malloc (total_len);
467 if (! temp_buf)
468 {
469 return -1;
470 }
471
472 (void)memcpy (temp_buf, st -> history_buf, st -> history_buf_len);
473 (void)memcpy (temp_buf + st -> history_buf_len, data, len);
474
475 if (st -> delay_secondary_sentinel_check)
476 {
477 if (NULL != memchr (data, '\n', len))
478 st -> delay_secondary_sentinel_check = false;
479 }
480
481 if (st -> in_trailing_banner && ! st -> secondary_sentinel_seen && ! st -> delay_secondary_sentinel_check)
482 {
483 for (int i = 0; i <= (int)total_len - 23; i++)
484 {
485 if (temp_buf [i + 0] == '\r' &&
486 isdigit (temp_buf [i + 13]) &&
487 isdigit (temp_buf [i + 14]) &&
488 isdigit (temp_buf [i + 15]) &&
489 isdigit (temp_buf [i + 16]) &&
490 isdigit (temp_buf [i + 17]) &&
491 temp_buf [i + 18] == ' ' &&
492 temp_buf [i + 19] == ' ' &&
493 temp_buf [i + 20] == ' ' &&
494 temp_buf [i + 21] == ' ' &&
495 temp_buf [i + 22] == ' ')
496 {
497 st -> secondary_sentinel_seen = true;
498 break;
499 }
500 }
501 }
502 else if (! st -> in_trailing_banner)
503 {
504 for (int i = 0; i <= (int)total_len - 21; i++)
505 {
506 if (temp_buf [i + 0] == '\r' &&
507 temp_buf [i + 1] == '\r' &&
508 temp_buf [i + 2] == '\f' &&
509 isdigit (temp_buf [i + 16]) &&
510 isdigit (temp_buf [i + 17]) &&
511 isdigit (temp_buf [i + 18]) &&
512 isdigit (temp_buf [i + 19]) &&
513 isdigit (temp_buf [i + 20]))
514 {
515 st -> in_trailing_banner = true;
516 st -> delay_secondary_sentinel_check = true;
517 break;
518 }
519 }
520 }
521
522 if (total_len >= sizeof (st -> history_buf))
523 {
524 (void)memcpy (st -> history_buf, temp_buf + total_len - sizeof (st -> history_buf), sizeof (st -> history_buf));
525 st -> history_buf_len = sizeof (st -> history_buf);
526 }
527 else
528 {
529 (void)memcpy (st -> history_buf, temp_buf, total_len);
530 st -> history_buf_len = total_len;
531 }
532
533 FREE (temp_buf);
534
535 ssize_t n_write = write (st -> prtfile, data, len);
536
537
538
539
540
541
542 return n_write;
543 }
544
545
546
547
548
549
550 static int openPrtFile (int prt_unit_num, word36 * buffer, uint tally)
551 {
552 if (prt_state [prt_unit_num] . prtfile != -1)
553 return 0;
554
555
556 eoj_history_len [prt_unit_num] = 0;
557 prt_state [prt_unit_num] . in_trailing_banner = false;
558 prt_state [prt_unit_num] . secondary_sentinel_seen = false;
559 prt_state [prt_unit_num] . delay_secondary_sentinel_check = false;
560 prt_state [prt_unit_num] . history_buf_len = 0;
561
562
563 if (tally == 1 && buffer [0] == 0014013000000llu)
564 {
565 prt_state [prt_unit_num] . cachedFF = true;
566 return -3;
567 }
568
569 char qno [6], name [LONGEST + 1];
570 int rc = parseID (buffer, tally, qno, name);
571 char template [1024 + 129 + LONGEST];
572 char unit_designator = 'a' + (char) prt_unit_num;
573 char split_prefix [6];
574 split_prefix [0] = 0;
575
576 if (prt_state [prt_unit_num] . split) {
577 (void)sprintf (split_prefix, "prt%c/", unit_designator);
578 }
579
580 if (rc == 0)
581 (void)sprintf (template, "%s%sprt%c.spool.XXXXXX.prt.OPEN", prt_path, split_prefix, unit_designator);
582 else
583 (void)sprintf (template, "%s%sprt%c.spool.%s.%s.XXXXXX.prt.OPEN", prt_path, split_prefix, unit_designator, qno, name);
584
585 if (prt_path [0] || split_prefix [0])
586 {
587 char dir_to_create [sizeof (template)];
588 (void)snprintf (dir_to_create, sizeof (dir_to_create), "%s%s", prt_path, split_prefix);
589 size_t l = strlen (dir_to_create);
590 #if defined(__MINGW64__) || defined(__MINGW32__)
591 if (l > 1 && (dir_to_create [l - 1] == '/' || dir_to_create [l - 1] == '\\'))
592 #else
593 if (l > 1 && dir_to_create [l - 1] == '/')
594 #endif
595 dir_to_create [l - 1] = 0;
596
597 if (dir_to_create [0])
598 {
599 struct stat st;
600 if (stat (dir_to_create, & st) == -1)
601 {
602 (void)sir_notice ("Printer output directory '%s' not found; creating it.", dir_to_create);
603 if (0 != x_mkdir_p (dir_to_create))
604 {
605 sir_error ("Unable to create directory '%s': %s (Error %d)", dir_to_create, xstrerror_l (errno), errno);
606 return -1;
607 }
608 }
609 }
610 }
611
612 prt_state [prt_unit_num] . prtfile = utfile_mkstemps (template, 9);
613 strcpy (prt_state [prt_unit_num] . filename, template);
614
615 if (prt_state[prt_unit_num].prtfile == -1)
616 {
617 sir_error ("Unable to open printer file '%s': %s (Error %d)", template, xstrerror_l (errno), errno);
618 return -1;
619 }
620 if (prt_state[prt_unit_num].cachedFF)
621 {
622 ssize_t n_write = buffered_write (prt_unit_num, formfeed, 1);
623 if (n_write != 1)
624 {
625 return -2;
626 }
627 prt_state[prt_unit_num].cachedFF = false;
628 }
629 return 0;
630 }
631
632
633
634 #define MAX_WINDOW_WORDS (4096 + 2)
635 static int eoj (int prt_unit_num, word36 * buffer, uint tally)
636 {
637 if (! prt_state [prt_unit_num] . in_trailing_banner)
638 return 0;
639
640 if (tally + 2 > MAX_WINDOW_WORDS)
641 {
642 sir_warn ("tally %u too large at %s[%s:%d]", tally, __func__, __FILE__, __LINE__);
643 return 0;
644 }
645
646 word36 window [MAX_WINDOW_WORDS];
647 uint window_tally = (uint)eoj_history_len [prt_unit_num];
648
649 if (window_tally > 0)
650 (void)memcpy (window, eoj_history [prt_unit_num], window_tally * sizeof (word36));
651
652 (void)memcpy (window + window_tally, buffer, tally * sizeof (word36));
653 window_tally += tally;
654
655 int found = 0;
656 if (window_tally >= 3)
657 {
658 uint num_chars = window_tally * 4;
659 unsigned char chars [MAX_WINDOW_WORDS * 4];
660
661 for (uint i = 0; i < window_tally; i++)
662 {
663 chars [i * 4 + 0] = (unsigned char)getbits36_9 (window [i], 0);
664 chars [i * 4 + 1] = (unsigned char)getbits36_9 (window [i], 9);
665 chars [i * 4 + 2] = (unsigned char)getbits36_9 (window [i], 18);
666 chars [i * 4 + 3] = (unsigned char)getbits36_9 (window [i], 27);
667 }
668
669 for (uint i = 0; i <= num_chars - 9; i++)
670 {
671 if ( chars [i + 0] == 037 &&
672 chars [i + 1] == 014 &&
673 (chars [i + 2] >= '0' && chars [i + 2] <= '9') &&
674 (chars [i + 3] >= '0' && chars [i + 3] <= '9') &&
675 (chars [i + 4] >= '0' && chars [i + 4] <= '9') &&
676 (chars [i + 5] >= '0' && chars [i + 5] <= '9') &&
677 (chars [i + 6] >= '0' && chars [i + 6] <= '9') &&
678 chars [i + 7] == 037 &&
679 chars [i + 8] == 005)
680 {
681 if (prt_state [prt_unit_num] . secondary_sentinel_seen)
682 {
683 found = -1;
684 break;
685 }
686 }
687 }
688 }
689
690 if (found)
691 {
692
693 eoj_history_len [prt_unit_num] = 0;
694 prt_state [prt_unit_num] . in_trailing_banner = false;
695 prt_state [prt_unit_num] . secondary_sentinel_seen = false;
696 prt_state [prt_unit_num] . delay_secondary_sentinel_check = false;
697 prt_state [prt_unit_num] . history_buf_len = 0;
698 }
699 else
700 {
701
702 if (window_tally >= 2)
703 {
704 eoj_history_len [prt_unit_num] = 2;
705 (void)memcpy (eoj_history [prt_unit_num], window + window_tally - 2, 2 * sizeof (word36));
706 }
707 else if (window_tally == 1)
708 {
709 eoj_history_len [prt_unit_num] = 1;
710 eoj_history [prt_unit_num] [0] = window [0];
711 }
712 else
713 {
714 eoj_history_len [prt_unit_num] = 0;
715 }
716 }
717
718 return found;
719 }
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830 static int print_buf (int prt_unit_num, bool isBCD, bool is_edited, int slew, word36 * buffer, uint tally)
831 {
832
833
834
835
836
837
838
839
840
841
842
843
844 static char * bcd_lc =
845 "01234567"
846 "89{#?;>?"
847 " abcdefg"
848 "hi|.}(<\\"
849 "^jklmnop"
850 "qr_$*);'"
851 "+/stuvwx"
852 "yz~,!=\"!";
853
854
855
856
857
858
859
860
861
862
863
864
865 static char * bcd_uc =
866 "01234567"
867 "89[#@;>?"
868 " ABCDEFG"
869 "HI&.](<\\"
870 "^JKLMNOP"
871 "QR-$*);'"
872 "+/STUVWX"
873 "YZ_,%=\"!";
874
875
876 static char * bcd =
877 "01234567"
878 "89[#@;> "
879 " ABCDEFG"
880 "HI&.](<\\"
881 "^JKLMNOP"
882 "QR-$*);'"
883 "+/STUVWX"
884 "YZ_,%=\"!";
885
886 if (prt_state[prt_unit_num].prtfile == -1)
887 {
888 int rc = openPrtFile (prt_unit_num, buffer, tally);
889 if (rc < 0)
890 {
891 return rc == -3 ? 0 : rc;
892 }
893 }
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924 if (slew == -1)
925 {
926 ssize_t n_write = buffered_write (prt_unit_num, formfeed, 1);
927 if (n_write != 1)
928 {
929 return -2;
930 }
931 }
932 else if (slew)
933 {
934 for (int i = 0; i < slew; i ++)
935 {
936 ssize_t n_write = buffered_write (prt_unit_num, crlf, 2);
937 if (n_write != 2)
938 {
939 return -2;
940 }
941 }
942 }
943
944
945
946
947
948
949 if (tally)
950 {
951 if (isBCD)
952 {
953 uint nchars = tally * 6;
954 #define get_BCD_char(i) ((uint8_t) ((buffer[i / 6] >> ((5 - i % 6) * 6)) & 077))
955
956 if (! is_edited)
957 {
958 uint8 bytes[nchars];
959 for (uint i = 0; i < nchars; i ++)
960 {
961 bytes[i] = (uint8_t) bcd_uc [get_BCD_char (i)];
962 }
963 ssize_t n_write = buffered_write (prt_unit_num, bytes, nchars);
964 if (n_write != (ssize_t)nchars)
965 {
966 return -2;
967 }
968 }
969 else
970 {
971
972
973
974
975
976 int BCD_cset = 0;
977 char * table[3] = { bcd, bcd_lc, bcd_uc };
978
979 for (uint i = 0; i < nchars; i ++)
980 {
981 uint8_t ch = get_BCD_char (i);
982
983
984
985
986
987
988
989
990 if (ch == 077)
991 {
992 i ++;
993 uint8_t n = get_BCD_char (i);
994
995 if (n == 077)
996 {
997
998 switch (BCD_cset)
999 {
1000 case 0: BCD_cset = 1; break;
1001 case 1: BCD_cset = 2; break;
1002 case 2: BCD_cset = 1; break;
1003 }
1004 }
1005 else if (n >= 041 && n <= 057)
1006 {
1007 int nchars = (n - 040) * 8;
1008 ssize_t n_write = buffered_write (prt_unit_num, spaces, (size_t)nchars);
1009 if (n_write != nchars)
1010 {
1011 return -2;
1012 }
1013 }
1014 else if (n >= 020 && n <= 022)
1015 {
1016
1017 ssize_t n_write = buffered_write (prt_unit_num, formfeed, 1);
1018 if (n_write != 1)
1019 {
1020 return -2;
1021 }
1022 }
1023 else if (n == 0)
1024 {
1025 ssize_t n_write = buffered_write (prt_unit_num, cr, 1);
1026 if (n_write != 1)
1027 {
1028 return -2;
1029 }
1030 }
1031 else if (n <= 017)
1032 {
1033 ssize_t n_write = buffered_write (prt_unit_num, newlines, n);
1034 if (n_write != n)
1035 {
1036 return -2;
1037 }
1038 }
1039 #if defined(TESTING)
1040 else
1041 {
1042 sim_warn ("Printer BCD edited ESC %u. %o ignored\r\n", n, n);
1043 }
1044 #endif
1045 }
1046 else
1047 {
1048 ssize_t n_write = buffered_write (prt_unit_num, table[BCD_cset] + ch, 1);
1049 if (n_write != 1)
1050 {
1051 return -2;
1052 }
1053 }
1054 }
1055 }
1056 }
1057 else
1058 {
1059 uint nchars = tally * 4;
1060 #define get_ASCII_char(i) ((uint8_t) ((buffer[i / 4] >> ((3 - i % 4) * 9)) & 0377))
1061
1062 if (! is_edited)
1063 {
1064 uint8 bytes[nchars];
1065 uint nbytes = 0;
1066 for (uint i = 0; i < nchars; i ++)
1067 {
1068 uint8_t ch = get_ASCII_char (i);
1069 if (isprint (ch))
1070 bytes[nbytes ++] = ch;
1071 }
1072 ssize_t n_write = buffered_write (prt_unit_num, bytes, nbytes);
1073 if (n_write != (ssize_t)nbytes)
1074 {
1075 return -2;
1076 }
1077 }
1078 else
1079 {
1080 uint col = 0;
1081 for (uint i = 0; i < tally * 4; i ++)
1082 {
1083 uint8_t ch = get_ASCII_char (i);
1084 if (ch == 037)
1085 {
1086 i ++;
1087 uint8_t n = get_ASCII_char (i);
1088 ssize_t n_write = buffered_write (prt_unit_num, spaces, n);
1089 if (n_write != n)
1090 {
1091 return -2;
1092 }
1093 col += n;
1094 }
1095 else if (ch == 013)
1096 {
1097 i ++;
1098 uint8_t n = get_ASCII_char (i);
1099 if (n)
1100 {
1101 ssize_t n_write = buffered_write (prt_unit_num, newlines, n);
1102 if (n_write != n)
1103 {
1104 return -2;
1105 }
1106 }
1107 else
1108 {
1109 ssize_t n_write = buffered_write (prt_unit_num, cr, 1);
1110 if (n_write != 1)
1111 {
1112 return -2;
1113 }
1114 }
1115 col = 0;
1116 }
1117 else if (ch == 014)
1118 {
1119 ssize_t n_write = buffered_write (prt_unit_num, formfeed, 1);
1120 if (n_write != 1)
1121 {
1122 return -2;
1123 }
1124 col = 0;
1125 }
1126 else if (ch == 011)
1127 {
1128 i ++;
1129 uint8_t n = get_ASCII_char (i);
1130 if (col < n)
1131 {
1132 ssize_t n_write = buffered_write (prt_unit_num, spaces, n - col);
1133 if (n_write != n - col)
1134 {
1135 return -2;
1136 }
1137 col += n;
1138 }
1139 }
1140 else if (isprint (ch))
1141 {
1142 ssize_t n_write = buffered_write (prt_unit_num, & ch, 1);
1143 if (n_write != 1)
1144 {
1145 return -2;
1146 }
1147 col ++;
1148 }
1149 }
1150 }
1151 }
1152 }
1153
1154
1155 ssize_t n_write = buffered_write (prt_unit_num, cr, 1);
1156 if (n_write != 1)
1157 {
1158 return -2;
1159 }
1160
1161 if ((! isBCD) && eoj (prt_unit_num, buffer, tally))
1162 {
1163 close (prt_state [prt_unit_num] . prtfile);
1164 prt_state [prt_unit_num] . prtfile = -1;
1165
1166 int rename_attempts = 0;
1167 const int MAX_RENAME_ATTEMPTS = 10000;
1168 bool rename_successful = false;
1169
1170 char old_open_filename [SIR_MAXPATH];
1171 char new_target_filename [SIR_MAXPATH];
1172
1173 strcpy (old_open_filename, prt_state [prt_unit_num] . filename);
1174
1175 char * open_ext_pos = strstr (old_open_filename, ".OPEN");
1176 if (open_ext_pos)
1177 {
1178 strncpy (new_target_filename, old_open_filename, open_ext_pos - old_open_filename);
1179 new_target_filename [open_ext_pos - old_open_filename] = '\0';
1180 }
1181 else
1182 strcpy (new_target_filename, old_open_filename);
1183
1184 while (rename_attempts < MAX_RENAME_ATTEMPTS)
1185 {
1186 if (safe_rename (old_open_filename, new_target_filename) == 0)
1187 {
1188 rename_successful = true;
1189 break;
1190 }
1191
1192 char new_random_part [7];
1193 const char charset [] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1194 const int charset_size = sizeof (charset) - 1;
1195
1196 for (int i = 0; i < 6; ++i)
1197 {
1198 new_random_part [i] = charset [random () % charset_size];
1199 }
1200
1201 new_random_part [6] = '\0';
1202
1203 char * prt_ext_pos = strstr (new_target_filename, ".prt");
1204 if (prt_ext_pos)
1205 {
1206 char * random_start_pos = prt_ext_pos - 6;
1207 if (random_start_pos >= new_target_filename)
1208 (void)memmove (random_start_pos, new_random_part, 6);
1209 }
1210
1211 rename_attempts++;
1212 }
1213
1214 if (!rename_successful)
1215 {
1216 sir_error ("Failed to rename '%s': %s (Error %d)", old_open_filename, xstrerror_l (errno), errno);
1217 }
1218 }
1219
1220 return 0;
1221 }
1222
1223 static int loadImageBuffer (uint iom_unit_idx, uint chan)
1224 {
1225 iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1226
1227 p->stati = 04000;
1228 return 0;
1229 }
1230
1231 static int readStatusRegister (uint iom_unit_idx, uint chan)
1232 {
1233 iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1234
1235 uint tally = p -> DDCW_TALLY;
1236
1237 if (tally != 4)
1238 {
1239 sim_warn ("%s: expected tally of 4, is %d\r\n", __func__, tally);
1240 }
1241 if (tally == 0)
1242 {
1243 tally = 4096;
1244 }
1245
1246
1247
1248 word36 buffer[tally];
1249 (void)memset (buffer, 0, sizeof (buffer));
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271 uint wordsProcessed = tally;
1272 iom_indirect_data_service (iom_unit_idx, chan, buffer,
1273 & wordsProcessed, true);
1274 p->charPos = 0;
1275 p->stati = 04000;
1276 return 0;
1277 }
1278
1279 static int loadVFCImage (uint iom_unit_idx, uint chan)
1280 {
1281 iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1282
1283 p->stati = 04000;
1284 return 0;
1285 }
1286
1287 static iom_cmd_rc_t print_cmd (uint iom_unit_idx, uint chan, int prt_unit_num, bool isBCD, bool is_edited, int slew)
1288 {
1289 #if defined(TESTING)
1290 cpu_state_t * cpup = _cpup;
1291 #endif
1292 iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1293 p->isRead = false;
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329 uint tally = p -> DDCW_TALLY;
1330 sim_debug (DBG_DEBUG, & prt_dev,
1331 "%s: Tally %d (%o)\r\n", __func__, tally, tally);
1332
1333 if (tally == 0)
1334 tally = 4096;
1335
1336
1337 word36 buffer[tally];
1338 uint wordsProcessed = 0;
1339 iom_indirect_data_service (iom_unit_idx, chan, buffer,
1340 & wordsProcessed, false);
1341 p -> initiate = false;
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362 int rc = print_buf (prt_unit_num, isBCD, is_edited, slew, buffer, tally);
1363 if (rc == -1)
1364 {
1365 p->stati = 04201;
1366 return IOM_CMD_ERROR;
1367 }
1368 if (rc == -2)
1369 {
1370 p->stati = 04210;
1371 return IOM_CMD_ERROR;
1372 }
1373
1374
1375
1376 p -> tallyResidue = 0;
1377 p -> stati = 04000;
1378
1379 return IOM_CMD_RESIDUE;
1380 }
1381
1382 iom_cmd_rc_t prt_cmd_202 (uint iomUnitIdx, uint chan) {
1383 #if defined(TESTING)
1384 cpu_state_t * cpup = _cpup;
1385 #endif
1386 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1387 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1388 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1389 UNIT * unitp = & prt_unit[devUnitIdx];
1390 int prt_unit_num = (int) PRT_UNIT_NUM (unitp);
1391 prt_state_t * statep = & prt_state[devUnitIdx];
1392
1393
1394 if (IS_IDCW (p)) {
1395
1396 statep->ioMode = prtNoMode;
1397
1398 switch (p->IDCW_DEV_CMD) {
1399 case 000:
1400 sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\r\n", __func__);
1401 p->stati = 04000;
1402 break;
1403
1404 case 010:
1405 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew One Line\r\n", __func__);
1406 statep->ioMode = prtPrt;
1407 statep->prtUnitNum = prt_unit_num;
1408 statep->isBCD = true;
1409 statep->isEdited = false;
1410 statep->slew = 1;
1411 p->stati = 04000;
1412 break;
1413
1414 case 030:
1415 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Zero Lines\r\n", __func__);
1416 statep->ioMode = prtPrt;
1417 statep->prtUnitNum = prt_unit_num;
1418 statep->isBCD = true;
1419 statep->isEdited = true;
1420 statep->slew = 0;
1421 p->stati = 04000;
1422 break;
1423
1424 case 040:
1425 sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\r\n", __func__);
1426 p->stati = 04000;
1427 p->isRead = false;
1428 break;
1429
1430 default:
1431 p->stati = 04501;
1432 p->chanStatus = chanStatIncorrectDCW;
1433 if (p->IDCW_DEV_CMD != 051)
1434 sim_warn ("%s: PRT unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1435 return IOM_CMD_ERROR;
1436 }
1437
1438 sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\r\n", __func__, p->stati);
1439 return IOM_CMD_PROCEED;
1440 }
1441
1442
1443 switch (statep->ioMode) {
1444 case prtNoMode:
1445
1446
1447
1448 break;
1449
1450 case prtPrt: {
1451 iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1452 statep->isEdited, statep->slew);
1453 if (rc)
1454 return rc;
1455 }
1456 break;
1457
1458 default:
1459 sim_warn ("%s: Unrecognized ioMode %d\r\n", __func__, statep->ioMode);
1460 return IOM_CMD_ERROR;
1461 }
1462
1463 return IOM_CMD_PROCEED;
1464 }
1465
1466 iom_cmd_rc_t prt_cmd_300 (uint iomUnitIdx, uint chan) {
1467 #if defined(TESTING)
1468 cpu_state_t * cpup = _cpup;
1469 #endif
1470 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1471 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1472 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1473 UNIT * unitp = & prt_unit[devUnitIdx];
1474 int prt_unit_num = (int) PRT_UNIT_NUM (unitp);
1475 prt_state_t * statep = & prt_state[devUnitIdx];
1476
1477
1478 if (IS_IDCW (p)) {
1479
1480 statep->ioMode = prtNoMode;
1481
1482 switch (p->IDCW_DEV_CMD) {
1483 case 000:
1484 sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\r\n", __func__);
1485 p->stati = 04000;
1486 break;
1487
1488 case 011:
1489 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\r\n", __func__);
1490 statep->ioMode = prtPrt;
1491 statep->prtUnitNum = prt_unit_num;
1492 statep->isBCD = false;
1493 statep->isEdited = false;
1494 statep->slew = 1;
1495 p->stati = 04000;
1496 break;
1497
1498 case 014:
1499 sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\r\n", __func__);
1500 statep->ioMode = prtLdImgBuf;
1501 p->stati = 04000;
1502 break;
1503
1504 case 030:
1505 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\r\n", __func__);
1506 statep->ioMode = prtPrt;
1507 statep->prtUnitNum = prt_unit_num;
1508 statep->isBCD = false;
1509 statep->isEdited = true;
1510 statep->slew = 0;
1511 p->stati = 04000;
1512 break;
1513
1514 case 040:
1515 sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\r\n", __func__);
1516 p->stati = 04000;
1517 p->isRead = false;
1518 break;
1519
1520 default:
1521 p->stati = 04501;
1522 p->chanStatus = chanStatIncorrectDCW;
1523 if (p->IDCW_DEV_CMD != 051)
1524 sim_warn ("%s: PRT unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1525 return IOM_CMD_ERROR;
1526 }
1527
1528 sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\r\n", __func__, p->stati);
1529 return IOM_CMD_PROCEED;
1530 }
1531
1532
1533 switch (statep->ioMode) {
1534 case prtNoMode:
1535
1536
1537
1538 break;
1539
1540 case prtPrt: {
1541 iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1542 statep->isEdited, statep->slew);
1543 if (rc)
1544 return rc;
1545 }
1546 break;
1547
1548 case prtLdImgBuf: {
1549 int rc = loadImageBuffer (iomUnitIdx, chan);
1550 if (rc)
1551 return IOM_CMD_ERROR;
1552 }
1553 break;
1554
1555 default:
1556 sim_warn ("%s: Unrecognized ioMode %d\r\n", __func__, statep->ioMode);
1557 return IOM_CMD_ERROR;
1558 }
1559 return IOM_CMD_PROCEED;
1560 }
1561
1562 iom_cmd_rc_t prt_cmd_300a (uint iomUnitIdx, uint chan) {
1563 #if defined(TESTING)
1564 cpu_state_t * cpup = _cpup;
1565 #endif
1566 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1567 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1568 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1569 UNIT * unitp = & prt_unit[devUnitIdx];
1570 int prt_unit_num = (int) PRT_UNIT_NUM (unitp);
1571 prt_state_t * statep = & prt_state[devUnitIdx];
1572
1573
1574 if (IS_IDCW (p)) {
1575
1576 statep->ioMode = prtNoMode;
1577
1578 switch (p->IDCW_DEV_CMD) {
1579 case 000:
1580 sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\r\n", __func__);
1581 p->stati = 04000;
1582 break;
1583
1584 case 001:
1585 sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\r\n", __func__);
1586 statep->ioMode = prtLdImgBuf;
1587 p->stati = 04000;
1588 break;
1589
1590 case 015:
1591 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\r\n", __func__);
1592 statep->ioMode = prtPrt;
1593 statep->prtUnitNum = prt_unit_num;
1594 statep->isBCD = false;
1595 statep->isEdited = false;
1596 statep->slew = 1;
1597 p->stati = 04000;
1598 break;
1599
1600 case 034:
1601 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\r\n", __func__);
1602 statep->ioMode = prtPrt;
1603 statep->prtUnitNum = prt_unit_num;
1604 statep->isBCD = false;
1605 statep->isEdited = true;
1606 statep->slew = 0;
1607 p->stati = 04000;
1608 break;
1609
1610 case 040:
1611 sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\r\n", __func__);
1612 p->stati = 04000;
1613 p->isRead = false;
1614 break;
1615
1616 default:
1617 p->stati = 04501;
1618 p->chanStatus = chanStatIncorrectDCW;
1619 if (p->IDCW_DEV_CMD != 051)
1620 sim_warn ("%s: PRT unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1621 return IOM_CMD_ERROR;
1622 }
1623
1624 sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\r\n", __func__, p->stati);
1625 return IOM_CMD_PROCEED;
1626 }
1627
1628
1629 switch (statep->ioMode) {
1630 case prtNoMode:
1631
1632
1633
1634 break;
1635
1636 case prtPrt: {
1637 iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1638 statep->isEdited, statep->slew);
1639 if (rc)
1640 return rc;
1641 }
1642 break;
1643
1644 case prtLdImgBuf: {
1645 int rc = loadImageBuffer (iomUnitIdx, chan);
1646 if (rc)
1647 return IOM_CMD_ERROR;
1648 }
1649 break;
1650
1651 default:
1652 sim_warn ("%s: Unrecognized ioMode %d\r\n", __func__, statep->ioMode);
1653 return IOM_CMD_ERROR;
1654 }
1655 return IOM_CMD_PROCEED;
1656 }
1657
1658 iom_cmd_rc_t prt_cmd_400 (uint iomUnitIdx, uint chan) {
1659 #if defined(TESTING)
1660 cpu_state_t * cpup = _cpup;
1661 #endif
1662 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1663 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1664 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1665 UNIT * unitp = & prt_unit[devUnitIdx];
1666 int prt_unit_num = (int) PRT_UNIT_NUM (unitp);
1667 prt_state_t * statep = & prt_state[devUnitIdx];
1668
1669
1670 if (IS_IDCW (p)) {
1671
1672 statep->ioMode = prtNoMode;
1673
1674 switch (p->IDCW_DEV_CMD) {
1675 case 000:
1676 sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\r\n", __func__);
1677 p->stati = 04000;
1678 break;
1679
1680 case 001:
1681 sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\r\n", __func__);
1682 statep->ioMode = prtLdImgBuf;
1683 p->stati = 04000;
1684 break;
1685
1686 case 003:
1687 sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\r\n", __func__);
1688 statep->ioMode = prtRdStatReg;
1689 p->stati = 04000;
1690 break;
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716 case 005:
1717 sim_debug (DBG_DEBUG, & prt_dev, "%s: Load VFC Image\r\n", __func__);
1718 statep->ioMode = prtLdVFCImg;
1719 p->stati = 04000;
1720 break;
1721
1722 case 010:
1723 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Zero Lines\r\n", __func__);
1724 statep->ioMode = prtPrt;
1725 statep->prtUnitNum = prt_unit_num;
1726 statep->isBCD = true;
1727 statep->isEdited = false;
1728 statep->slew = 0;
1729 p->stati = 04000;
1730 break;
1731
1732 case 011:
1733 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew One Line\r\n", __func__);
1734 statep->ioMode = prtPrt;
1735 statep->prtUnitNum = prt_unit_num;
1736 statep->isBCD = true;
1737 statep->isEdited = false;
1738 statep->slew = 1;
1739 p->stati = 04000;
1740 break;
1741
1742 case 012:
1743 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Two Lines\r\n", __func__);
1744 statep->ioMode = prtPrt;
1745 statep->prtUnitNum = prt_unit_num;
1746 statep->isBCD = true;
1747 statep->isEdited = false;
1748 statep->slew = 2;
1749 p->stati = 04000;
1750 break;
1751
1752 case 013:
1753 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Top Of Page\r\n", __func__);
1754 statep->ioMode = prtPrt;
1755 statep->prtUnitNum = prt_unit_num;
1756 statep->isBCD = true;
1757 statep->isEdited = false;
1758 statep->slew = -1;
1759 p->stati = 04000;
1760 break;
1761
1762 case 014:
1763 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Zero Lines\r\n", __func__);
1764 statep->ioMode = prtPrt;
1765 statep->prtUnitNum = prt_unit_num;
1766 statep->isBCD = false;
1767 statep->isEdited = false;
1768 statep->slew = 0;
1769 p->stati = 04000;
1770 break;
1771
1772 case 015:
1773 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\r\n", __func__);
1774 statep->ioMode = prtPrt;
1775 statep->prtUnitNum = prt_unit_num;
1776 statep->isBCD = false;
1777 statep->isEdited = false;
1778 statep->slew = 1;
1779 p->stati = 04000;
1780 break;
1781
1782 case 016:
1783 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Two Lines\r\n", __func__);
1784 statep->ioMode = prtPrt;
1785 statep->prtUnitNum = prt_unit_num;
1786 statep->isBCD = false;
1787 statep->isEdited = false;
1788 statep->slew = 2;
1789 p->stati = 04000;
1790 break;
1791
1792 case 017:
1793 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Top Of Page\r\n", __func__);
1794 statep->ioMode = prtPrt;
1795 statep->prtUnitNum = prt_unit_num;
1796 statep->isBCD = false;
1797 statep->isEdited = false;
1798 statep->slew = -1;
1799 p->stati = 04000;
1800 break;
1801
1802 case 030:
1803 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Zero Lines\r\n", __func__);
1804 statep->ioMode = prtPrt;
1805 statep->prtUnitNum = prt_unit_num;
1806 statep->isBCD = true;
1807 statep->isEdited = true;
1808 statep->slew = 0;
1809 p->stati = 04000;
1810 break;
1811
1812 case 031:
1813 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew One Line\r\n", __func__);
1814 statep->ioMode = prtPrt;
1815 statep->prtUnitNum = prt_unit_num;
1816 statep->isBCD = true;
1817 statep->isEdited = true;
1818 statep->slew = 1;
1819 p->stati = 04000;
1820 break;
1821
1822 case 032:
1823 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Two Lines\r\n", __func__);
1824 statep->ioMode = prtPrt;
1825 statep->prtUnitNum = prt_unit_num;
1826 statep->isBCD = true;
1827 statep->isEdited = true;
1828 statep->slew = 2;
1829 p->stati = 04000;
1830 break;
1831
1832 case 033:
1833 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Top Of Page\r\n", __func__);
1834 statep->ioMode = prtPrt;
1835 statep->prtUnitNum = prt_unit_num;
1836 statep->isBCD = true;
1837 statep->isEdited = true;
1838 statep->slew = -1;
1839 p->stati = 04000;
1840 break;
1841
1842 case 034:
1843 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\r\n", __func__);
1844 statep->ioMode = prtPrt;
1845 statep->prtUnitNum = prt_unit_num;
1846 statep->isBCD = false;
1847 statep->isEdited = true;
1848 statep->slew = 0;
1849 p->stati = 04000;
1850 break;
1851
1852 case 035:
1853 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew One Line\r\n", __func__);
1854 statep->ioMode = prtPrt;
1855 statep->prtUnitNum = prt_unit_num;
1856 statep->isBCD = false;
1857 statep->isEdited = true;
1858 statep->slew = 1;
1859 p->stati = 04000;
1860 break;
1861
1862 case 036:
1863 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Two Lines\r\n", __func__);
1864 statep->ioMode = prtPrt;
1865 statep->prtUnitNum = prt_unit_num;
1866 statep->isBCD = false;
1867 statep->isEdited = true;
1868 statep->slew = 2;
1869 p->stati = 04000;
1870 break;
1871
1872 case 037:
1873 sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Top Of Page\r\n", __func__);
1874 statep->ioMode = prtPrt;
1875 statep->prtUnitNum = prt_unit_num;
1876 statep->isBCD = false;
1877 statep->isEdited = true;
1878 statep->slew = -1;
1879 p->stati = 04000;
1880 break;
1881
1882 case 040:
1883 sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\r\n", __func__);
1884 p->stati = 04000;
1885 p->isRead = false;
1886 break;
1887
1888 case 061: {
1889 sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew One Line\r\n", __func__);
1890 int rc = print_buf (prt_unit_num, false, false, 1, NULL, 0);
1891 if (rc == -1) {
1892 p->stati = 04201;
1893 return IOM_CMD_ERROR;
1894 }
1895 if (rc == -2) {
1896 p->stati = 04210;
1897 return IOM_CMD_ERROR;
1898 }
1899 p->stati = 04000;
1900 p->isRead = false;
1901 }
1902 break;
1903
1904 case 062: {
1905 sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew Two Lines\r\n", __func__);
1906 int rc = print_buf (prt_unit_num, false, false, 2, NULL, 0);
1907 if (rc == -1) {
1908 p->stati = 04201;
1909 return IOM_CMD_ERROR;
1910 }
1911 if (rc == -2) {
1912 p->stati = 04210;
1913 return IOM_CMD_ERROR;
1914 }
1915 p->stati = 04000;
1916 p->isRead = false;
1917 }
1918 break;
1919
1920 case 063: {
1921 sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew To Top Of Page\r\n", __func__);
1922 int rc = print_buf (prt_unit_num, false, false, -1, NULL, 0);
1923 if (rc == -1) {
1924 p->stati = 04201;
1925 return IOM_CMD_ERROR;
1926 }
1927 if (rc == -2) {
1928 p->stati = 04210;
1929 return IOM_CMD_ERROR;
1930 }
1931 p->stati = 04000;
1932 p->isRead = false;
1933 }
1934 break;
1935
1936 case 066:
1937 sim_debug (DBG_DEBUG, & prt_dev, "%s: Reserve Device\r\n", __func__);
1938 p->stati = 04000;
1939 p->isRead = false;
1940 break;
1941
1942 case 067:
1943 sim_debug (DBG_DEBUG, & prt_dev, "%s: Release Device\r\n", __func__);
1944 p->stati = 04000;
1945 p->isRead = false;
1946 break;
1947
1948 default:
1949 p->stati = 04501;
1950 p->chanStatus = chanStatIncorrectDCW;
1951 if (p->IDCW_DEV_CMD != 051)
1952 sim_warn ("%s: PRT unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1953 return IOM_CMD_ERROR;
1954 }
1955
1956 sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\r\n", __func__, p->stati);
1957 return IOM_CMD_PROCEED;
1958 }
1959
1960
1961 switch (statep->ioMode) {
1962 case prtNoMode:
1963
1964
1965
1966 break;
1967
1968 case prtPrt: {
1969 iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1970 statep->isEdited, statep->slew);
1971 if (rc)
1972 return rc;
1973 }
1974 break;
1975
1976 case prtLdImgBuf: {
1977 int rc = loadImageBuffer (iomUnitIdx, chan);
1978 if (rc)
1979 return IOM_CMD_ERROR;
1980 }
1981 break;
1982
1983 case prtRdStatReg: {
1984 int rc = readStatusRegister (iomUnitIdx, chan);
1985 if (rc)
1986 return IOM_CMD_ERROR;
1987 }
1988 break;
1989
1990 case prtLdVFCImg: {
1991 int rc = loadVFCImage (iomUnitIdx, chan);
1992 if (rc)
1993 return IOM_CMD_ERROR;
1994 }
1995 break;
1996
1997 default:
1998 sim_warn ("%s: Unrecognized ioMode %d\r\n", __func__, statep->ioMode);
1999 return IOM_CMD_ERROR;
2000 }
2001 return IOM_CMD_PROCEED;
2002 }
2003
2004 iom_cmd_rc_t prt_iom_cmd (uint iomUnitIdx, uint chan) {
2005 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
2006 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
2007 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
2008 UNIT * unitp = & prt_unit[devUnitIdx];
2009 int prt_unit_num = (int) PRT_UNIT_NUM (unitp);
2010
2011 switch (model_type [prt_state[prt_unit_num].model]) {
2012 case 1:
2013 return prt_cmd_202 (iomUnitIdx, chan);
2014
2015 case 2:
2016 return prt_cmd_300 (iomUnitIdx, chan);
2017
2018 case 3:
2019 return prt_cmd_300a (iomUnitIdx, chan);
2020
2021
2022 case 4:
2023 return prt_cmd_400 (iomUnitIdx, chan);
2024 }
2025 p->stati = 04502;
2026 return IOM_CMD_DISCONNECT;
2027 }
2028
2029 static t_stat prt_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
2030 UNUSED const void * desc)
2031 {
2032 sim_printf("Number of PRT units in system is %d\r\n", prt_dev.numunits);
2033 return SCPE_OK;
2034 }
2035
2036 static t_stat prt_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
2037 UNUSED void * desc)
2038 {
2039 if (! cptr)
2040 return SCPE_ARG;
2041 int n = atoi (cptr);
2042 if (n < 1 || n > N_PRT_UNITS_MAX)
2043 return SCPE_ARG;
2044 prt_dev.numunits = (uint) n;
2045 return SCPE_OK;
2046 }
2047
2048 static t_stat prt_show_device_name (UNUSED FILE * st, UNIT * uptr,
2049 UNUSED int val, UNUSED const void * desc)
2050 {
2051 int n = (int) PRT_UNIT_NUM (uptr);
2052 if (n < 0 || n >= N_PRT_UNITS_MAX)
2053 return SCPE_ARG;
2054 sim_printf("name : %s", prt_state[n].device_name);
2055 return SCPE_OK;
2056 }
2057
2058 static t_stat prt_set_device_model (UNUSED UNIT * uptr, UNUSED int32 value,
2059 const UNUSED char * cptr, UNUSED void * desc)
2060 {
2061 int n = (int) PRT_UNIT_NUM (uptr);
2062 if (n < 0 || n >= N_PRT_UNITS_MAX)
2063 return SCPE_ARG;
2064 if (cptr)
2065 {
2066 for (int i = 0; i < N_MODELS; i ++)
2067 {
2068 if (strcmp (cptr, model_names[i]) == 0)
2069 {
2070 prt_state[n].model = i;
2071 return SCPE_OK;
2072 }
2073 }
2074 sim_printf ("Model '%s' not known (202 300 301 302 303 304 401 402 901 1000 1200 1201 1600)\r\n", cptr);
2075 return SCPE_ARG;
2076 }
2077 sim_printf ("Specify model from 202 300 301 302 303 304 401 402 901 1000 1200 1201 1600\r\n");
2078 return SCPE_ARG;
2079 }
2080
2081 static t_stat prt_show_device_model (UNUSED FILE * st, UNIT * uptr,
2082 UNUSED int val, UNUSED const void * desc)
2083 {
2084 int n = (int) PRT_UNIT_NUM (uptr);
2085 if (n < 0 || n >= N_PRT_UNITS_MAX)
2086 return SCPE_ARG;
2087 sim_printf("model : %s", model_names[prt_state[n].model]);
2088 return SCPE_OK;
2089 }
2090
2091 static t_stat prt_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
2092 const UNUSED char * cptr, UNUSED void * desc)
2093 {
2094 int n = (int) PRT_UNIT_NUM (uptr);
2095 if (n < 0 || n >= N_PRT_UNITS_MAX)
2096 return SCPE_ARG;
2097 if (cptr)
2098 {
2099 strncpy (prt_state[n].device_name, cptr, MAX_DEV_NAME_LEN - 1);
2100 prt_state[n].device_name[MAX_DEV_NAME_LEN - 1] = 0;
2101 }
2102 else
2103 {
2104 prt_state[n].device_name[0] = 0;
2105 }
2106 return SCPE_OK;
2107 }
2108
2109 static t_stat prt_show_path (UNUSED FILE * st, UNUSED UNUSED UNIT * uptr,
2110 UNUSED int val, UNUSED const void * desc)
2111 {
2112 if (prt_path[1] != '\0')
2113 {
2114 sim_printf("Path to PRT files is %s\r\n", prt_path);
2115 }
2116 else
2117 {
2118 char cwd_path [SIR_MAXPATH + 1];
2119 if (getcwd(cwd_path, sizeof(cwd_path)) != NULL)
2120 {
2121 sim_printf("Path to PRT files is %s\r\n", cwd_path);
2122 }
2123 else
2124 {
2125 if (errno)
2126 {
2127 sim_printf("Path to PRT files is unavailable: %s (Error %d)\r\n",
2128 xstrerror_l(errno), errno);
2129 }
2130 else
2131 {
2132 sim_printf("Path to PRT files is undefined\r\n");
2133 }
2134 }
2135 }
2136 return SCPE_OK;
2137 }
2138
2139 static t_stat prt_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
2140 const UNUSED char * cptr, UNUSED void * desc)
2141 {
2142 if (! cptr)
2143 return SCPE_ARG;
2144
2145 size_t len = strlen(cptr);
2146
2147 if (len >= sizeof(prt_path))
2148 return SCPE_ARG;
2149 strncpy(prt_path, cptr, sizeof(prt_path) - 1);
2150 prt_path[sizeof(prt_path) - 1] = '\0';
2151 if (len > 0)
2152 {
2153 if (prt_path[len - 1] != '/')
2154 {
2155 if (len == sizeof(prt_path) - 1)
2156 return SCPE_ARG;
2157 prt_path[len++] = '/';
2158 prt_path[len] = 0;
2159 }
2160 }
2161 return SCPE_OK;
2162 }
2163
2164 t_stat burst_printer (UNUSED int32 arg, const char * buf)
2165 {
2166 for (int i = 0; i < N_PRT_UNITS_MAX; i ++)
2167 {
2168 if (strcmp (buf, prt_state [i] . device_name) == 0)
2169 {
2170 if (prt_state [i] . prtfile != -1)
2171 {
2172 close (prt_state [i] . prtfile);
2173 eoj_history_len [i] = 0;
2174 prt_state [i] . prtfile = -1;
2175 prt_state [i] . in_trailing_banner = false;
2176 prt_state [i] . secondary_sentinel_seen = false;
2177 prt_state [i] . delay_secondary_sentinel_check = false;
2178 prt_state [i] . history_buf_len = 0;
2179
2180 int rename_attempts = 0;
2181 const int MAX_RENAME_ATTEMPTS = 10000;
2182 bool rename_successful = false;
2183
2184 char old_open_filename [SIR_MAXPATH];
2185 char new_target_filename [SIR_MAXPATH];
2186
2187 strcpy (old_open_filename, prt_state [i] . filename);
2188
2189 char * open_ext_pos = strstr (old_open_filename, ".OPEN");
2190 if (open_ext_pos)
2191 {
2192 strncpy (new_target_filename, old_open_filename, open_ext_pos - old_open_filename);
2193 new_target_filename [open_ext_pos - old_open_filename] = '\0';
2194 }
2195 else
2196 strcpy (new_target_filename, old_open_filename);
2197
2198 while (rename_attempts < MAX_RENAME_ATTEMPTS)
2199 {
2200 if (safe_rename (old_open_filename, new_target_filename) == 0)
2201 {
2202 rename_successful = true;
2203 break;
2204 }
2205
2206 char new_random_part [7];
2207 const char charset [] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
2208 const int charset_size = sizeof (charset) - 1;
2209
2210 for (int j = 0; j < 6; ++j)
2211 {
2212 new_random_part [j] = charset [random () % charset_size];
2213 }
2214
2215 new_random_part [6] = '\0';
2216
2217 char * prt_ext_pos = strstr (new_target_filename, ".prt");
2218 if (prt_ext_pos)
2219 {
2220 char * random_start_pos = prt_ext_pos - 6;
2221 if (random_start_pos >= new_target_filename)
2222 (void)memmove (random_start_pos, new_random_part, 6);
2223 }
2224
2225 rename_attempts++;
2226 }
2227
2228 if (!rename_successful)
2229 {
2230 sir_error ("Failed to rename '%s': %s (Error %d)", old_open_filename, xstrerror_l (errno), errno);
2231 }
2232
2233 return SCPE_OK;
2234 }
2235
2236 sim_printf ("burst sees nothing to burst\r\n");
2237 return SCPE_OK;
2238 }
2239 }
2240
2241 sim_printf ("burst can't find printer named '%s'\r\n", buf);
2242
2243 return SCPE_ARG;
2244 }
2245
2246 static t_stat signal_prt_ready (uint prt_unit_idx) {
2247
2248 if (! sim_is_running)
2249 return SCPE_OK;
2250 uint ctlr_unit_idx = cables->prt_to_urp[prt_unit_idx].ctlr_unit_idx;
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275 for (uint ctlr_port_num = 0; ctlr_port_num < MAX_CTLR_PORTS; ctlr_port_num ++) {
2276 struct ctlr_to_iom_s * urp_to_iom = & cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num];
2277 if (urp_to_iom->in_use) {
2278 uint iom_unit_idx = urp_to_iom->iom_unit_idx;
2279 uint chan_num = urp_to_iom->chan_num;
2280 uint dev_code = cables->prt_to_urp[prt_unit_idx].dev_code;
2281
2282 send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0x40, 01 );
2283 return SCPE_OK;
2284 }
2285 }
2286 return SCPE_ARG;
2287
2288 }
2289
2290 static t_stat prt_set_ready (UNIT * uptr, UNUSED int32 value,
2291 UNUSED const char * cptr,
2292 UNUSED void * desc)
2293 {
2294 #if defined(TESTING)
2295 cpu_state_t * cpup = _cpup;
2296 #endif
2297 int n = (int) PRT_UNIT_NUM (uptr);
2298 if (n < 0 || n >= N_PRT_UNITS_MAX)
2299 {
2300 sim_debug (DBG_ERR, & prt_dev,
2301 "Printer set ready: Invalid unit number %ld\r\n", (long) n);
2302 sim_printf ("error: Invalid unit number %ld\r\n", (long) n);
2303 return SCPE_ARG;
2304 }
2305 return signal_prt_ready ((uint) n);
2306 }
2307
2308 static config_value_list_t cfg_on_off [] =
2309 {
2310 { "off", 0 },
2311 { "on", 1 },
2312 { "disable", 0 },
2313 { "enable", 1 },
2314 { NULL, 0 }
2315 };
2316
2317 static config_list_t prt_config_list [] =
2318 {
2319 { "split", 0, 1, cfg_on_off },
2320 { NULL, 0, 0, NULL }
2321 };
2322
2323 static t_stat prt_set_config (UNUSED UNIT * uptr, UNUSED int32 value,
2324 const char * cptr, UNUSED void * desc)
2325 {
2326 int devUnitIdx = (int) PRT_UNIT_NUM (uptr);
2327 prt_state_t * psp = prt_state + devUnitIdx;
2328
2329 config_state_t cfg_state = { NULL, NULL };
2330
2331 for (;;)
2332 {
2333 int64_t v;
2334 int rc = cfg_parse (__func__, cptr, prt_config_list,
2335 & cfg_state, & v);
2336 if (rc == -1)
2337 break;
2338
2339 if (rc == -2)
2340 {
2341 cfg_parse_done (& cfg_state);
2342 return SCPE_ARG;
2343 }
2344 const char * p = prt_config_list[rc].name;
2345
2346 if (strcmp (p, "split") == 0)
2347 {
2348 psp->split = v != 0;
2349 continue;
2350 }
2351
2352 sim_warn ("error: prt_set_config: Invalid cfg_parse rc <%ld>\r\n",
2353 (long) rc);
2354 cfg_parse_done (& cfg_state);
2355 return SCPE_ARG;
2356 }
2357 cfg_parse_done (& cfg_state);
2358 return SCPE_OK;
2359 }
2360
2361 static t_stat prt_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
2362 UNUSED int val, UNUSED const void * desc)
2363 {
2364 int devUnitIdx = (int) PRT_UNIT_NUM (uptr);
2365 prt_state_t * psp = prt_state + devUnitIdx;
2366 sim_msg ("split : %d", psp->split);
2367 return SCPE_OK;
2368 }