1 /****^  ***********************************************************
   2         *                                                         *
   3         * Copyright, (C) Honeywell Bull Inc., 1987                *
   4         *                                                         *
   5         * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   6         *                                                         *
   7         * Copyright (c) 1972 by Massachusetts Institute of        *
   8         * Technology and Honeywell Information Systems, Inc.      *
   9         *                                                         *
  10         *********************************************************** */
  11 
  12 /* format: style4,delnl,insnl,^ifthendo */
  13 tty_interrupt:
  14      proc (a_wtcbp, a_type, a_info);
  15 
  16 /* DESCRIPTION:
  17    interrupt handler for logical terminal channels.
  18 */
  19 
  20 /* HISTORY:
  21    Written by Robert Coren, 08/01/78.
  22    Modified:
  23    01/20/79 by Bernard Greenberg:  Negotiated interrupt-time echo.
  24    03/01/79 by J. Stern:  for wakeup table processing.
  25    06/29/79 by Bernard Greenberg:  FNP (multiplexer)-negotiated echo.
  26    04/01/81 by Robert Coren:  bugs fixed and references to dialedt removed.
  27    05/01/81 by J. Bongiovanni:  for response time metering.
  28    06/01/82 by Robert Coren:  to add handling of MASKED interrupt type.
  29    11/01/82 by Robert Coren:  to save error code returned by channel_manager$write
  30    and to trust returned pointer even if code ^= 0.
  31    04/01/84 by Robert Coren:  to fix bug caused by setting mark flag in a buffer
  32    that might have been freed.
  33    07/20/84 by R. Michael Tague:  Changed the calling sequence of pxss$wakeup_int
  34    so that the IPS signal is specified by a bit mask instead of the
  35    signal name.
  36    09/20/84 by Robert Coren:  to fix echoing bug that arose if FNP appended
  37    characters after it stopped echoing, and to reset all the WTCB
  38    flags that have to be reset on hangup.
  39    12/10/84 by Robert Coren:  to ignore line_status interrupts if
  40    wtcb.line_status_disabled is "1"b, and to clear it on hangup.
  41 
  42 /****^  HISTORY COMMENTS:
  43   1) change(86-06-19,Kissel), approve(86-07-30,MCR7475), audit(86-08-04,Coren),
  44      install(86-10-09,MR12.0-1181):
  45      Changed to support the new tty event message format declared in
  46      net_event_message.incl.pl1 which replaces tty_event_message.incl.pl1.
  47   2) change(87-07-17,LJAdams), approve(87-08-07,MCR7750),
  48      audit(87-08-07,Fawcett), install(87-08-11,MR12.1-1079):
  49      wtcb.mark_set was being set to "0"b at all times.  Changed this so that it
  50      will be set to "0"b only if quits are enabled. (phx20905)
  51   3) change(88-01-15,Farley), approve(88-02-22,MCR7843),
  52      audit(88-02-22,Beattie), install(88-03-01,MR12.2-1029):
  53      Added a check to ACCEPT_INPUT for ceasing echo neg when there is no more
  54      horiz_room_left.
  55   4) change(88-06-20,Berno), approve(88-07-13,MCR7928),
  56      audit(88-06-20,Parisek), install(88-07-19,MR12.2-1061):
  57      Added code to implement the UNCP multiplexer (DSA gateway) interface.
  58      Set the wtcb.send_turn flag & check the wtcb.receive_mode_device flag.
  59                                                    END HISTORY COMMENTS */
  60 
  61 
  62 /* PARAMETERS */
  63 
  64 dcl  a_wtcbp ptr;
  65 dcl  a_type fixed bin;
  66 dcl  a_info bit (72) aligned;
  67 
  68 
  69 /* AUTOMATIC */
  70 
  71 dcl  i fixed bin;
  72 dcl  int_type fixed bin;
  73 dcl  devx fixed bin;
  74 dcl  charx fixed bin;
  75 dcl  echbufp ptr;
  76 dcl  this_char char (1) unaligned;
  77 dcl  echo_tally fixed bin (9);
  78 dcl  sync_ctr_tally fixed bin;
  79 dcl  inchain fixed bin (18);
  80 dcl  code fixed bin (35);
  81 dcl  next_offset fixed bin;
  82 dcl  last_offset fixed bin;
  83 dcl  new_headp ptr;
  84 dcl  old_tailp ptr;
  85 dcl  new_first_tally fixed bin;
  86 dcl  old_last_tally fixed bin;
  87 dcl  max_tally fixed bin;
  88 dcl  filled bit (1);
  89 dcl  source_ptr ptr;
  90 dcl  target_ptr ptr;
  91 dcl  start_time fixed bin (71);
  92 dcl  echnego_from_mux_flag bit (1);
  93 dcl  echnego_scan_start fixed bin;
  94 dcl  r0_did_echo bit (1);
  95 dcl  uncp_flag bit (1);                                     /* designate UNCP mpx */
  96 dcl  1 echo_start_data,
  97        2 ctr fixed bin (35),
  98        2 screenleft fixed bin (35);
  99 
 100 /* BASED */
 101 
 102 dcl  new_chars char (new_first_tally) based;
 103 
 104 
 105 /* BUILTINS */
 106 
 107 dcl  (addr, bin, clock, divide, hbound, max, min, null,
 108       ptr, unspec, rank, rel, size, string, substr) builtin;
 109 
 110 
 111 /* ENTRIES */
 112 
 113 dcl  meter_response_time entry (bit (36) aligned, fixed bin);
 114 dcl  pxss$ring_0_wakeup entry (bit (36) aligned, fixed bin (71), fixed bin (71), fixed bin (35));
 115 dcl  pxss$unique_ring_0_wakeup entry (bit (36) aligned, fixed bin (71), fixed bin (71), fixed bin (35));
 116 dcl  pxss$ips_wakeup_int entry (bit (36) aligned, bit (35) aligned);
 117 dcl  syserr entry options (variable);
 118 
 119 
 120 /* EXTERNAL STATIC */
 121 
 122 dcl  error_table_$noalloc fixed bin (35) ext static;
 123 dcl  error_table_$invalid_write fixed bin (35) ext static;
 124 dcl  sys_info$quit_mask bit (35) aligned ext static;
 125 
 126 /* INTERNAL STATIC */
 127 
 128 dcl  CRASH_SYSTEM fixed bin int static options (constant) init (1);
 129 
 130 dcl  line_delimiter_octal (16) bit (9) int static options (constant)
 131           init ("012"b3, (2) (1)"055"b3, "012"b3, (3) (1)"003"b3, (5) (1)"012"b3, (3) (1)"003"b3, "012"b3);
 132 dcl  line_delimiter (16) char (1) based (addr (line_delimiter_octal));
 133 
 134 dcl  no_write_code fixed bin (35) internal static;
 135 dcl  noalloc_code fixed bin (35) internal static;           /* copy of code to be used at interrupt time */
 136 ^L
 137 %include wtcb;
 138 %include mcs_interrupt_info;
 139 %include tty_buf;
 140 %include tty_buffer_block;
 141 %include net_event_message;
 142 %include tty_space_man_dcls;
 143 %include channel_manager_dcls;
 144 %include line_types;
 145 %include mcs_echo_neg_sys;
 146 %include lct;
 147 %include set_wakeup_table_info;
 148 %include response_transitions;
 149 %include multiplexer_types;
 150 ^L
 151 interrupt:
 152      entry;                                                 /* the only entry into this program */
 153 
 154           wtcbp = a_wtcbp;
 155           int_type = a_type;
 156           interrupt_info = a_info;
 157           devx = wtcb.devx;
 158           ttybp = addr (tty_buf$);
 159 
 160           uncp_flag = is_parent_mpx (UNCP_MPX);
 161 
 162           if int_type = DIALUP
 163           then do;
 164                unspec (dialup_info) = interrupt_info;
 165                if wtcb.dialing
 166                then do;                                     /* if we asked 355 to dial */
 167                     wtcb.dial_status_valid = "1"b;          /* status code is now valid */
 168                     wtcb.dial_status_code = 0;              /* success */
 169                end;
 170 
 171 
 172                wtcb.line_type = dialup_info.line_type;
 173                wtcb.baud_rate = dialup_info.baud_rate;
 174                wtcb.max_buf_size = dialup_info.max_buf_size;
 175                wtcb.buffer_pad = dialup_info.buffer_pad;
 176                wtcb.line_delimiter = line_delimiter (wtcb.line_type);
 177                wtcb.receive_mode_device = dialup_info.receive_mode_device;
 178 
 179                if uncp_flag then wtcb.send_turn = "0"b;     /* Add for the Datanet 7100. */
 180 
 181                do i = 1 to n_sync_line_types while (sync_line_type (i) ^= wtcb.line_type);
 182                end;
 183                wtcb.sync_line = (i <= n_sync_line_types);
 184 
 185                wtcb.flags.dialed = "1"b;                    /* indicate dialed */
 186                wtcb.uproc = wtcb.hproc;                     /* make boss process the user until we get real one */
 187 
 188                unspec (net_event_message) = "0"b;
 189                net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 190                net_event_message.network_type = MCS_NETWORK_TYPE;
 191                net_event_message.handle = devx;
 192                net_event_message.type = MCS_DIALUP_MSG;
 193                call pxss$ring_0_wakeup (wtcb.hproc, wtcb.hevent, net_event_message_arg, 0);
 194                                                             /* wakeup the answering service */
 195           end;
 196 
 197           else if int_type = HANGUP
 198           then do;
 199                unspec (net_event_message) = "0"b;
 200                net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 201                net_event_message.network_type = MCS_NETWORK_TYPE;
 202                net_event_message.handle = devx;
 203                net_event_message.type = MCS_HANGUP_MSG;
 204                call pxss$ring_0_wakeup (wtcb.hproc, wtcb.hevent, net_event_message_arg, (0));
 205                                                             /* notify Initializer */
 206 
 207                call kill_line;                              /* wipe out our record of the channel */
 208           end;
 209 
 210           else if int_type = CRASH                          /* we don't have to tell anyone */
 211           then call kill_line;                              /* except ourselves */
 212 
 213           else if int_type = SEND_OUTPUT
 214           then do;
 215                wtcb.send_output = "1"b;                     /* send_next_page will undo this if necessary */
 216                if wtcb.write_first ^= 0                     /* we have more output waiting */
 217                then call send_next_page;
 218                else if wtcb.negotiating_echo
 219                then do;                                     /* Do we need to get start_echo ctl order thru? */
 220 
 221                     echo_datap = ptr (ttybp, wtcb.echdp);
 222                     if echo_data.echo_start_pending_sndopt
 223                     then call start_negotiated_echo;        /* This happens when multiplexer couldn't honor previous start_negotiated_echo */
 224                                                             /* because it had output pending. */
 225                end;
 226 
 227                if wtcb.write_first = 0                      /* no write chain left */
 228                then if wtcb.wflag                           /* user is waiting to be told when output is done */
 229                     then do;
 230                          unspec (net_event_message) = "0"b;
 231                          net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 232                          net_event_message.network_type = MCS_NETWORK_TYPE;
 233                          net_event_message.handle = devx;
 234                          net_event_message.type = MCS_WRITE_MSG;
 235                          call pxss$ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, (0));
 236                          wtcb.wflag = "0"b;
 237                     end;
 238           end;
 239 
 240           else if int_type = INPUT_AVAILABLE                /* they've got input for us, but they won't say where */
 241           then do;
 242                wtcb.input_available = "1"b;
 243                if wtcb.rflag                                /* the process wants it */
 244                then do;
 245                     unspec (net_event_message) = "0"b;
 246                     net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 247                     net_event_message.network_type = MCS_NETWORK_TYPE;
 248                     net_event_message.handle = devx;
 249                     net_event_message.type = MCS_READ_MSG;
 250                     call meter_response_time (wtcb.uproc, TTY_WAKEUP);
 251                     call pxss$ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, (0));
 252                     wtcb.rflag = "0"b;
 253                end;
 254           end;
 255 
 256           else if int_type = ACCEPT_INPUT                   /* they're handing us input */
 257           then do;
 258                unspec (rtx_info) = interrupt_info;
 259                if rtx_info.formfeed_present                 /* this is end_of_page response */
 260                then do;
 261                     if ^rtx_info.output_in_ring_0 & wtcb.write_first = 0
 262                                                             /* if tty_write is up-to-date */
 263                     then wtcb.actline = 0;
 264                end;
 265 
 266                inchain = bin (rtx_info.chain_head);
 267                if inchain = 0
 268                then return;
 269 
 270                sync_ctr_tally = 0;                          /* Set for echo sync */
 271                r0_did_echo = "0"b;                          /* Set for resync hack. */
 272 
 273                last_offset = bin (rtx_info.chain_tail);     /* initialize end_of_chain pointer */
 274 ^L
 275                if wtcb.negotiating_echo
 276                then do;                                     /* In echnego state */
 277                     start_time = clock ();                  /* count time spent doing this */
 278                     tty_buf.echo_neg_interrupts = tty_buf.echo_neg_interrupts + 1;
 279                                                             /* METER */
 280                     echo_datap = ptr (ttybp, wtcb.echdp);   /* Develop table ptr */
 281                     echbufp = null ();                      /* No echo buffer yet */
 282                     echnego_from_mux_flag = "0"b;
 283                     if wtcb.write_last = 0
 284                     then old_tailp = null;                  /* Set for combining */
 285                     else do;
 286                          old_tailp = ptr (ttybp, wtcb.write_last);
 287                          old_last_tally = old_tailp -> buffer.tally;
 288                          if old_last_tally ^< max_buffer_tally (old_tailp -> buffer.size_code) - wtcb.buffer_pad
 289                          then old_tailp = null;
 290                     end;
 291 
 292 
 293                     do blockp = ptr (ttybp, rtx_info.chain_head) repeat (ptr (ttybp, buffer.next)) while (rel (blockp));
 294 
 295                          echnego_scan_start = 0;
 296 
 297                          if echo_data.mux_will_echnego      /* Mux knows how to echo negotiate */
 298                               & buffer.next = 0             /* This is end of chain */
 299                               & ^rtx_info.break_char        /* Mux echoed all these characters */
 300                                                             /* Except maybe the last few */
 301                               & buffer.tally > 0
 302                          then do;
 303 
 304 /* it's possible that the multiplexer (in particular, the FNP) appended a few more
 305    characters after it stopped echoing. This code assumes that there will be no
 306    more than 4 such, and that the multiplexer echoed exactly the characters up to
 307    but not including the first non-echoable character. */
 308 
 309                               do echnego_scan_start = max (0, buffer.tally - 4) to buffer.tally - 1
 310                                    while (echoable (buffer.chars (echnego_scan_start)));
 311                               end;
 312                               if echnego_scan_start > echo_data.horiz_room_left
 313                                                             /* stopped because it ran out of line */
 314                               then echnego_scan_start = echo_data.horiz_room_left;
 315 
 316                               echo_data.horiz_room_left = echo_data.horiz_room_left - echnego_scan_start;
 317                               echo_data.chars_echoed = echo_data.chars_echoed + echnego_scan_start;
 318                               sync_ctr_tally = sync_ctr_tally - echnego_scan_start;
 319                                                             /* Will go negative */
 320                               tty_buf.echo_neg_mux_chars = tty_buf.echo_neg_mux_chars + echnego_scan_start;
 321                                                             /* METER */
 322                               rtx_info.break_char = "1"b;
 323                               echnego_from_mux_flag = "1"b;
 324                               if echo_data.horiz_room_left ^> 0
 325                               then go to negotiated_echo_ceases;
 326                          end;
 327 
 328 /* Mux echoed _^Hn_^Ho_^Hn_^He of them; see if we can echo them. */
 329 
 330                          do charx = echnego_scan_start to buffer.tally - 1;
 331                                                             /* Scan buffer */
 332                               this_char = buffer.chars (charx);
 333                               if ^echoable (this_char)
 334                               then go to negotiated_echo_ceases;
 335 
 336 
 337 /* This character is echoable */
 338 
 339                               if echo_data.horiz_room_left ^> 0
 340                               then go to negotiated_echo_ceases;
 341                               if echnego_from_mux_flag
 342                               then do;
 343                                    echo_data.chars_echoed = echo_data.chars_echoed + 1;
 344                                    tty_buf.echo_neg_mux_chars = tty_buf.echo_neg_mux_chars + 1;
 345                                                             /* METER */
 346                                    sync_ctr_tally = sync_ctr_tally - 1;
 347                               end;
 348                               else if old_tailp ^= null
 349                               then do;                      /* Try to combine buffers */
 350                                    r0_did_echo = "1"b;
 351                                    old_tailp -> buffer.chars (old_last_tally) = this_char;
 352                                    echo_data.chars_echoed = echo_data.chars_echoed + 1;
 353                                    tty_buf.echo_neg_r0_chars = tty_buf.echo_neg_r0_chars + 1;
 354                                    old_last_tally, old_tailp -> buffer.tally = old_last_tally + 1;
 355                                    if old_last_tally ^< max_buffer_tally (old_tailp -> buffer.size_code) - wtcb.buffer_pad
 356                                    then old_tailp = null;
 357                               end;
 358                               else do;
 359 
 360                                    if echbufp = null
 361                                    then do;
 362 
 363                                         r0_did_echo = "1"b;
 364                                         lctp = tty_buf.lct_ptr;
 365                                                             /* we're going to check if the guy's got too much space already */
 366                                         lctep = addr (lct.lcte_array (devx));
 367                                         lctep = addr (lct.lcte_array (lcte.physical_channel_devx));
 368                                         if lcte.output_words >= divide (tty_buf.bleft, output_bpart, 17, 0)
 369                                                             /* he does */
 370                                         then go to negotiated_echo_ceases;
 371                                                             /* so stop for now */
 372 
 373                                         call tty_space_man$get_buffer (devx, 16, OUTPUT, echbufp);
 374                                         if echbufp = null
 375                                         then go to negotiated_echo_ceases;
 376                                                             /* No more room */
 377                                         echo_tally = 0;
 378                                    end;
 379                                    echbufp -> buffer.chars (echo_tally) = this_char;
 380                                                             /* Insert it */
 381                                    echo_tally = echo_tally + 1;
 382                                                             /* chars is 0-indexed */
 383 
 384                                    if echo_tally >= max_buffer_tally (echbufp -> buffer.size_code) - wtcb.buffer_pad
 385                                    then call ship_echo_buffer;
 386                               end;
 387                               echo_data.horiz_room_left = echo_data.horiz_room_left - 1;
 388                          end;                               /* End of input buffer */
 389                     end;                                    /* End of input chain */
 390                     rtx_info.break_char = "0"b;             /* NO break! */
 391                     go to negotiated_echo_continues;
 392 
 393 
 394 negotiated_echo_ceases:                                     /* Some break condition or lossage has been hit. */
 395                     echo_data.echo_start_pending_sndopt = "0"b;
 396                                                             /* DONT start mux up. */
 397                     wtcb.negotiating_echo = "0"b;           /* Turn off echoing */
 398 negotiated_echo_continues:
 399                     if echbufp ^= null
 400                     then call ship_echo_buffer;
 401                     tty_buf.echo_neg_time = tty_buf.echo_neg_time + clock () - start_time;
 402                end;
 403 
 404                if wtcb.echdp ^= "000000"b3
 405                then do;                                     /* May need to count synchronization */
 406                     echo_datap = ptr (ttybp, wtcb.echdp);
 407                     if echo_data.synchronized
 408                     then do;
 409                          if sync_ctr_tally < 0
 410                          then echo_data.sync_ctr = 0;       /* mux-Echoed chars reinit */
 411                          do blockp = ptr (ttybp, rtx_info.chain_head) repeat (ptr (ttybp, buffer.next))
 412                               while (rel (blockp));
 413 
 414                               sync_ctr_tally = sync_ctr_tally + buffer.tally;
 415                          end;                               /* MUX-echoed characters have been predecremented out */
 416                          echo_data.sync_ctr = echo_data.sync_ctr + sync_ctr_tally;
 417                          if r0_did_echo & wtcb.write_first = 0
 418                          then do;                           /* Keep output in order
 419                                                                with respect to r0 */
 420                               tty_buf.echo_neg_mux_nonecho = tty_buf.echo_neg_mux_nonecho + 1;
 421                               if wtcb.negotiating_echo
 422                               then call start_negotiated_echo;
 423                                                             /* Mux lost race, retry. */
 424                          end;
 425                     end;
 426                end;
 427 
 428                if uncp_flag then
 429                     if wtcb.receive_mode_device             /* Modification for the Datanet 7100 */
 430                     then wtcb.wake_tbl = "0"b;              /* If UNCP then do not optimize with qedx */
 431 
 432                if wtcb.wake_tbl & ^wtcb.allow_wakeup
 433                then call scan_iw_char;                      /* look for input wakeup char */
 434 
 435                if wtcb.mark_set
 436                then do;                                     /* indicate that input is first after mark set */
 437                     blockp = ptr (ttybp, inchain);          /* point to first buffer */
 438                     buffer.mark = "1"b;
 439                     wtcb.mark_set = "0"b;                   /* we've taken care of it now */
 440                end;
 441 
 442                if wtcb.fblock = 0
 443                then do;                                     /* no existing blocks */
 444                     wtcb.fblock = inchain;                  /* set offset to first block */
 445                     wtcb.fchar = 0;                         /* and offset to first char */
 446                end;
 447                else do;
 448                     old_tailp = ptr (ttybp, wtcb.lblock);
 449                     next_offset = bin (rtx_info.chain_head);
 450                     if ^old_tailp -> buffer.converted       /* don't combine new input with preconverted */
 451                     then do;
 452                          old_last_tally = old_tailp -> buffer.tally;
 453 
 454                          max_tally = max_buffer_tally (old_tailp -> buffer.size_code);
 455                                                             /* number of characters this buffer will hold */
 456                          filled = "0"b;
 457                          do while ((next_offset ^= 0) & ^filled);
 458                                                             /* put as much as possible of input into last old buffer */
 459                               new_headp = ptr (ttybp, next_offset);
 460                               new_first_tally = new_headp -> buffer.tally;
 461 
 462                               if (old_last_tally + new_first_tally <= max_tally) & ^new_headp -> buffer.mark
 463                                                             /* if it will fit (but don't mixed marked input with unmarked) */
 464                               then do;
 465                                    source_ptr = addr (new_headp -> buffer.chars (0));
 466                                    target_ptr = addr (old_tailp -> buffer.chars (old_last_tally));
 467                                    target_ptr -> new_chars = source_ptr -> new_chars;
 468                                    old_last_tally = old_last_tally + new_first_tally;
 469                                    next_offset = new_headp -> buffer.next;
 470                                                             /* move on to next buffer */
 471                                    call tty_space_man$free_buffer (devx, INPUT, new_headp);
 472                                                             /* through with this one */
 473                               end;
 474 
 475                               else filled = "1"b;           /* no more room in last old buffer */
 476                          end;
 477 
 478                          old_tailp -> buffer.tally = old_last_tally;
 479                     end;
 480                     old_tailp -> buffer.next = next_offset;
 481                     if next_offset = 0
 482                     then last_offset = 0;                   /* took care of entire new chain */
 483 
 484                end;
 485 
 486                if last_offset ^= 0
 487                then wtcb.lblock = last_offset;
 488 
 489                if wtcb.wake_tbl & ^wtcb.allow_wakeup
 490                then call check_iw_limit;                    /* see if too much input has accumulated */
 491 
 492                if rtx_info.break_char & ^rtx_info.output_in_ring_0
 493                                                             /* newline or form feed */
 494                then do;
 495                     if ^rtx_info.output_in_fnp              /* if there's no output going on */
 496                     then wtcb.actcol, wtcb.white_col = 0;   /* make sure next one starts at left margin */
 497 
 498                     if wtcb.flags.count_lines & ^wtcb.breakall
 499                                                             /* counting lines */
 500                     then wtcb.actline = wtcb.actline + 1;   /* count this one */
 501                end;
 502                if (rtx_info.break_char | wtcb.wru)          /* if there was a break char or this is answerback */
 503                     & wtcb.rflag
 504                then do;                                     /* and the user wants a wakeup then */
 505                     if wtcb.wake_tbl & ^wtcb.allow_wakeup
 506                     then if wtcb.prompt_len > 0
 507                          then call send_prompt;
 508                          else ;
 509                     else do;
 510                          unspec (net_event_message) = "0"b;
 511                          net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 512                          net_event_message.network_type = MCS_NETWORK_TYPE;
 513                          net_event_message.handle = devx;
 514                          net_event_message.type = MCS_READ_MSG;
 515                          call meter_response_time (wtcb.uproc, TTY_WAKEUP);
 516                          call pxss$ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, 0);
 517                                                             /* wakeup the user */
 518                          wtcb.rflag = "0"b;                 /* we've taken care of this now */
 519                     end;
 520                end;
 521           end;
 522 
 523           else if int_type = INPUT_REJECTED                 /* we couldn't take more input for this guy */
 524           then do;
 525                if wtcb.fblock ^= 0                          /* if he's sitting on any */
 526                then do;
 527                     unspec (net_event_message) = "0"b;
 528                     net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 529                     net_event_message.network_type = MCS_NETWORK_TYPE;
 530                     net_event_message.handle = devx;
 531                     net_event_message.type = MCS_READ_MSG;  /* poke him */
 532                     if wtcb.rflag                           /* he hasn't been poked already */
 533                     then do;
 534                          call meter_response_time (wtcb.uproc, TTY_WAKEUP);
 535                          call pxss$ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, (0));
 536                          wtcb.rflag = "0"b;
 537                     end;
 538 
 539                     else call pxss$unique_ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, (0));
 540                end;
 541           end;
 542 
 543           else if int_type = QUIT
 544           then do;
 545                if wtcb.flags.hndlquit
 546                then do;
 547                     if wtcb.negotiating_echo
 548                     then do;
 549                          echo_datap = ptr (ttybp, wtcb.echdp);
 550                          echo_data.echo_start_pending_sndopt, echo_data.synchronized, wtcb.negotiating_echo = "0"b;
 551                     end;
 552                     if wtcb.fblock ^= 0                     /* free read chain also */
 553                     then do;
 554                          call tty_space_man$free_chain (devx, INPUT, ptr (ttybp, wtcb.fblock));
 555                          wtcb.fblock, wtcb.lblock = 0;
 556                     end;
 557 
 558                     if wtcb.write_first ^= 0
 559                     then do;
 560                          call tty_space_man$free_chain (devx, OUTPUT, ptr (ttybp, wtcb.write_first));
 561                          wtcb.write_first, wtcb.write_last, wtcb.write_cnt = 0;
 562                     end;
 563 
 564                     wtcb.white_col = 0;
 565                     wtcb.actcol = 0;
 566                end;
 567 
 568                unspec (net_event_message) = "0"b;
 569                net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 570                net_event_message.network_type = MCS_NETWORK_TYPE;
 571                net_event_message.handle = devx;
 572 
 573                if wtcb.wflag | wtcb.rflag                   /* if process was blocked on output or input */
 574                then do;
 575                     if wtcb.wflag
 576                     then net_event_message.type = MCS_WRITE_MSG;
 577                                                             /* set message type accordingly */
 578                     else net_event_message.type = MCS_READ_MSG;
 579                     call meter_response_time (wtcb.uproc, TTY_WAKEUP);
 580                     call pxss$ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, 0);
 581                                                             /* wakeup the user */
 582                     wtcb.wflag, wtcb.rflag = "0"b;
 583                end;
 584 
 585                if wtcb.flags.qenable
 586                then do;                                     /* if quit is enabled */
 587                     net_event_message.type = MCS_QUIT_MSG;  /* we will wake up the user so he knows what gives */
 588                     call pxss$ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, 0);
 589 
 590                     call pxss$ips_wakeup_int (wtcb.uproc, sys_info$quit_mask);
 591                                                             /* signal user process */
 592                     wtcb.flags.qflag = "1"b;                /* set "quit received" flag */
 593                     wtcb.mark_set = "0"b;
 594                end;
 595 
 596                if wtcb.count_lines
 597                then if wtcb.flags.scroll
 598                     then wtcb.actline = 0;                  /* count quit as input for scrolling purposes */
 599                     else wtcb.actline = wtcb.actline + 1;   /* else count the newline */
 600 
 601                wtcb.end_frame = "0"b;
 602 
 603                tty_buf.nquits = tty_buf.nquits + 1;         /* bump quit count */
 604 
 605           end;
 606 
 607           else if int_type = LINE_STATUS
 608           then do;
 609                if ^wtcb.line_status_disabled
 610                then if wtcb.uproc ^= "0"b
 611                     then do;
 612                          wtcb.line_status = interrupt_info;
 613                          wtcb.line_status_present = "1"b;
 614                          unspec (net_event_message) = "0"b;
 615                          net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 616                          net_event_message.network_type = MCS_NETWORK_TYPE;
 617                          net_event_message.handle = devx;
 618                          net_event_message.type = MCS_LINE_STATUS_MSG;
 619                          call pxss$ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, 0);
 620                     end;
 621 
 622                return;
 623 
 624           end;
 625 
 626           else if int_type = DIAL_STATUS
 627           then do;
 628                if wtcb.dialing
 629                then do;
 630                     wtcb.dial_status_valid = "1"b;          /* we have dial out status */
 631                     wtcb.dial_status_code = bin (substr (interrupt_info, 1, 8), 8);
 632                     unspec (net_event_message) = "0"b;
 633                     net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 634                     net_event_message.network_type = MCS_NETWORK_TYPE;
 635                     net_event_message.handle = devx;
 636                     net_event_message.type = MCS_DIALOUT_MSG;
 637                     call pxss$ring_0_wakeup (wtcb.hproc, wtcb.hevent, net_event_message_arg, 0);
 638                                                             /* wakeup the user */
 639                                                             /* user will use dial_status ordercall */
 640                end;
 641           end;
 642 
 643           else if int_type = WRU_TIMEOUT                    /* no response to answerback */
 644           then do;
 645                if wtcb.flags.dialed
 646                then do;                                     /* it had better be dialed */
 647                     wtcb.rflag = "0"b;                      /* read no longer pending */
 648                     unspec (net_event_message) = "0"b;
 649                     net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 650                     net_event_message.network_type = MCS_NETWORK_TYPE;
 651                     net_event_message.handle = devx;
 652                     net_event_message.type = MCS_READ_MSG;
 653                     call pxss$ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, 0);
 654                                                             /* wakeup the user */
 655                end;
 656           end;
 657 
 658           else if int_type = SPACE_AVAILABLE                /* we were waiting for space */
 659           then if wtcb.write_first ^= 0                     /* we've got more output */
 660                then call send_next_page;
 661                else do;
 662                     unspec (net_event_message) = "0"b;
 663                     net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 664                     net_event_message.network_type = MCS_NETWORK_TYPE;
 665                     net_event_message.handle = devx;
 666                     net_event_message.type = MCS_UNSPECIFIED_MSG;
 667                     call pxss$unique_ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, (0));
 668                end;                                         /* unique because we don't want to pile these up */
 669 
 670           else if int_type = ACKNOWLEDGE_ECHNEGO_INIT
 671           then do;
 672                echo_datap = ptr (ttybp, wtcb.echdp);
 673                if echo_datap ^= ttybp
 674                then do;
 675                     echo_data.awaiting_start_sync = "0"b;
 676                     echo_data.synchronized = "1"b;
 677                     echo_data.sync_ctr = 0;
 678                end;
 679           end;
 680           else if int_type = ACKNOWLEDGE_ECHNEGO_STOP
 681           then do;
 682                echo_datap = ptr (ttybp, wtcb.echdp);
 683                wtcb.negotiating_echo = "0"b;
 684                if echo_datap ^= ttybp
 685                then do;
 686                     echo_data.awaiting_stop_sync = "0"b;
 687                     echo_data.echo_start_pending_sndopt = "0"b;
 688                     unspec (net_event_message) = "0"b;
 689                     net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 690                     net_event_message.network_type = MCS_NETWORK_TYPE;
 691                     net_event_message.handle = devx;
 692                     net_event_message.type = MCS_UNSPECIFIED_MSG;
 693                     call pxss$unique_ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, (0));
 694                end;
 695           end;
 696 
 697           else if int_type = MASKED
 698           then do;
 699                unspec (net_event_message) = "0"b;
 700                net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 701                net_event_message.network_type = MCS_NETWORK_TYPE;
 702                net_event_message.handle = devx;
 703                net_event_message.type = MCS_MASKED_MSG;
 704                call pxss$ring_0_wakeup (wtcb.hproc, wtcb.hevent, net_event_message_arg, 0);
 705                call kill_line;
 706                wtcb.masked = "1"b;
 707           end;
 708 
 709           else
 710 bad_int:
 711                call syserr (CRASH_SYSTEM, "tty_interrupt: unrecognized interrupt type (^d) for devx ^d", int_type, devx);
 712 
 713           return;
 714 ^L
 715 /* internal procedure to send pending output */
 716 
 717 send_next_page:
 718      proc;
 719 
 720 dcl  headp ptr;
 721 dcl  next_head fixed bin;
 722 
 723           if wtcb.send_output
 724           then do;
 725                headp, blockp = ptr (ttybp, wtcb.write_first);
 726 
 727                do while (^buffer.end_of_page & buffer.next ^= 0);
 728                                                             /* find last buffer of current page */
 729                     if buffer.mark                          /* this page contains the mark */
 730                     then wtcb.mark_set = "1"b;
 731                     blockp = ptr (ttybp, buffer.next);
 732                end;
 733 
 734                if buffer.mark                               /* check last buffer too */
 735                then wtcb.mark_set = "1"b;
 736                next_head = buffer.next;
 737                buffer.next = 0;                             /* break chain here */
 738                wtcb.end_frame = buffer.end_of_page;
 739 
 740                call channel_manager$write (devx, headp, code);
 741                if code = noalloc_code
 742                then do;
 743                     call tty_space_man$needs_space (devx);
 744                     code = 0;                               /* don't treat like other error codes */
 745                end;
 746 
 747 
 748                if headp ^= null                             /* didn't take it all */
 749                then do;
 750                     if code = 0
 751                     then do;
 752                          blockp = headp;
 753                          do while (buffer.next ^= 0);
 754                               if buffer.mark                /* we didn't send the marked buffer yet */
 755                               then wtcb.mark_set = "0"b;
 756                               blockp = ptr (ttybp, buffer.next);
 757                          end;
 758 
 759                          if buffer.mark                     /* have to check last one */
 760                          then wtcb.mark_set = "0"b;
 761                          buffer.next = next_head;           /* found the end of the returned chain, reconnect it */
 762                          if next_head = 0                   /* if we weren't hanging on to one */
 763                          then wtcb.write_last = bin (rel (blockp));
 764                                                             /* this is the end */
 765                          next_head = bin (rel (headp));     /* this is now head of the chain */
 766                     end;
 767 
 768                     else do;
 769                          call tty_space_man$free_chain (devx, OUTPUT, headp);
 770                                                             /* all output to be discarded */
 771                          wtcb.mark_set = "0"b;              /* can't trust anything */
 772                          wtcb.error_code = code;            /* save this for callers */
 773                          unspec (net_event_message) = "0"b;
 774                          net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
 775                          net_event_message.network_type = MCS_NETWORK_TYPE;
 776                          net_event_message.handle = devx;
 777                          net_event_message.type = MCS_UNSPECIFIED_MSG;
 778                                                             /* poke the process to make sure it finds out eventually */
 779                          call pxss$unique_ring_0_wakeup (wtcb.uproc, wtcb.event, net_event_message_arg, (0));
 780                     end;
 781                end;
 782 
 783                wtcb.write_first = next_head;
 784                if wtcb.write_first = 0
 785                then wtcb.write_last = 0;                    /* this must be true */
 786                else if code ^= 0                            /* in this case we'll throw away all output anyway */
 787                then do;
 788                     call tty_space_man$free_chain (devx, OUTPUT, ptr (ttybp, wtcb.write_first));
 789                     wtcb.write_first, wtcb.write_last = 0;
 790                end;
 791                wtcb.send_output = "0"b;
 792           end;
 793 
 794           return;
 795      end /* send_next_page */;
 796 ^L
 797 /* internal procedure to set wtcb to "hung up" state */
 798 
 799 kill_line:
 800      proc;
 801 
 802 dcl  sync_flag bit (1);
 803 dcl  masked_flag bit (1);
 804 
 805           if wtcb.fblock ^= 0                               /* if there's a read chain, free it */
 806           then call tty_space_man$free_chain (devx, INPUT, ptr (ttybp, wtcb.fblock));
 807 
 808           if wtcb.write_first ^= 0                          /* likewise for write chain */
 809           then call tty_space_man$free_chain (devx, OUTPUT, ptr (ttybp, wtcb.write_first));
 810 
 811 /* save those flags that need to be preserved */
 812 
 813           masked_flag = wtcb.flags.masked;
 814           sync_flag = wtcb.flags.sync_line;
 815           string (wtcb.flags) = ""b;                        /* clear them all, then restore saved values */
 816           string (wtcb.more_flags) = ""b;
 817           wtcb.flags.masked = masked_flag;
 818           wtcb.flags.sync_line = sync_flag;
 819 
 820           wtcb.uproc = ""b;
 821           wtcb.white_col, wtcb.fblock, wtcb.lblock = 0;
 822           wtcb.fchar, wtcb.actline, wtcb.actcol, wtcb.nramsgs = 0;
 823           wtcb.write_first, wtcb.write_last = 0;
 824           wtcb.prompt_len = 0;
 825           wtcb.error_code = 0;
 826 
 827           if wtcb.echdp ^= ""b
 828           then do;
 829                call tty_space_man$free_space (size (echo_data), ptr (ttybp, wtcb.echdp));
 830                wtcb.echdp = ""b;
 831           end;
 832           if wtcb.waketp ^= ""b
 833           then do;
 834                call tty_space_man$free_space (size (wakeup_table), ptr (ttybp, wtcb.waketp));
 835                wtcb.waketp = ""b;
 836           end;
 837 
 838      end /* kill_line */;
 839 ^L
 840 echoable:
 841      procedure (test_char) returns (bit (1) aligned);
 842 
 843 /* function that indicates whether a given character can be echoed by anyone other than the application */
 844 
 845 dcl  test_char char (1);
 846 dcl  char_pos fixed bin (9);
 847 
 848           char_pos = rank (test_char);
 849           if char_pos > hbound (echo_data.break, 1)         /* it's not in the table at all */
 850           then return ("0"b);
 851 
 852 /* if it is, it is echoable iff its corresponding bit is off */
 853 
 854           else return (^echo_data.break (char_pos));
 855      end echoable;
 856 ^L
 857 ship_echo_buffer:
 858      proc;
 859 
 860 /* Proc called to ship out echo buffer for negotiated echo */
 861 
 862 dcl  loc_echbufp ptr;
 863 dcl  loc_lastp ptr;
 864 
 865           echbufp -> buffer.tally = echo_tally;
 866           loc_echbufp = echbufp;
 867           code = 0;
 868 
 869           if wtcb.write_first ^= 0                          /* already an output chain */
 870           then do;
 871                loc_lastp = ptr (ttybp, wtcb.write_last);
 872                wtcb.write_last,                             /* just append this stuff to it */
 873                     loc_lastp -> buffer.next = bin (rel (loc_echbufp));
 874                loc_echbufp = null;
 875           end;
 876 
 877           else if ^wtcb.send_output                         /* shouldn't send it now */
 878           then do;
 879                wtcb.write_first, wtcb.write_last = bin (rel (loc_echbufp));
 880                loc_echbufp = null;
 881           end;
 882 
 883           else do;
 884                wtcb.send_output = "0"b;
 885                call channel_manager$write (devx, loc_echbufp, code);
 886           end;
 887 
 888           if loc_echbufp = null & code = 0
 889           then do;                                          /* Won */
 890                echo_data.chars_echoed = echo_data.chars_echoed + echo_tally;
 891                tty_buf.echo_neg_r0_chars = tty_buf.echo_neg_r0_chars + echo_tally;
 892                                                             /* METER */
 893           end;
 894           else do;
 895                code = 1;                                    /* Cause echo stop */
 896                call tty_space_man$free_buffer (devx, OUTPUT, echbufp);
 897           end;
 898           echbufp = null;
 899           if code ^= 0
 900           then go to negotiated_echo_ceases;                /* Stop the rolling ball. */
 901 
 902      end ship_echo_buffer;
 903 ^L
 904 /* Subroutine to scan input chain for input wakeup chars */
 905 
 906 scan_iw_char:
 907      proc;
 908 
 909 dcl  charx fixed bin;
 910 dcl  i fixed bin;
 911 
 912           wakeup_tablep = ptr (ttybp, wtcb.waketp);
 913           do blockp = ptr (ttybp, rtx_info.chain_head) repeat (ptr (ttybp, buffer.next)) while (rel (blockp));
 914                do charx = 0 to buffer.tally - 1;
 915                     i = bin (unspec (buffer.chars (charx)));
 916                     if i <= 127
 917                     then if wakeup_table.wake_map (i)       /* found a wakeup char */
 918                          then do;
 919                               wtcb.allow_wakeup = "1"b;
 920                               return;
 921                          end;
 922                end;
 923           end;
 924 
 925      end;
 926 
 927 
 928 
 929 /* Subroutine to check if buffered input exceeds limit for wake_tbl mode */
 930 
 931 check_iw_limit:
 932      proc;
 933 
 934           lctp = tty_buf.lct_ptr;
 935           lctep = addr (lct.lcte_array (devx));
 936           lctep = addr (lct.lcte_array (lcte.physical_channel_devx));
 937           if lcte.input_words > min (128, divide (tty_buf.bleft, 4, 17, 0))
 938           then wtcb.allow_wakeup = "1"b;
 939 
 940      end;
 941 ^L
 942 /* Subroutine to write a prompt message */
 943 
 944 send_prompt:
 945      proc;
 946 
 947 dcl  bufp ptr;
 948 
 949 
 950           call tty_space_man$get_buffer (devx, 16, OUTPUT, bufp);
 951           if bufp = null
 952           then return;
 953 
 954           substr (string (bufp -> buffer.chars), 1, wtcb.prompt_len) = substr (wtcb.prompt, 1, wtcb.prompt_len);
 955           bufp -> buffer.tally = wtcb.prompt_len;
 956           if wtcb.write_first = 0                           /* thread prompt buffer onto write chain */
 957           then wtcb.write_first = bin (rel (bufp));
 958           else ptr (ttybp, wtcb.write_last) -> buffer.next = bin (rel (bufp));
 959           wtcb.write_last = bin (rel (bufp));
 960 
 961           call send_next_page;                              /* ship it out */
 962 
 963      end;
 964 ^L
 965 set_static:
 966      entry;
 967 
 968 /* entry called once per bootload to copy error codes into internal static */
 969 
 970           noalloc_code = error_table_$noalloc;
 971           no_write_code = error_table_$invalid_write;
 972           return;
 973 ^L
 974 start_negotiated_echo:
 975      proc;                                                  /* echdp had better be set. */
 976           echo_start_data.ctr = echo_data.sync_ctr;
 977           echo_start_data.screenleft = echo_data.horiz_room_left;
 978           call channel_manager$control (devx, "start_negotiated_echo", addr (echo_start_data), code);
 979           if code = 0
 980           then echo_data.echo_start_pending_sndopt = "0"b;
 981           else if code = no_write_code
 982           then echo_data.echo_start_pending_sndopt = "1"b;
 983           tty_buf.echo_neg_sndopt_restarts = tty_buf.echo_neg_sndopt_restarts + 1;
 984                                                             /* METER */
 985      end;
 986 ^L
 987 is_parent_mpx:                                              /* Check for match of channel's parent mpx type and input mpx type */
 988      proc (parent_mpx_type) returns (bit (1));
 989 
 990 dcl parent_mpx_type fixed bin;
 991 dcl temp_lctep ptr;
 992 
 993           lctp = tty_buf.lct_ptr;
 994           lctep = addr (lct.lcte_array (devx));
 995           if lcte.major_channel_devx ^= 0 then do;
 996                temp_lctep = addr (lct.lcte_array (lcte.major_channel_devx));
 997                if temp_lctep->lcte.channel_type = parent_mpx_type then return ("1"b);
 998           end;
 999           else if lcte.channel_type = parent_mpx_type then return ("1"b);
1000           return ("0"b);
1001      end is_parent_mpx;
1002 
1003 ^L
1004 /* BEGIN MESSAGE DOCUMENTATION
1005 
1006 
1007    Message:
1008    tty_interrupt: unrecognized interrupt type (N) for devx D
1009 
1010    S:     $crash
1011 
1012    T:     $run
1013 
1014    M:     An unrecognized interrupt type has been reported for the nonmultiplexed
1015    channel whose device index is D.
1016 
1017    A:     $inform
1018 
1019 
1020    END MESSAGE DOCUMENTATION */
1021 
1022      end /* tty_interrupt */;