This source file includes following definitions.
- rdr_init
- rdr_reset
- asciiToH
- getCardLine
- getCardData
- getRawCardData
- rdrReadRecord
- submit
- scanForCards
- rdrProcessEvent
- rdrCardReady
- rdr_iom_cmd
- rdr_show_nunits
- rdr_set_nunits
- rdr_show_device_name
- rdr_set_device_name
- rdr_set_path
- rdr_show_path
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
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <dirent.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <stdint.h>
43
44 #include "dps8.h"
45 #include "dps8_iom.h"
46 #include "dps8_crdrdr.h"
47 #include "dps8_sys.h"
48 #include "dps8_cable.h"
49 #include "dps8_cpu.h"
50 #include "dps8_faults.h"
51 #include "dps8_scu.h"
52 #include "dps8_utils.h"
53
54 #if defined(NO_LOCALE)
55 # define xstrerror_l strerror
56 #endif
57
58 #define DBG_CTR 1
59 #define N_RDR_UNITS 1
60
61 #define snprintf_truncat(dst, size, ...) \
62 do \
63 { \
64 volatile size_t n = size; \
65 (void)snprintf (dst, n, __VA_ARGS__); \
66 } \
67 while (0)
68
69 static t_stat rdr_reset (DEVICE * dptr);
70 static t_stat rdr_show_nunits (FILE *st, UNIT *uptr, int val, const void *desc);
71 static t_stat rdr_set_nunits (UNIT * uptr, int32 value, const char * cptr, void * desc);
72 static t_stat rdr_show_device_name (FILE *st, UNIT *uptr, int val, const void *desc);
73 static t_stat rdr_set_device_name (UNIT * uptr, int32 value, const char * cptr, void * desc);
74 static t_stat rdr_show_path (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
75 UNUSED const void * desc);
76 static t_stat rdr_set_path (UNUSED UNIT * uptr, UNUSED int32 value, const UNUSED char * cptr,
77 UNUSED void * desc);
78
79 #define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
80 UNIT_IDLE )
81 UNIT rdr_unit [N_RDR_UNITS_MAX] =
82 {
83 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
84 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
85 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
86 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
87 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
88 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
89 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
90 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
91 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
92 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
93 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
94 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
95 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
96 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
97 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
98 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}
99 };
100
101 #define RDR_UNIT_NUM(uptr) ((uptr) - rdr_unit)
102
103 static DEBTAB rdr_dt [] =
104 {
105 { "NOTIFY", DBG_NOTIFY, NULL },
106 { "INFO", DBG_INFO, NULL },
107 { "ERR", DBG_ERR, NULL },
108 { "WARN", DBG_WARN, NULL },
109 { "DEBUG", DBG_DEBUG, NULL },
110 { "ALL", DBG_ALL, NULL },
111 { NULL, 0, NULL }
112 };
113
114 #define UNIT_WATCH UNIT_V_UF
115
116 static MTAB rdr_mod [] =
117 {
118 #if !defined(SPEED)
119 { UNIT_WATCH, 1, "WATCH", "WATCH", 0, 0, NULL, NULL },
120 { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
121 #endif
122 {
123 MTAB_XTD | MTAB_VDV | \
124 MTAB_NMO | MTAB_VALR,
125 0,
126 "NUNITS",
127 "NUNITS",
128 rdr_set_nunits,
129 rdr_show_nunits,
130 "Number of RDR units in the system",
131 NULL
132 },
133 {
134 MTAB_XTD | MTAB_VUN | \
135 MTAB_VALR | MTAB_NC,
136 0,
137 "NAME",
138 "NAME",
139 rdr_set_device_name,
140 rdr_show_device_name,
141 "Select the boot drive",
142 NULL
143 },
144 {
145 MTAB_XTD | MTAB_VDV | MTAB_NMO | \
146 MTAB_VALR | MTAB_NC,
147 0,
148 "PATH",
149 "PATH",
150 rdr_set_path,
151 rdr_show_path,
152 "Path to card reader directories",
153 NULL
154 },
155
156 { 0, 0, NULL, NULL, 0, 0, NULL, NULL }
157 };
158
159 DEVICE rdr_dev = {
160 "RDR",
161 rdr_unit,
162 NULL,
163 rdr_mod,
164 N_RDR_UNITS,
165 10,
166 24,
167 1,
168 8,
169 36,
170 NULL,
171 NULL,
172 rdr_reset,
173 NULL,
174 NULL,
175 NULL,
176 NULL,
177 DEV_DEBUG,
178 0,
179 rdr_dt,
180 NULL,
181 NULL,
182 NULL,
183 NULL,
184 NULL,
185 NULL,
186 NULL
187 };
188
189 enum deckFormat { sevenDeck, cardDeck, streamDeck, xDeck };
190
191
192
193
194
195 static struct rdr_state
196 {
197 enum rdr_mode
198 {
199 rdr_no_mode, rdr_rd_bin
200 } io_mode;
201 int deckfd;
202
203
204 enum { deckStart = 0, eof1Sent, uid1Sent, inputSent, eof2Sent} deckState;
205 enum deckFormat deckFormat;
206 bool running;
207 char device_name [MAX_DEV_NAME_LEN];
208 char fname [PATH_MAX+1];
209 } rdr_state [N_RDR_UNITS_MAX];
210
211 static char* rdr_name = "rdr";
212 static char rdr_path_prefix[PATH_MAX+1];
213
214
215
216
217
218
219
220 void rdr_init (void)
221 {
222 (void)memset (rdr_path_prefix, 0, sizeof (rdr_path_prefix));
223 (void)memset (rdr_state, 0, sizeof (rdr_state));
224 for (uint i = 0; i < N_RDR_UNITS_MAX; i ++)
225 rdr_state [i] . deckfd = -1;
226 }
227
228 static t_stat rdr_reset (UNUSED DEVICE * dptr)
229 {
230
231
232
233
234
235
236
237 return SCPE_OK;
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 static uint16 table [128] =
363 {
364 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007,
365 02011, 04021, 02021, 04103, 04043, 04023, 04013, 04007,
366 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011,
367 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007,
368 00000, 02202, 00006, 00102, 02102, 01042, 04000, 00022,
369 04022, 02022, 02042, 04012, 01102, 02000, 04102, 01400,
370 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004,
371 00002, 00001, 00202, 02012, 04042, 00012, 01012, 01006,
372 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004,
373 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010,
374 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010,
375 01004, 01002, 01001, 05022, 04202, 06022, 02006, 01022,
376 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004,
377 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010,
378 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010,
379 03004, 03002, 03001, 05000, 04006, 03000, 03400, 00000
380 };
381
382 static void asciiToH (char * str, uint * hstr, size_t l)
383 {
384 char * p = str;
385 for (size_t i = 0; i < l; i ++)
386
387 {
388 * hstr ++ = table [(* p) & 0177];
389 p ++;
390 }
391 }
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421 static int getCardLine (int fd, unsigned char * buffer)
422 {
423 uint n = 0;
424 buffer [n] = 0;
425 while (1)
426 {
427 uint8 ch;
428 ssize_t rc = read (fd, & ch, 1);
429 if (rc <= 0)
430 return n == 0;
431 if (ch == '\n')
432 return 0;
433 buffer [n ++] = ch;
434 buffer [n] = 0;
435 if (n > 79)
436 return 0;
437 }
438 #if defined(SUNLINT) || !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
439
440 return 0;
441 #endif
442 }
443
444 static int getCardData (int fd, char * buffer)
445 {
446 (void)memset (buffer, 0, 80);
447 ssize_t rc = read (fd, buffer, 80);
448 if (rc < 0)
449 return 0;
450 return (int) rc;
451 }
452
453 #define rawCardImageBytes (80 * 12 / 8)
454 static int getRawCardData (int fd, uint8_t * buffer)
455 {
456 (void)memset (buffer, 0, rawCardImageBytes + 2);
457 ssize_t rc = read (fd, buffer, rawCardImageBytes);
458 if (rc < 0)
459 return 0;
460 return (int) rc;
461 }
462
463 #if defined(TESTING)
464 static bool empty = false;
465 #endif
466
467 static int rdrReadRecord (uint iomUnitIdx, uint chan) {
468 #if defined(TESTING)
469 cpu_state_t * cpup = _cpup;
470 #endif
471 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
472
473 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
474 uint unitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492 #if defined(TESTING)
493 sim_printf ("hopper not empty\r\n");
494 empty = false;
495 #endif
496 unsigned char cardImage [80] = "";
497 uint8_t rawCardImage [rawCardImageBytes + 2 ];
498 size_t l = 0;
499
500 enum deckFormat thisCard = cardDeck;
501
502 static int jobNo = 0;
503
504 switch (rdr_state [unitIdx].deckState) {
505 case deckStart: {
506 #if defined(TESTING)
507 sim_printf ("deckStart: sending ++EOF\r\n");
508 #endif
509 strcpy ((char *) cardImage, "++EOF");
510 l = strlen ((char *) cardImage);
511 thisCard = cardDeck;
512 rdr_state [unitIdx].deckState = eof1Sent;
513 jobNo ++;
514 }
515 break;
516
517 case eof1Sent: {
518 #if defined(TESTING)
519 sim_printf ("eof1Sent: sending ++UID\r\n");
520 #endif
521 (void)sprintf ((char *) cardImage, "++UID %d", jobNo);
522 l = strlen ((char *) cardImage);
523 thisCard = cardDeck;
524 rdr_state [unitIdx].deckState = uid1Sent;
525 }
526 break;
527
528 case uid1Sent: {
529 #if defined(TESTING)
530 sim_printf ("uid1Sent: sending data\r\n");
531 #endif
532 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
533 if (rc) {
534 #if defined(TESTING)
535 sim_printf ("uid1Sent: getCardLine returned %d\r\n", rc);
536 #endif
537 close (rdr_state [unitIdx].deckfd);
538
539 rc = unlink (rdr_state [unitIdx].fname);
540 if (rc)
541 perror ("card reader deck unlink\r\n");
542 rdr_state [unitIdx].deckfd = -1;
543 rdr_state [unitIdx].deckState = deckStart;
544 p->stati = 04201;
545 return IOM_CMD_DISCONNECT;
546 }
547 #if defined(TESTING)
548 sim_printf ("uid1Sent: getCardLine returned <%s>\r\n", cardImage);
549 #endif
550 l = strlen ((char *) cardImage);
551 thisCard = cardDeck;
552 if (strncasecmp ((char *) cardImage, "++input", 7) == 0) {
553 #if defined(TESTING)
554 sim_printf ("uid1Sent: switching to inputSent <%s>\r\n", cardImage);
555 #endif
556 rdr_state [unitIdx].deckState = inputSent;
557 }
558 }
559 break;
560
561
562
563 case inputSent: {
564 #if defined(TESTING)
565 sim_printf ("inputSent: format %d\r\n", rdr_state [unitIdx].deckFormat);
566 #endif
567 switch (rdr_state [unitIdx].deckFormat) {
568 case xDeck: {
569 #if defined(TESTING)
570 sim_printf ("inputSent: xDeck\r\n");
571 #endif
572 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
573 if (rc) {
574 rdr_state [unitIdx].deckState = deckStart;
575 close (rdr_state [unitIdx].deckfd);
576
577 int rc = unlink (rdr_state [unitIdx].fname);
578 if (rc)
579 perror ("card reader deck unlink\r\n");
580 rdr_state [unitIdx].deckfd = -1;
581 p->stati = 04201;
582 return IOM_CMD_DISCONNECT;
583 }
584 l = strlen ((char *) cardImage);
585 }
586 thisCard = cardDeck;
587 break;
588
589 case cardDeck: {
590 #if defined(TESTING)
591 sim_printf ("inputSent: cardDeck\r\n");
592 #endif
593 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
594 if (rc) {
595 strcpy ((char *) cardImage, "++EOF");
596 rdr_state [unitIdx].deckState = eof2Sent;
597 }
598 l = strlen ((char *) cardImage);
599 }
600 thisCard = cardDeck;
601 break;
602
603 case streamDeck: {
604 #if defined(TESTING)
605 sim_printf ("inputSent: streamDeck\r\n");
606 #endif
607 l = (size_t) getCardData (rdr_state [unitIdx].deckfd, (char *) cardImage);
608 if (l) {
609 thisCard = streamDeck;
610 } else {
611 strcpy ((char *) cardImage, "++EOF");
612 l = strlen ((char *) cardImage);
613 rdr_state [unitIdx].deckState = eof2Sent;
614 thisCard = cardDeck;
615 }
616 #if defined(TESTING)
617 sim_printf ("inputSent: getCardLine returned <%s>\r\n", cardImage);
618 #endif
619 }
620 break;
621
622 case sevenDeck: {
623 #if defined(TESTING)
624 sim_printf ("inputSent: 7Deck\r\n");
625 #endif
626 l = (size_t) getRawCardData (rdr_state [unitIdx].deckfd, rawCardImage);
627 if (l) {
628 thisCard = sevenDeck;
629 } else {
630 strcpy ((char *) cardImage, "++EOF");
631 l = strlen ((char *) cardImage);
632 rdr_state [unitIdx].deckState = eof2Sent;
633 thisCard = cardDeck;
634 }
635 }
636 break;
637
638 }
639 }
640 break;
641
642
643
644 case eof2Sent: {
645 # if defined(TESTING)
646 sim_printf ("eof2Sent\r\n");
647 # endif
648 (void)sprintf ((char *) cardImage, "++UID %d", jobNo);
649 l = strlen ((char *) cardImage);
650 thisCard = cardDeck;
651 rdr_state [unitIdx].deckState = deckStart;
652 close (rdr_state [unitIdx].deckfd);
653
654 int rc = unlink (rdr_state [unitIdx].fname);
655 if (rc)
656 perror ("card reader deck unlink\r\n");
657 rdr_state [unitIdx].deckfd = -1;
658 }
659 break;
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689 }
690
691
692
693
694
695
696 #if defined(TESTING)
697 sim_printf ("\r\n");
698 sim_printf ("\r\n");
699 for (uint i = 0; i < 80; i ++) {
700 if (isprint (cardImage [i]))
701 sim_printf ("%c", cardImage [i]);
702 else
703 sim_printf ("\\%03o", cardImage [i]);
704 }
705 sim_printf ("\r\n");
706 sim_printf ("\r\n");
707 #endif
708 word36 buffer [27];
709 switch (thisCard) {
710 case sevenDeck: {
711
712
713 for (uint i = 0; i < 27; i ++)
714 buffer [i] = extr36 ((uint8 *) rawCardImage, i);
715
716
717 }
718 break;
719
720 case streamDeck:
721
722
723
724
725
726
727
728
729
730
731 case xDeck:
732 case cardDeck: {
733 if (l > 80) {
734 sim_warn ("Whups. rdr l %lu > 80; truncating.\r\n", (unsigned long)l);
735 l = 80;
736
737 }
738
739 uint hbuf [l + 1];
740 asciiToH ((char *) cardImage, hbuf, l);
741
742
743 uint nbits = (uint) l * 12;
744
745 uint tally = (nbits + 35) / 36;
746
747 if (tally > 27) {
748 sim_warn ("Impossible rdr tally: %d > 27; truncating.\r\n", tally);
749 tally = 27;
750 }
751
752
753
754 (void)memset (buffer, 0, sizeof (buffer));
755 for (uint col = 0; col < l; col ++) {
756 uint wordno = col / 3;
757 uint fieldno = col % 3;
758 putbits36_12 (& buffer [wordno], fieldno * 12, (word12) hbuf [col]);
759 }
760 }
761 break;
762 }
763
764
765
766
767
768
769
770
771
772
773
774 p->stati = 04000;
775
776
777 uint tally = 27;
778
779 iom_indirect_data_service (iomUnitIdx, chan, buffer, & tally, true);
780 p->initiate = false;
781 p->stati = 04000;
782 p->tallyResidue = (word12) tally & MASK12;
783 p->charPos = 0;
784
785 return IOM_CMD_PROCEED;
786 }
787
788 static void submit (enum deckFormat fmt, char * fname, uint16 readerIndex)
789 {
790 if (readerIndex >= N_RDR_UNITS_MAX) {
791 sim_warn("crdrdr: submit called with invalid reader index %ld\r\n", (long) readerIndex);
792 return;
793 }
794
795 int deckfd = open (fname, O_RDONLY);
796 if (deckfd < 0)
797 perror ("card reader deck open\r\n");
798
799
800 #if defined(TESTING)
801 sim_printf ("submit %s\r\n", fname);
802 #endif
803 #if defined(__GNUC__)
804 # if !defined(__clang_version__)
805 # if __GNUC__ > 7
806 # if !defined(__INTEL_COMPILER)
807 # pragma GCC diagnostic push
808 # pragma GCC diagnostic ignored "-Wstringop-truncation"
809 # endif
810 # endif
811 # endif
812 #endif
813 strncpy (rdr_state [readerIndex].fname, fname, sizeof(rdr_state [readerIndex].fname) - 1);
814 rdr_state [readerIndex].fname [sizeof(rdr_state [readerIndex].fname) - 1] = '\0';
815 #if defined(__GNUC__)
816 # if !defined(__clang_version__)
817 # if __GNUC__ > 7
818 # if !defined(__INTEL_COMPILER)
819 # pragma GCC diagnostic pop
820 # endif
821 # endif
822 # endif
823 #endif
824 rdr_state [readerIndex].deckfd = deckfd;
825 rdr_state [readerIndex].deckState = deckStart;
826 rdr_state [readerIndex].deckFormat = fmt;
827 if (fmt == xDeck) {
828 rdr_state [readerIndex].deckState = inputSent;
829 }
830 if (deckfd >= 0)
831 rdrCardReady (readerIndex);
832 }
833
834 static void scanForCards(uint16 readerIndex)
835 {
836 char rdr_dir [2 * PATH_MAX + 8];
837
838 if (readerIndex >= N_RDR_UNITS_MAX) {
839 sim_warn("crdrdr: scanForCards called with invalid reader index %d\r\n", readerIndex);
840 return;
841 }
842
843 #if !defined(__MINGW64__) || !defined(__MINGW32__)
844 const char* r_tmpdir = getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp";
845 #else
846 const char* r_tmpdir = getenv("TEMP") ? getenv("TEMP") : \
847 getenv("TMP") ? getenv("TMP") : ".";
848 #endif
849 snprintf_truncat(rdr_dir, PATH_MAX + 1, "%s/%s%c",
850 r_tmpdir, rdr_name, 'a' + readerIndex);
851
852 if (rdr_path_prefix [0])
853 {
854 snprintf_truncat(rdr_dir, PATH_MAX + 1, "%s%s%c",
855 rdr_path_prefix, rdr_name, 'a' + readerIndex);
856 }
857
858 DIR * dp;
859 dp = opendir (rdr_dir);
860 if (! dp)
861 {
862 sim_warn ("crdrdr opendir '%s' fail.\r\n", rdr_dir);
863 perror ("opendir");
864 return;
865 }
866 struct dirent * entry;
867 struct stat info;
868 char fqname [2 * PATH_MAX + 8];
869 while ((entry = readdir (dp)))
870 {
871 strcpy (fqname, rdr_dir);
872 strcat (fqname, "/");
873 strcat (fqname, entry -> d_name);
874
875 if (stat(fqname, &info) != 0)
876 {
877 sim_warn("crdrdr: scanForCards stat() error for %s: %s\r\n", fqname, xstrerror_l(errno));
878 continue;
879 }
880
881 if (S_ISDIR(info.st_mode))
882 {
883
884 continue;
885 }
886
887 if (rdr_state [readerIndex] . deckfd < 0)
888 {
889 if (strncmp (entry -> d_name, "xdeck.", 6) == 0)
890 {
891 submit (xDeck, fqname, readerIndex);
892 break;
893 }
894 if (strncmp (entry -> d_name, "cdeck.", 6) == 0)
895 {
896 submit (cardDeck, fqname, readerIndex);
897 break;
898 }
899 if (strncmp (entry -> d_name, "7deck.", 6) == 0)
900 {
901 submit (sevenDeck, fqname, readerIndex);
902 break;
903 }
904 if (strncmp (entry -> d_name, "sdeck.", 6) == 0)
905 {
906 submit (streamDeck, fqname, readerIndex);
907 break;
908 }
909 }
910 if (strcmp (entry -> d_name, "discard") == 0)
911 {
912
913 int rc = unlink (fqname);
914 if (rc)
915 perror ("crdrdr discard unlink\r\n");
916 if (rdr_state [readerIndex] . deckfd >= 0)
917 {
918 close (rdr_state [readerIndex] . deckfd);
919 rc = unlink (rdr_state [readerIndex] . fname);
920 if (rc)
921 perror ("crdrdr deck unlink\r\n");
922 rdr_state [readerIndex] . deckfd = -1;
923 rdr_state [readerIndex] . deckState = deckStart;
924 break;
925 }
926 }
927 }
928 closedir (dp);
929 }
930
931 void rdrProcessEvent (void)
932 {
933 if (rdr_path_prefix [0])
934 {
935
936
937 for (uint16 reader_idx = 0; reader_idx < rdr_dev . numunits; reader_idx++)
938 {
939 if (rdr_state [reader_idx] . running)
940 scanForCards(reader_idx);
941 }
942 }
943 else
944 {
945
946
947 if (! rdr_state [0] . running)
948 return;
949
950 scanForCards(0);
951 }
952 }
953
954 void rdrCardReady (int unitNum)
955 {
956 uint ctlr_unit_idx = cables->rdr_to_urp [unitNum].ctlr_unit_idx;
957 uint ctlr_port_num = 0;
958 uint iom_unit_idx = cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num].iom_unit_idx;
959 uint chan_num = cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num].chan_num;
960 uint dev_code = cables->rdr_to_urp[unitNum].dev_code;
961 send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0377, 0377 );
962 }
963
964 iom_cmd_rc_t rdr_iom_cmd (uint iomUnitIdx, uint chan) {
965 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
966 #if defined(xTESTING)
967 uint dev_code = p->IDCW_DEV_CODE;
968 cpu_state_t * cpup = _cpup;
969
970
971
972 #endif
973
974 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
975 uint unitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
976 struct rdr_state * statep = & rdr_state[unitIdx];
977 statep->running = true;
978
979 iom_cmd_rc_t rc = IOM_CMD_PROCEED;
980
981 if (IS_IDCW (p)) {
982
983 statep->io_mode = rdr_no_mode;
984
985 switch (p->IDCW_DEV_CMD) {
986 case 000:
987
988 p->stati = 04000;
989
990
991
992 #if defined(TESTING)
993 sim_printf ("Request status %04o\r\n", p->stati);
994 #endif
995 break;
996
997 case 001:
998
999 if (rdr_state [unitIdx].deckfd < 0) {
1000 p->stati = 04201;
1001 p->tallyResidue = 0;
1002 #if defined(TESTING)
1003 if (! empty)
1004 sim_printf ("hopper empty\r\n");
1005 empty = true;
1006 #endif
1007 return IOM_CMD_DISCONNECT;
1008 }
1009 statep->io_mode = rdr_rd_bin;
1010 p->stati = 04000;
1011
1012
1013
1014 #if defined(TESTING)
1015 sim_printf ("read binary %04o\r\n", p->stati);
1016 #endif
1017 break;
1018
1019 case 040:
1020
1021 p->stati = 04000;
1022 p->isRead = false;
1023
1024
1025
1026 #if defined(TESTING)
1027 sim_printf ("reset status %04o\r\n", p->stati);
1028 #endif
1029 break;
1030
1031 default:
1032 #if defined(TESTING)
1033 sim_printf ("unknown %o\r\n", p->IDCW_DEV_CMD);
1034 #endif
1035 if (p->IDCW_DEV_CMD != 051)
1036 sim_warn ("%s: RDR unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1037 p->stati = 04501;
1038 p->chanStatus = chanStatIncorrectDCW;
1039 return IOM_CMD_ERROR;
1040 }
1041
1042
1043 return IOM_CMD_PROCEED;
1044 }
1045
1046
1047 switch (statep->io_mode) {
1048 case rdr_no_mode:
1049 #if defined(TESTING)
1050 sim_printf ("%s: Unexpected IOTx\r\n", __func__);
1051 #endif
1052
1053
1054 break;
1055
1056 case rdr_rd_bin: {
1057 int rc = rdrReadRecord (iomUnitIdx, chan);
1058 #if defined(TESTING)
1059 sim_printf ("rdrReadRecord returned %d\r\n", rc);
1060 #endif
1061 if (rc)
1062 return IOM_CMD_DISCONNECT;
1063 }
1064 break;
1065
1066 default:
1067 sim_warn ("%s: Unrecognized io_mode %d\r\n", __func__, statep->io_mode);
1068 return IOM_CMD_ERROR;
1069 }
1070 return rc;
1071 }
1072
1073 static t_stat rdr_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
1074 UNUSED const void * desc)
1075 {
1076 sim_printf("Number of RDR units in system is %d\r\n", rdr_dev . numunits);
1077 return SCPE_OK;
1078 }
1079
1080 static t_stat rdr_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
1081 UNUSED void * desc)
1082 {
1083 if (! cptr)
1084 return SCPE_ARG;
1085 int n = atoi (cptr);
1086 if (n < 1 || n > N_RDR_UNITS_MAX)
1087 return SCPE_ARG;
1088 rdr_dev . numunits = (uint32) n;
1089 return SCPE_OK;
1090 }
1091
1092 static t_stat rdr_show_device_name (UNUSED FILE * st, UNIT * uptr,
1093 UNUSED int val, UNUSED const void * desc)
1094 {
1095 long n = RDR_UNIT_NUM (uptr);
1096 if (n < 0 || n >= N_RDR_UNITS_MAX)
1097 return SCPE_ARG;
1098 sim_printf("name : %s", rdr_state [n] . device_name);
1099 return SCPE_OK;
1100 }
1101
1102 static t_stat rdr_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
1103 UNUSED const char * cptr, UNUSED void * desc)
1104 {
1105 long n = RDR_UNIT_NUM (uptr);
1106 if (n < 0 || n >= N_RDR_UNITS_MAX)
1107 return SCPE_ARG;
1108 if (cptr)
1109 {
1110 strncpy (rdr_state [n] . device_name, cptr, MAX_DEV_NAME_LEN - 1);
1111 rdr_state [n] . device_name [MAX_DEV_NAME_LEN - 1] = 0;
1112 }
1113 else
1114 rdr_state [n] . device_name [0] = 0;
1115 return SCPE_OK;
1116 }
1117
1118 static t_stat rdr_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
1119 const UNUSED char * cptr, UNUSED void * desc)
1120 {
1121 if (! cptr)
1122 return SCPE_ARG;
1123
1124 size_t len = strlen(cptr);
1125
1126
1127
1128 if (len >= (sizeof(rdr_path_prefix) - (strlen(rdr_name) + 3)))
1129 return SCPE_ARG;
1130
1131 strncpy(rdr_path_prefix, cptr, sizeof(rdr_path_prefix) -1);
1132 rdr_path_prefix[sizeof(rdr_path_prefix) - 1] = '\0';
1133 if (len > 0)
1134 {
1135 if (rdr_path_prefix[len - 1] != '/')
1136 {
1137 if (len == sizeof(rdr_path_prefix) - 1)
1138 return SCPE_ARG;
1139 rdr_path_prefix[len++] = '/';
1140 rdr_path_prefix[len] = 0;
1141 }
1142 }
1143 return SCPE_OK;
1144 }
1145
1146 static t_stat rdr_show_path (UNUSED FILE * st, UNUSED UNIT * uptr,
1147 UNUSED int val, UNUSED const void * desc)
1148 {
1149 if (rdr_path_prefix [0])
1150 {
1151 sim_printf("\rPath to card reader directories is \"%s\".\r\n", rdr_path_prefix);
1152 }
1153 else
1154 {
1155 sim_printf("\rPath to card reader directories is unset.\r\n");
1156 }
1157 return SCPE_OK;
1158 }