1
2
3
4
5
6
7
8
9
10
11
12
13
14 polled_vip_mpx:
15 proc;
16
17
18
19
20
21
22
23
24
25
26
27
28
29 dcl pm_chain_ptr ptr;
30 dcl pm_code fixed bin (35);
31 dcl pm_infop ptr;
32 dcl pm_int_data bit (72) aligned;
33 dcl pm_int_type fixed bin;
34 dcl pm_mclp ptr;
35 dcl pm_modes char (*);
36 dcl pm_more_input bit (1) aligned;
37 dcl pm_order char (*);
38 dcl pm_pvmdp ptr;
39 dcl pm_subchan fixed bin;
40
41
42
43
44 dcl adr bit (9);
45 dcl bmp ptr;
46 dcl chain_ptr ptr;
47 dcl code fixed bin (35);
48 dcl end_chain bit (1);
49 dcl eop_sw bit (1);
50 dcl ff_sent bit (1);
51 dcl found_text bit (1);
52 dcl 1 frame_header aligned like frame_header_template;
53 dcl 1 frame_trailer aligned like frame_trailer_template;
54 dcl headp ptr;
55 dcl i fixed bin;
56 dcl infop ptr;
57 dcl input_framep ptr;
58 dcl int_data bit (72) aligned;
59 dcl int_type fixed bin;
60
61 dcl 1 lc_info aligned,
62 2 type fixed bin (17) unal,
63 2 arg1 fixed bin (17) unal,
64 2 station_mask (0:35) bit (1) unal;
65
66 dcl leftover_chain_ptr ptr;
67
68 dcl 1 ls_info aligned,
69 2 type fixed bin (17) unal,
70 2 adr fixed bin (9) unsigned unal,
71 2 sta char (1) unal,
72 2 unused bit (36);
73
74 dcl meter_ptr ptr;
75 dcl nchars fixed bin;
76 dcl nmsg fixed bin;
77 dcl order char (32);
78 dcl output_restarted bit (1);
79 dcl prev_blockp ptr;
80 dcl saved_write_chan fixed bin;
81 dcl subchan fixed bin;
82 dcl tailp ptr;
83 dcl text_lrc bit (9);
84 dcl ttybp ptr;
85 dcl xflag bit (1);
86
87
88
89
90 dcl 1 abort_info aligned based (infop),
91 2 resetwrite bit (1) unal,
92 2 resetread bit (1) unal;
93
94 dcl 1 break_msg based (bmp),
95 2 soh char (1),
96 2 adr char (1),
97 2 sta char (1),
98 2 fc1 char (1),
99 2 fc2 char (1),
100 2 stx char (1),
101 2 text char (6);
102
103 dcl 1 input_frame aligned based (input_framep),
104 2 msg (nmsg) unal,
105 3 soh char (1),
106 3 adr char (1),
107 3 sta char (1),
108 3 fc1 char (1),
109 3 fc2 char (1),
110 3 stx char (1),
111 3 etx char (1),
112 3 lrc char (1),
113 2 eot char (1) unal;
114
115 dcl 1 write_status_info aligned based (infop),
116 2 ev_chan fixed bin (71),
117 2 output_pending bit (1);
118
119
120
121
122 dcl et_action_not_performed fixed bin (35) int static;
123 dcl et_bad_mode fixed bin (35) int static;
124 dcl et_invalid_state fixed bin (35) int static;
125 dcl et_noalloc fixed bin (35) int static;
126 dcl et_undefined_order_request fixed bin (35) int static;
127 dcl et_unimplemented_version fixed bin (35) int static;
128
129
130
131 dcl error_table_$action_not_performed fixed bin (35) ext static;
132 dcl error_table_$bad_mode fixed bin (35) ext static;
133 dcl error_table_$invalid_state fixed bin (35) ext static;
134 dcl error_table_$noalloc fixed bin (35) ext static;
135 dcl error_table_$undefined_order_request fixed bin (35) ext static;
136 dcl error_table_$unimplemented_version fixed bin (35) ext static;
137 dcl tty_buf$ ext static;
138
139
140
141
142 dcl (addr, bin, bit, bool, divide, hbound, lbound, length, max, min, mod, null, ptr, rel, string, substr, translate,
143 unspec, verify) builtin;
144
145
146
147
148 dcl pxss$ring_0_wakeup entry (bit (36) aligned, fixed bin (71), fixed bin (71), fixed bin (35));
149 dcl syserr entry options(variable);
150 dcl wire_proc$wire_me entry;
151
152
153
154
155 dcl (
156 ACK char (1) init ("^F"),
157 ADR_MASK bit (9) init ("740"b3),
158 AWAIT_FIRST_RESPONSE fixed bin init (6),
159 COMMON_LRC bit (9) init ("001"b3),
160 DISPLAY bit (9) init ("140"b3),
161 ETB char (1) init ("^W"),
162 ETX char (1) init ("^C"),
163 ETX_XOR_ETB bit (9) init ("024"b3),
164 FF char (1) init ("^L"),
165 NAK char (1) init ("^U"),
166 NL char (1) init ("
167 "),
168 NUL char (1) init ("^@"),
169 POLL bit (9) init ("040"b3),
170 PRINTER bit (9) init ("150"b3),
171 PRT char (1) init ("^Z"),
172 RESTART_CHARS char (4) init ("@^M
173 ^L"),
174 SELECT bit (9) init ("100"b3),
175 SOH char (1) init ("^A"),
176 STATION_POLL fixed bin init (1),
177 WRITE_ABORT bit (2) init ("10"b),
178 XOR bit (4) init ("0110"b)
179 ) internal static options (constant);
180
181 dcl 1 frame_header_template aligned int static options (constant),
182 2 select_msg unal,
183 3 syn (4) char (1) init ((4) (1)"^V"),
184 3 soh char (1) init ("^A"),
185 3 adr char (1),
186 3 sta char (1) init ("^@"),
187 3 fc1 char (1) init (" "),
188 3 fc2 char (1) init (" "),
189 3 stx char (1) init ("^B"),
190 3 etx char (1) init ("^C"),
191 3 lrc char (1),
192 2 text_msg unal,
193 3 syn (4) char (1) init ((4) (1)"^V"),
194 3 soh char (1) init ("^A"),
195 3 adr char (1),
196 3 sta char (1) init ("^@"),
197 3 fc1 char (1) init (" "),
198 3 fc2 char (1) init (" "),
199 3 stx char (1) init ("^B"),
200 3 ff char (1) init ("^L"),
201 3 nul char (1) init ("^@");
202
203 dcl 1 frame_trailer_template aligned int static options (constant),
204 2 text_msg unal,
205 3 etx char (1) init ("^C"),
206 3 lrc char (1),
207 2 poll_msg unal,
208 3 syn (4) char (1) init ((4) (1)"^V"),
209 3 soh char (1) init ("^A"),
210 3 adr char (1),
211 3 sta char (1) init ("^@"),
212 3 fc1 char (1) init (" "),
213 3 fc2 char (1) init (" "),
214 3 stx char (1) init ("^B"),
215 3 etx char (1) init ("^C"),
216 3 lrc char (1),
217 2 end_frame unal,
218 3 syn (4) char (1) init ((4) (1)"^V"),
219 3 eof char (1) init ("^@");
220 ^L
221 %include polled_vip_mpx_data;
222 ^L
223 %include polled_vip_load_info;
224 ^L
225 %include mcs_interrupt_info;
226 ^L
227 %include lct;
228 ^L
229 %include tty_buffer_block;
230 ^L
231 %include mcs_modes_change_list;
232 ^L
233 %include channel_manager_dcls;
234 ^L
235 %include tty_space_man_dcls;
236 ^L
237 %include polled_vip_mpx_meters;
238 ^L
239 %include pvip_subchan_meters;
240 ^L
241 %include get_comm_meters_info;
242 ^L
243
244
245 control:
246 entry (pm_pvmdp, pm_subchan, pm_order, pm_infop, pm_code);
247
248 call setup_subchan;
249 order = pm_order;
250 pm_code = 0;
251
252 if order = "listen"
253 then do;
254 pvste.listen = "1"b;
255 if pvmd.mpx_started & ^pvste.dialed & pvste.slave
256
257 then call signal_dialup;
258 end;
259
260 else if order = "hangup"
261 then do;
262 pvste.listen, pvste.dialed = "0"b;
263 call free_write_chain;
264 call channel_manager$interrupt ((pvste.devx), HANGUP, ""b);
265 end;
266
267 else if order = "wru"
268 then call channel_manager$interrupt ((pvste.devx), WRU_TIMEOUT, ""b);
269
270
271 else if order = "abort"
272 then do;
273 infop = pm_infop;
274 if abort_info.resetwrite
275 then call free_write_chain;
276 end;
277
278 else if order = "write_status"
279 then do;
280 infop = pm_infop;
281 if (pvste.write_chain ^= 0) | (pvmd.write_chan = subchan)
282 then write_status_info.output_pending = "1"b;
283 else if pvste.printer & pvste.hold_output
284 then write_status_info.output_pending = "1"b;
285 else write_status_info.output_pending = "0"b;
286 end;
287
288 else if order = "copy_meters"
289 then pvste.saved_meters_ptr -> pvip_subchan_meters = pvste.meters;
290
291 else if order = "get_meters"
292 then do;
293 infop = pm_infop;
294 if infop -> get_comm_meters_info.version ^= GET_COMM_METERS_INFO_VERSION_1
295 then pm_code = et_unimplemented_version;
296 else do;
297 meter_ptr = infop -> get_comm_meters_info.parent_ptr;
298 if meter_ptr ^= null ()
299 then if meter_ptr -> pvip_subchan_meter_struc.version ^= PVIP_SUBCHAN_METERS_VERSION_1
300 then pm_code = et_unimplemented_version;
301 else do;
302 meter_ptr -> pvip_subchan_meter_struc.current_meters = pvste.meters;
303 meter_ptr -> pvip_subchan_meter_struc.saved_meters =
304 pvste.saved_meters_ptr -> pvip_subchan_meters;
305 meter_ptr -> pvip_subchan_meter_struc.printer = pvste.printer;
306 end;
307 end;
308 end;
309
310 else pm_code = et_undefined_order_request;
311
312 return;
313
314
315
316
317
318 check_modes:
319 entry (pm_pvmdp, pm_subchan, pm_mclp, pm_code);
320
321 call setup_subchan;
322
323 mclp = pm_mclp;
324 do i = 1 to mcl.n_entries;
325 mclep = addr (mcl.entries (i));
326 mcle.mpx_mode = (mcle.mode_name = "hndlquit");
327 end;
328
329 pm_code = 0;
330 return;
331
332
333
334
335
336 set_modes:
337 entry (pm_pvmdp, pm_subchan, pm_mclp, pm_code);
338
339 call setup_subchan;
340
341 pm_code = 0;
342 mclp = pm_mclp;
343 if mcl.init
344 then pvste.hndlquit = "0"b;
345
346 do i = 1 to mcl.n_entries;
347 mclep = addr (mcl.entries (i));
348 if mcle.mpx_mode
349 then if mcle.mode_name = "hndlquit"
350 then pvste.hndlquit = mcle.mode_switch;
351 else do;
352 mcle.error = "1"b;
353 pm_code = et_bad_mode;
354 end;
355 end;
356
357 return;
358
359
360
361
362
363 get_modes:
364 entry (pm_pvmdp, pm_subchan, pm_modes, pm_code);
365
366 call setup_subchan;
367 pm_modes = "";
368
369 pm_code = 0;
370 return;
371
372
373
374
375
376 read:
377 entry (pm_pvmdp, pm_subchan, pm_chain_ptr, pm_more_input, pm_code);
378
379 pm_chain_ptr = null;
380 pm_more_input = "0"b;
381 pm_code = 0;
382 return;
383
384
385
386
387 write:
388 entry (pm_pvmdp, pm_subchan, pm_chain_ptr, pm_code);
389
390 ttybp = addr (tty_buf$);
391 call setup_subchan;
392 chain_ptr = pm_chain_ptr;
393
394 if ^pvste.dialed
395 then do;
396 call tty_space_man$free_chain ((pvste.devx), OUTPUT, chain_ptr);
397 pm_chain_ptr = null;
398 pm_code = 0;
399 return;
400 end;
401 if (pvste.write_chain ^= 0) | pvste.hold_output | (pvmd.write_chan = subchan)
402
403 then do;
404 pm_code = 0;
405 return;
406 end;
407
408 nchars = 0;
409 blockp = chain_ptr;
410 prev_blockp = null;
411 end_chain = "0"b;
412 do while (^end_chain);
413 nchars = nchars + buffer.tally;
414 if nchars > pvmd.max_text_len | buffer.next = 0
415 then end_chain = "1"b;
416 else do;
417 prev_blockp = blockp;
418 blockp = ptr (ttybp, buffer.next);
419 end;
420 end;
421
422 if nchars > pvmd.max_text_len
423 then do;
424 tailp = prev_blockp;
425 tailp -> buffer.next = 0;
426 leftover_chain_ptr = blockp;
427 end;
428 else do;
429 tailp = blockp;
430 leftover_chain_ptr = null;
431 end;
432
433 eop_sw = tailp -> buffer.end_of_page;
434 tailp -> buffer.end_of_page = "0"b;
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449 call tty_space_man$get_buffer ((pvste.devx), 16, OUTPUT, headp);
450 if headp = null
451 then go to noalloc;
452 headp -> buffer.next = bin (rel (chain_ptr), 18);
453
454 call get_frame_header (nchars);
455 substr (string (headp -> buffer.chars), 1, nchars) = substr (string (frame_header), 1, nchars);
456
457 headp -> buffer.tally = nchars;
458
459 blockp = chain_ptr;
460 end_chain = "0"b;
461 do while (^end_chain);
462 call verify_text;
463 text_lrc = bool (get_buffer_lrc (), text_lrc, XOR);
464 if buffer.next = 0
465 then end_chain = "1"b;
466 else blockp = ptr (ttybp, buffer.next);
467 end;
468
469 nchars = (bin (tailp -> buffer.size_code, 3) + 1) * 16;
470
471 nchars = (nchars - 1) * 4;
472 i = bin (tailp -> buffer.tally, 9);
473 nchars = nchars - i;
474 nchars = min (nchars, length (string (frame_trailer)));
475
476 call get_frame_trailer;
477 if pvmd.etb_mode & ^pvste.printer & ^(eop_sw | tailp -> buffer.break)
478 then do;
479 frame_trailer.text_msg.etx = ETB;
480 unspec (frame_trailer.text_msg.lrc) = bool (unspec (frame_trailer.text_msg.lrc), ETX_XOR_ETB, XOR);
481 end;
482
483 if nchars > 0
484 then substr (string (tailp -> buffer.chars), i + 1, nchars) = substr (string (frame_trailer), 1, nchars);
485 tailp -> buffer.tally = i + nchars;
486
487 nchars = length (string (frame_trailer)) - nchars;
488 if nchars > 0
489 then do;
490 call tty_space_man$get_buffer ((pvste.devx), 16, OUTPUT, blockp);
491 if blockp = null
492 then do;
493 tailp -> buffer.tally = i;
494 go to noalloc;
495 end;
496
497 tailp -> buffer.next = bin (rel (blockp), 18);
498
499 tailp = blockp;
500 tailp -> buffer.next = 0;
501
502 i = length (string (frame_trailer)) - nchars + 1;
503
504 substr (string (tailp -> buffer.chars), 1, nchars) = substr (string (frame_trailer), i, nchars);
505 tailp -> buffer.tally = nchars;
506 end;
507
508 pvste.eop = "0"b;
509 headp -> buffer.end_of_page = eop_sw;
510 pvste.write_chain = bin (rel (headp), 18);
511 if pvmd.write_chan = 0
512 then call write_frame (code);
513
514 pm_chain_ptr = leftover_chain_ptr;
515 pm_code = 0;
516 return;
517
518 noalloc:
519 if headp ^= null
520 then call tty_space_man$free_buffer ((pvste.devx), OUTPUT, headp);
521 if leftover_chain_ptr = null
522 then tailp -> buffer.next = 0;
523 else tailp -> buffer.next = bin (rel (leftover_chain_ptr), 18);
524 tailp -> buffer.end_of_page = eop_sw;
525 pm_code = et_noalloc;
526 return;
527
528
529
530
531
532 interrupt:
533 entry (pm_pvmdp, pm_int_type, pm_int_data);
534
535 ttybp = addr (tty_buf$);
536 pvmdp = pm_pvmdp;
537 int_type = pm_int_type;
538 int_data = pm_int_data;
539
540 if int_type < lbound (INTERRUPT, 1) | int_type > hbound (INTERRUPT, 1)
541 then return;
542 go to INTERRUPT (int_type);
543
544
545 INTERRUPT (1):
546 pvmd.dialup_info = int_data;
547 pvmd.mpx_loading = "0"b;
548 pvmd.mpx_loaded = "1"b;
549 call pxss$ring_0_wakeup (pvmd.load_proc_id, pvmd.load_ev_chan, PV_MPX_UP, code);
550 return;
551
552
553 INTERRUPT (2):
554 call crash_mpx;
555 call pxss$ring_0_wakeup (pvmd.load_proc_id, pvmd.load_ev_chan, PV_MPX_DOWN, code);
556 return;
557
558
559 INTERRUPT (3):
560 call crash_mpx;
561 return;
562
563
564 INTERRUPT (4):
565 if ^pvmd.mpx_loaded
566 then return;
567
568 pvmd.send_output = "1"b;
569 if pvmd.writep ^= null
570 then do;
571 call write_bchain (code);
572 if code = 0
573 then return;
574 end;
575
576 saved_write_chan = pvmd.write_chan;
577 pvmd.write_chan = 0;
578 call send_next_frame (saved_write_chan);
579
580 if saved_write_chan ^= 0
581 then do;
582 pvstep = addr (pvmd.subchan_table (saved_write_chan));
583 if pvste.pgofs > 0
584 then do;
585 pvste.writes = pvste.writes + 1;
586 if pvste.writes > pvste.pgofs
587 then pvste.pgofs, pvste.writes = 0;
588 end;
589
590 if pvste.dialed & ^pvste.hold_output
591 then call channel_manager$interrupt ((pvste.devx), SEND_OUTPUT, ""b);
592 end;
593
594 return;
595
596
597 INTERRUPT (5):
598 return;
599
600
601 INTERRUPT (6):
602 if ^pvmd.mpx_loaded
603 then return;
604
605 unspec (rtx_info) = int_data;
606 headp = ptr (ttybp, rtx_info.chain_head);
607 input_framep = addr (headp -> buffer.chars);
608
609
610
611
612
613
614
615
616 i = 2;
617 adr = unspec (input_frame.msg (1).adr);
618 if (adr & ADR_MASK) ^= POLL
619 then do;
620 adr = ""b;
621 i = 1;
622 end;
623
624 found_text = "0"b;
625 do i = i to 4 while (^found_text);
626 if input_frame.msg (i).soh ^= SOH
627 then go to discard_input;
628 if input_frame.msg (i).sta = NUL
629 then do;
630 found_text = "1"b;
631 if adr = ""b
632 then adr = unspec (input_frame.msg (i).adr);
633 nmsg = i;
634 end;
635 end;
636 if ^found_text
637 then do;
638 discard_input:
639 call tty_space_man$free_chain (pvmd.devx, INPUT, headp);
640 return;
641 end;
642
643 i = bin (substr (adr, 5, 5), 5);
644 subchan = pvmd.station_to_subchan (i).display;
645 if subchan = 0
646 then go to discard_input;
647 pvstep = addr (pvmd.subchan_table (subchan));
648 if ^pvste.dialed
649 then do;
650 if pvmd.mpx_started & pvste.listen & ^pvste.slave
651 then call signal_dialup;
652 go to discard_input;
653 end;
654
655 ff_sent = "0"b;
656 output_restarted = "0"b;
657 xflag = (substr (pvste.name, 1, 1) = "x");
658
659
660
661 if ^xflag & (input_frame.msg (nmsg).fc1 = pvmd.quit)
662 then do;
663 quit:
664 call channel_manager$interrupt ((pvste.devx), QUIT, ""b);
665 if pvste.hndlquit
666 then do;
667 if pvste.hold_output
668 then do;
669 pvste.hold_output = "0"b;
670 pvste.eop = "1"b;
671 end;
672 call free_write_chain;
673 end;
674 go to discard_input;
675 end;
676
677 if ^xflag & pvmd.gcos_break
678 then do;
679 bmp = addr (input_frame.msg (nmsg));
680 if headp -> buffer.next = 0
681 then if bin (headp -> buffer.tally) = length (string (input_frame)) + 6
682 then if break_msg.text = "$*$BRK"
683 then go to quit;
684 end;
685
686
687
688 if pvste.hold_output
689 then do;
690 pvste.hold_output = "0"b;
691 pvste.eop = "1"b;
692 call channel_manager$interrupt ((pvste.devx), SEND_OUTPUT, ""b);
693 if pvste.eop
694 then call write_ff (ff_sent);
695 output_restarted = "1"b;
696 end;
697
698
699
700 if ^xflag & (input_frame.msg (nmsg).fc1 = pvmd.formfeed)
701 then do;
702 if output_restarted
703 then go to discard_input;
704 call write_ff (ff_sent);
705 if headp -> buffer.next ^= 0
706 then call tty_space_man$free_chain (pvmd.devx, INPUT, ptr (ttybp, headp -> buffer.next));
707 blockp = headp;
708 buffer.next = 0;
709 buffer.chars (0) = FF;
710 unspec (buffer.tally) = bit (bin (1, 9), 9);
711 rtx_info.input_count = 1;
712 rtx_info.formfeed_present = "1"b;
713 rtx_info.break_char = "0"b;
714 end;
715
716
717
718
719
720
721 else do;
722 i = length (string (input_frame)) - 3;
723 nchars = bin (headp -> buffer.tally, 9) - i;
724 if nchars < 3
725 then go to discard_input;
726 if nchars = 3
727 then if output_restarted | pvmd.omit_nl | xflag
728 then go to discard_input;
729
730 substr (string (headp -> buffer.chars), 1, nchars) =
731 substr (string (headp -> buffer.chars), i + 1, nchars);
732 unspec (headp -> buffer.tally) = bit (bin (nchars, 9), 9);
733
734 if output_restarted & (headp -> buffer.next = 0)
735 then do;
736 if verify (substr (string (headp -> buffer.chars), 1, nchars - 3), RESTART_CHARS) = 0
737 then go to discard_input;
738 end;
739
740 prev_blockp = null;
741 blockp = headp;
742 end_chain = "0"b;
743 do while (^end_chain);
744 if buffer.next = 0
745 then end_chain = "1"b;
746 else do;
747 prev_blockp = blockp;
748 blockp = ptr (ttybp, buffer.next);
749 end;
750 end;
751
752 if pvmd.omit_nl | xflag
753 then i = 3;
754 else if buffer.chars (nchars - 3) = ETX
755 then i = 2;
756 else i = 3;
757 nchars = buffer.tally;
758 if nchars <= i
759 then do;
760 call tty_space_man$free_buffer ((pvste.devx), INPUT, blockp);
761 blockp = prev_blockp;
762 buffer.next = 0;
763 nchars = buffer.tally + nchars;
764 end;
765 nchars = nchars - i;
766 unspec (buffer.tally) = bit (bin (nchars, 9), 9);
767 if i = 2
768 then buffer.chars (nchars - 1) = NL;
769
770 rtx_info.break_char = "1"b;
771 rtx_info.formfeed_present = "0"b;
772 rtx_info.input_count = rtx_info.input_count + 1 - length (string (input_frame));
773
774 end;
775
776 rtx_info.output_in_fnp = "0"b;
777 if ff_sent
778 then rtx_info.output_in_ring_0 = "0"b;
779 else rtx_info.output_in_ring_0 = (pvste.write_chain ^= 0) | (pvmd.write_chan = subchan);
780 rtx_info.chain_tail = rel (blockp);
781 call channel_manager$interrupt ((pvste.devx), ACCEPT_INPUT, unspec (rtx_info));
782
783 return;
784
785
786 INTERRUPT (7):
787 return;
788
789
790 INTERRUPT (8):
791 return;
792
793
794 INTERRUPT (9):
795 if ^pvmd.mpx_loaded
796 then return;
797 unspec (ls_info) = int_data;
798 if ls_info.type < lbound (LINE_STAT, 1) | ls_info.type > hbound (LINE_STAT, 1)
799 then return;
800 go to LINE_STAT (ls_info.type);
801
802
803 LINE_STAT (1):
804 ls_info.adr = mod (ls_info.adr, 32);
805 subchan = pvmd.station_to_subchan (ls_info.adr).printer;
806
807 if subchan = 0
808 then return;
809 pvstep = addr (pvmd.subchan_table (subchan));
810 if ^pvste.dialed
811 then return;
812 if ^pvste.hold_output
813 then return;
814
815 if ls_info.sta = ACK
816 then do;
817 ack:
818 pvste.hold_output = "0"b;
819 pvste.naks = 0;
820 call free_write_chain;
821
822 end;
823
824 else if ls_info.sta = NAK
825 then do;
826 if pvste.write_chain = 0
827 then go to ack;
828 pvste.naks = pvste.naks + 1;
829 pvste.printer_naks = pvste.printer_naks + 1;
830 if pvste.naks >= 3
831 then do;
832 pvste.discarded_printer_frame = pvste.discarded_printer_frame + 1;
833 go to ack;
834 end;
835
836 pvste.hold_output = "0"b;
837 if pvmd.write_chan = 0
838 then call write_frame (code);
839 end;
840
841 else do;
842 call channel_manager$interrupt ((pvste.devx), QUIT, ""b);
843 go to ack;
844 end;
845
846 return;
847
848
849 LINE_STAT (2):
850 pvmd.input_timeouts = pvmd.input_timeouts + 1;
851
852 if pvmd.controller_poll
853 then do;
854 lc_info.type = AWAIT_FIRST_RESPONSE;
855 call channel_manager$control (pvmd.devx, "line_control", addr (lc_info), code);
856 end;
857 else do;
858 i = mod (ls_info.adr, 32);
859 if i < 0 | i > 31
860 then return;
861 if ^pvmd.cur_station_mask (i)
862 then return;
863
864 pvmd.cur_station_mask (i) = "0"b;
865 pvmd.cur_nstation = pvmd.cur_nstation - 1;
866 if pvmd.cur_nstation = 0
867 then do;
868 lc_info.type = AWAIT_FIRST_RESPONSE;
869 call channel_manager$control (pvmd.devx, "line_control", addr (lc_info), code);
870 if code ^= 0
871 then return;
872 pvmd.cur_station_mask = pvmd.station_mask;
873 pvmd.cur_nstation = pvmd.nstation;
874 end;
875
876 lc_info.type = STATION_POLL;
877 lc_info.arg1 = pvmd.cur_nstation;
878 lc_info.station_mask = pvmd.cur_station_mask;
879 call channel_manager$control (pvmd.devx, "line_control", addr (lc_info), code);
880 end;
881
882 return;
883
884
885 LINE_STAT (3):
886 pvmd.input_frames_lost = pvmd.input_frames_lost + 1;
887 return;
888
889
890 LINE_STAT (4):
891 pvmd.output_frames_lost = pvmd.output_frames_lost + 1;
892 return;
893
894
895 LINE_STAT (5):
896 pvmd.bad_output_frames = pvmd.bad_output_frames + 1;
897 return;
898
899
900 LINE_STAT (6):
901 pvmd.output_timeouts = pvmd.output_timeouts + 1;
902 return;
903
904
905 LINE_STAT (7):
906 ls_info.adr = mod (ls_info.adr, 32);
907 subchan = pvmd.station_to_subchan (ls_info.adr).display;
908 if subchan = 0
909 then return;
910 pvstep = addr (pvmd.subchan_table (subchan));
911 if ^pvste.dialed
912 then return;
913
914 pvste.pgofs = pvste.pgofs + 1;
915 pvste.display_pgofs = pvste.display_pgofs + 1;
916 if pvste.pgofs >= 3
917 then do;
918 pvste.pgofs, pvste.writes = 0;
919 pvste.pgof_limit_reached = pvste.pgof_limit_reached + 1;
920 call channel_manager$interrupt ((pvste.devx), QUIT, ""b);
921 pvste.hold_output = "0"b;
922 pvste.eop = "1"b;
923 call free_write_chain;
924 end;
925 return;
926
927
928 LINE_STAT(8):
929 call syserr(0, "Too many errors while trying to build a message, channel ^a will be hung up.", pvmd.name);
930 return;
931
932
933 INTERRUPT (10):
934 return;
935
936
937 INTERRUPT (11):
938 return;
939
940
941 INTERRUPT (12):
942 if ^pvmd.mpx_loaded
943 then return;
944
945
946
947
948
949 if ^pvmd.send_output
950 then return;
951
952 if pvmd.writep ^= null
953 then do;
954 call write_bchain (code);
955 if code = 0
956 then return;
957 end;
958
959 call send_next_frame (min (pvmd.write_chan - 1, 0));
960
961 return;
962
963 INTERRUPT (13):
964 INTERRUPT (14):
965 INTERRUPT (15):
966 INTERRUPT (16):
967 return;
968
969 INTERRUPT (17):
970 call crash_mpx;
971 call pxss$ring_0_wakeup (pvmd.load_proc_id, pvmd.load_ev_chan, PV_MPX_MASKED, code);
972 return;
973
974 ^L
975
976
977 dialup:
978 entry (pm_pvmdp, pm_subchan);
979
980 pvmdp = pm_pvmdp;
981 subchan = pm_subchan;
982 pvstep = addr (pvmd.subchan_table (subchan));
983
984 call signal_dialup;
985 return;
986
987
988
989
990 crash:
991 entry (pm_pvmdp);
992
993 ttybp = addr (tty_buf$);
994 pvmdp = pm_pvmdp;
995
996 call crash_mpx;
997 return;
998
999
1000
1001
1002 system_init:
1003 entry;
1004
1005
1006
1007 et_undefined_order_request = error_table_$undefined_order_request;
1008 et_noalloc = error_table_$noalloc;
1009 et_action_not_performed = error_table_$action_not_performed;
1010 et_bad_mode = error_table_$bad_mode;
1011 et_invalid_state = error_table_$invalid_state;
1012 et_unimplemented_version = error_table_$unimplemented_version;
1013
1014 call wire_proc$wire_me;
1015
1016 return;
1017
1018
1019 ERROR_EXIT:
1020 return;
1021 ^L
1022
1023
1024 setup_subchan:
1025 proc;
1026
1027 pvmdp = pm_pvmdp;
1028 if ^pvmd.mpx_loaded
1029 then do;
1030 pm_code = et_action_not_performed;
1031 go to ERROR_EXIT;
1032 end;
1033
1034 subchan = pm_subchan;
1035 pvstep = addr (pvmd.subchan_table (subchan));
1036 if ^pvmd.cur_station_mask (pvste.station_addr)
1037 then do;
1038 pm_code = et_invalid_state;
1039 go to ERROR_EXIT;
1040 end;
1041
1042 end;
1043
1044
1045
1046
1047
1048
1049
1050 signal_dialup:
1051 proc;
1052
1053 pvste.pgofs, pvste.writes = 0;
1054 pvste.hold_output, pvste.hndlquit = "0"b;
1055 if pvste.printer
1056 then pvste.eop = "0"b;
1057 else pvste.eop = "1"b;
1058 pvste.dialed = "1"b;
1059
1060 unspec (dialup_info) = pvmd.dialup_info;
1061 dialup_info.buffer_pad = dialup_info.buffer_pad + length (string (frame_trailer));
1062 dialup_info.max_buf_size =
1063 min (dialup_info.max_buf_size,
1064 max (16, divide (pvmd.max_text_len + dialup_info.buffer_pad + 4, 64, 17, 0) * 16));
1065 if pvste.printer
1066 then dialup_info.baud_rate = pvste.baud_rate;
1067 call channel_manager$interrupt ((pvste.devx), DIALUP, unspec (dialup_info));
1068
1069 call channel_manager$interrupt ((pvste.devx), SEND_OUTPUT, ""b);
1070
1071
1072 end;
1073 ^L
1074
1075
1076 verify_text:
1077 proc;
1078
1079 dcl btally fixed bin;
1080 dcl bchars char (btally) based (addr (buffer.chars));
1081
1082 btally = buffer.tally;
1083 bchars = translate (bchars, "^@^@^@^@^@^@", "^A^B^C^D^V^W");
1084
1085 end;
1086
1087
1088
1089
1090
1091 send_next_frame:
1092 proc (pm_last_write_chan);
1093
1094 dcl pm_last_write_chan fixed bin;
1095
1096 dcl last_write_chan fixed bin;
1097 dcl found_chan bit (1);
1098 dcl code fixed bin (35);
1099
1100 last_write_chan = pm_last_write_chan;
1101
1102 retry:
1103 found_chan = "0"b;
1104 do i = last_write_chan + 1 to pvmd.nchan while (^found_chan), 1 to last_write_chan while (^found_chan);
1105 subchan = i;
1106 pvstep = addr (pvmd.subchan_table (subchan));
1107 if pvste.write_chain ^= 0 & ^pvste.hold_output
1108 then found_chan = "1"b;
1109 end;
1110 if ^found_chan
1111 then return;
1112
1113 call write_frame (code);
1114 if code ^= 0
1115 then do;
1116 last_write_chan = subchan;
1117 go to retry;
1118 end;
1119
1120 end;
1121 ^L
1122
1123
1124 get_buffer_lrc:
1125 proc returns (bit (9));
1126
1127 dcl lrc bit (9);
1128 dcl (nwords, nchars, btally, i) fixed bin;
1129 dcl temp bit (36) aligned;
1130 dcl p ptr;
1131
1132 dcl bwords (nwords) bit (36) aligned based;
1133 dcl bchars (nchars) bit (9) unal based;
1134 dcl temp_chars (4) bit (9) based (addr (temp));
1135
1136 btally = buffer.tally;
1137 nwords = divide (btally, 4, 17, 0);
1138 nchars = mod (btally, 4);
1139 lrc = ""b;
1140
1141 if nwords > 0
1142 then do;
1143 temp = ""b;
1144 p = addr (buffer.chars);
1145 do i = 1 to nwords;
1146 temp = bool (temp, p -> bwords (i), XOR);
1147 end;
1148
1149 do i = 1 to 4;
1150 lrc = bool (lrc, temp_chars (i), XOR);
1151 end;
1152 end;
1153
1154 if nchars > 0
1155 then do;
1156 p = addr (buffer.chars (btally - nchars));
1157 do i = 1 to nchars;
1158 lrc = bool (lrc, p -> bchars (i), XOR);
1159 end;
1160 end;
1161
1162 return (lrc);
1163 end;
1164 ^L
1165
1166
1167 write_ff:
1168 proc (ff_sent);
1169
1170 dcl ff_sent bit (1);
1171 dcl p ptr;
1172 dcl (hlen, tlen) fixed bin;
1173
1174 ff_sent = "0"b;
1175 pvste.eop = "0"b;
1176 if pvmd.omit_ff | (substr (pvste.name, 1, 1) = "x")
1177 then return;
1178 if (pvste.write_chain ^= 0) | pvmd.write_chan = subchan
1179 then return;
1180
1181 call tty_space_man$get_buffer ((pvste.devx), 16, OUTPUT, p);
1182 if p = null
1183 then return;
1184
1185 pvste.eop = "1"b;
1186 call get_frame_header (hlen);
1187 pvste.eop = "0"b;
1188 substr (string (p -> buffer.chars), 1, hlen) = substr (string (frame_header), 1, hlen);
1189
1190 call get_frame_trailer;
1191 tlen = length (string (frame_trailer));
1192 substr (string (p -> buffer.chars), hlen + 1, tlen) = string (frame_trailer);
1193
1194 p -> buffer.tally = hlen + tlen;
1195 pvste.write_chain = bin (rel (p), 18);
1196 if pvmd.write_chan = 0
1197 then call write_frame (code);
1198
1199 ff_sent = "1"b;
1200
1201 end;
1202 ^L
1203
1204
1205 get_frame_header:
1206 proc (nchars);
1207
1208 dcl nchars fixed bin;
1209 dcl adr bit (9);
1210
1211
1212 frame_header = frame_header_template;
1213 adr = bit (pvste.station_addr, 9) | SELECT;
1214 unspec (frame_header.select_msg.adr) = adr;
1215 unspec (frame_header.select_msg.lrc) = bool (COMMON_LRC, adr, XOR);
1216
1217
1218 if pvste.printer
1219 then adr = PRINTER;
1220 else adr = DISPLAY;
1221 unspec (frame_header.text_msg.adr) = adr;
1222 text_lrc = bool (COMMON_LRC, adr, XOR);
1223
1224 if pvste.printer
1225 then do;
1226 frame_header.text_msg.sta = PRT;
1227 text_lrc = bool (text_lrc, unspec (PRT), XOR);
1228 end;
1229
1230 nchars = length (string (frame_header));
1231 if pvste.eop & ^pvmd.omit_ff & ^(substr (pvste.name, 1, 1) = "x")
1232
1233 then text_lrc = bool (text_lrc, unspec (FF), XOR);
1234 else nchars = nchars - 2;
1235
1236 end;
1237
1238
1239
1240
1241
1242 get_frame_trailer:
1243 proc;
1244
1245 dcl adr bit (9);
1246
1247
1248 frame_trailer = frame_trailer_template;
1249 unspec (frame_trailer.text_msg.lrc) = text_lrc;
1250
1251 adr = bit (pvste.station_addr, 9) | POLL;
1252 unspec (frame_trailer.poll_msg.adr) = adr;
1253 unspec (frame_trailer.poll_msg.lrc) = bool (COMMON_LRC, adr, XOR);
1254
1255
1256 end;
1257 ^L
1258
1259
1260 write_frame:
1261 proc (code);
1262
1263 dcl code fixed bin (35);
1264
1265
1266 code = 0;
1267 pvmd.write_chan = subchan;
1268
1269 if pvste.printer
1270 then do;
1271 call duplicate_write_chain ();
1272 if pvmd.writep = null
1273 then do;
1274 call tty_space_man$needs_space (pvmd.devx);
1275
1276 return;
1277 end;
1278 pvste.hold_output = "1"b;
1279 end;
1280 else do;
1281 pvmd.writep = ptr (ttybp, pvste.write_chain);
1282 pvste.write_chain = 0;
1283 pvste.hold_output = pvmd.writep -> buffer.end_of_page;
1284
1285 end;
1286
1287 pvmd.writep -> buffer.end_of_page = "0"b;
1288 call write_bchain (code);
1289
1290 end;
1291 ^L
1292
1293
1294 write_bchain:
1295 proc (code);
1296
1297 dcl code fixed bin (35);
1298
1299
1300 call channel_manager$write (pvmd.devx, pvmd.writep, code);
1301 if code ^= 0
1302 then do;
1303 if code = et_noalloc
1304 then do;
1305 code = 0;
1306 call tty_space_man$needs_space (pvmd.devx);
1307
1308 end;
1309 else do;
1310 subchan = pvmd.write_chan;
1311 pvstep = addr (pvmd.subchan_table (subchan));
1312 pvste.hold_output = "0"b;
1313 call free_bchain;
1314 call free_write_chain;
1315 end;
1316
1317 return;
1318 end;
1319
1320 pvmd.send_output = "0"b;
1321 end;
1322
1323
1324
1325
1326
1327 free_bchain:
1328 proc;
1329
1330 call channel_manager$control (pvmd.devx, "abort", addr (WRITE_ABORT), 0);
1331 call tty_space_man$free_chain (pvmd.devx, OUTPUT, pvmd.writep);
1332 pvmd.writep = null;
1333 pvmd.write_chan = 0;
1334
1335 end;
1336 ^L
1337
1338
1339 duplicate_write_chain:
1340 proc;
1341
1342 dcl (p, newp, prev_newp, new_headp) ptr;
1343 dcl end_chain bit (1);
1344 dcl nwords fixed bin;
1345 dcl bwords (nwords) fixed bin based;
1346
1347
1348 p = ptr (ttybp, pvste.write_chain);
1349 prev_newp = null;
1350 end_chain = "0"b;
1351 do while (^end_chain);
1352 nwords = (bin (p -> buffer.size_code, 3) + 1) * 16;
1353
1354 call tty_space_man$get_buffer ((pvste.devx), nwords, OUTPUT, newp);
1355 if newp = null
1356 then do;
1357 if prev_newp ^= null
1358 then do;
1359 prev_newp -> buffer.next = 0;
1360 call tty_space_man$free_chain ((pvste.devx), OUTPUT, prev_newp);
1361 end;
1362 return;
1363 end;
1364
1365 newp -> bwords = p -> bwords;
1366 if prev_newp = null
1367 then new_headp = newp;
1368 else prev_newp -> buffer.next = bin (rel (newp), 18);
1369 prev_newp = newp;
1370
1371 if p -> buffer.next = 0
1372 then end_chain = "1"b;
1373 else p = ptr (ttybp, p -> buffer.next);
1374 end;
1375
1376 pvmd.writep = new_headp;
1377 return;
1378
1379 end;
1380 ^L
1381
1382
1383 free_write_chain:
1384 proc;
1385
1386 if pvste.write_chain ^= 0
1387 then do;
1388 call tty_space_man$free_chain ((pvste.devx), OUTPUT, ptr (addr (tty_buf$), pvste.write_chain));
1389 pvste.write_chain = 0;
1390 end;
1391
1392 if pvste.dialed & ^pvste.hold_output & (pvmd.write_chan ^= subchan)
1393
1394 then call channel_manager$interrupt ((pvste.devx), SEND_OUTPUT, ""b);
1395
1396 end;
1397
1398
1399
1400
1401
1402 crash_mpx:
1403 proc;
1404
1405 dcl mpx_loaded bit (1);
1406
1407 mpx_loaded = pvmd.mpx_loaded;
1408 pvmd.mpx_loading, pvmd.mpx_loaded = "0"b;
1409
1410
1411 if mpx_loaded
1412 then do;
1413 if pvmd.writep ^= null
1414 then call free_bchain;
1415 do subchan = 1 to pvmd.nchan;
1416 pvstep = addr (pvmd.subchan_table (subchan));
1417 pvste.dialed = "0"b;
1418 call free_write_chain;
1419 call channel_manager$interrupt ((pvste.devx), CRASH, ""b);
1420 end;
1421 end;
1422
1423 end;
1424
1425
1426 end;